Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Rust lazy reader #77

Merged
merged 15 commits into from
Apr 3, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Support custom union id (#3)
* support custom unicode id
* Array get item return Vec<u8>
* union uses Enum
  • Loading branch information
joii2020 authored and XuJiandong committed Jan 31, 2024
commit 7ac63f2783fd7695567763f379b4a7794a8ef26e
36 changes: 33 additions & 3 deletions bindings/rust/src/lazy_reader.rs
Original file line number Diff line number Diff line change
@@ -23,7 +23,14 @@ pub enum Error {
Overflow(String),
Read(String),
Verify(String),
Unknow(String),
}
impl From<core::convert::Infallible> for Error {
fn from(value: core::convert::Infallible) -> Self {
Self::Unknow(format!("conver failed: {:?}", value))
}
}

pub trait Read {
/**
* try to read `buf.len()` bytes from data source with `offset`, then fill it in `buf`.
@@ -470,10 +477,9 @@ impl_cursor_primitive!(i8);
impl TryFrom<Cursor> for Vec<u8> {
type Error = Error;
fn try_from(cur: Cursor) -> Result<Self, Error> {
let mut buf = Vec::<u8>::new();
buf.resize(cur.size, 0);
let mut buf = vec![0u8; cur.size];

let size = cur.read_at(buf.as_mut_slice())?;
let size = cur.read_at(&mut buf[..])?;
if size != buf.len() {
return Err(Error::Read(format!(
"TryFrom<Cursor>: size({}) != buf.len()({})",
@@ -485,6 +491,24 @@ impl TryFrom<Cursor> for Vec<u8> {
}
}

impl<const N: usize> TryFrom<Cursor> for [u8; N] {
type Error = Error;
fn try_from(cur: Cursor) -> Result<Self, Error> {
let mut buf = [0u8; N];

let size = cur.read_at(&mut buf[..])?;
if size != N || size != cur.size {
return Err(Error::Read(format!(
"TryFrom<Cursor>: size({}) != buf.len()({})",
size,
buf.len()
)));
}

Ok(buf)
}
}

// it's an example about how to build a data source from memory
impl Read for Vec<u8> {
fn read(&self, buf: &mut [u8], offset: usize) -> Result<usize, Error> {
@@ -515,4 +539,10 @@ impl From<Vec<u8>> for Cursor {
Cursor::new(mem.len(), Box::new(mem))
}
}

impl<const N: usize> From<[u8; N]> for Cursor {
fn from(mem: [u8; N]) -> Self {
Cursor::new(mem.len(), Box::new(mem.to_vec()))
}
}
// end of example
50 changes: 23 additions & 27 deletions examples/ci-tests/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion examples/ci-tests/Makefile
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ C_DEPS = ${MOL_DEPS} \

CC = gcc
CXX = g++
CFLAGS = -Wall -Werror
CFLAGS = -Wall -Werror -Wno-array-bounds

clean:
@cargo clean
4 changes: 2 additions & 2 deletions examples/ci-tests/c/simple-example.c
Original file line number Diff line number Diff line change
@@ -138,7 +138,7 @@ void test_build_simple() {
mol_seg_t uniona;
{
const uint8_t expected[] = {
____, ____, ____, ____,
0x02, ____, ____, ____,
0x12,
};
MolBuilder_UnionA_init(&b);
@@ -148,7 +148,7 @@ void test_build_simple() {
}
{
const uint8_t expected[] = {
0x03, ____, ____, ____,
0x0b, ____, ____, ____,
0x03, ____, ____, ____,
0x12, 0x34, 0x56,
};
2 changes: 1 addition & 1 deletion examples/ci-tests/tests/simple.rs
Original file line number Diff line number Diff line change
@@ -100,7 +100,7 @@ fn union_default() {
test_default!(
UnionA,
s!("0x\
00000000\
02000000\
00\
")
);
9 changes: 8 additions & 1 deletion examples/lazy-reader-tests/build.rs
Original file line number Diff line number Diff line change
@@ -9,13 +9,20 @@ use std::{
fn compile_schema_rust(schema: &str) {
let mut compiler = Compiler::new();
let out_dir = path::PathBuf::from(&env::var("OUT_DIR").unwrap_or_else(|_| ".".to_string()));
let mut file_path = out_dir.clone();
compiler
.input_schema_file(schema)
.generate_code(Language::Rust)
.output_dir(out_dir)
.run()
.unwrap();

file_path.push("types.rs");
Command::new("rustfmt")
.arg(<PathBuf as AsRef<OsStr>>::as_ref(&file_path))
.spawn()
.unwrap()
.wait()
.unwrap();
println!("cargo:rerun-if-changed={}", schema);
}

147 changes: 139 additions & 8 deletions examples/lazy-reader-tests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ pub mod types_struct;
pub mod types_table;
pub mod types_vec;

use molecule::lazy_reader::Cursor;
use molecule::prelude::{Builder, Entity};
use rand::{rngs::ThreadRng, thread_rng, Rng};
use std::fmt::Debug;
@@ -144,9 +145,15 @@ impl From<molecule::lazy_reader::Error> for TypesCheckErr {
Overflow(v) => Self::Mol2Err(format!("Overflow({})", v)),
Read(v) => Self::Mol2Err(format!("Read({})", v)),
Verify(v) => Self::Mol2Err(format!("Verify({})", v)),
Unknow(v) => Self::Mol2Err(format!("Unknow({})", v)),
}
}
}
impl From<std::convert::Infallible> for TypesCheckErr {
fn from(value: std::convert::Infallible) -> Self {
Self::Mol2Err(format!("conver failed: {:?}", value))
}
}

pub enum TypesUnionA {
Byte(TypesArray<u8, 1>),
@@ -203,14 +210,138 @@ impl TypesUnionA {
// let item_id = d.item_id();

match self {
Self::Byte(v) => v.check(&d.as_byte()?),
Self::Word(v) => v.check2(&d.as_word()?.into()),
Self::StructA(v) => v.check(&d.as_struct_a()?),
Self::Bytes(v) => v.check(&d.as_bytes()?.try_into().unwrap()),
Self::Words(v) => v.check(&d.as_words()?.into()),
Self::Table0(v) => v.check(&d.as_table0()?),
Self::Table6(v) => v.check(&d.as_table6()?),
Self::Table6Opt(v) => v.check(&d.as_table6_opt()?),
Self::Byte(v) => match d {
types_api2::UnionA::Byte(v2) => v.check(v2),
_ => Err(TypesCheckErr::Data(format!("check union type is failed"))),
},
Self::Word(v) => match d {
types_api2::UnionA::Word(v2) => v.check2(v2),
_ => Err(TypesCheckErr::Data(format!("check union type is failed"))),
},
Self::StructA(v) => match d {
types_api2::UnionA::StructA(v2) => v.check(v2),
_ => Err(TypesCheckErr::Data(format!("check union type is failed"))),
},
Self::Bytes(v) => match d {
types_api2::UnionA::Bytes(v2) => {
v.check(&v2.clone().try_into()?)
}
_ => Err(TypesCheckErr::Data(format!("check union type is failed"))),
},
Self::Words(v) => match d {
types_api2::UnionA::Words(v2) => v.check(v2),
_ => Err(TypesCheckErr::Data(format!("check union type is failed"))),
},
Self::Table0(v) => match d {
types_api2::UnionA::Table0(v2) => v.check(v2),
_ => Err(TypesCheckErr::Data(format!("check union type is failed"))),
},
Self::Table6(v) => match d {
types_api2::UnionA::Table6(v2) => v.check(v2),
_ => Err(TypesCheckErr::Data(format!("check union type is failed"))),
},
Self::Table6Opt(v) => match d {
types_api2::UnionA::Table6Opt(v2) => v.check(v2),
_ => Err(TypesCheckErr::Data(format!("check union type is failed"))),
},
}
}
}

pub enum TypesUnionB {
Byte(TypesArray<u8, 1>), // 2
Word(TypesArrayWord), //4
}
impl BaseTypes for TypesUnionB {
fn new_rng(rng: &mut ThreadRng, config: &TypesConfig) -> Self {
let v = if config.min_size {
0 // Self::Byte
} else {
rng.gen_range(0..1)
};
match v {
0 => Self::Byte(TypesArray::new_rng(rng, config)),
1 => Self::Word(TypesArrayWord::new_rng(rng, config)),

_ => panic!("unknow error"),
}
}
}
impl Default for TypesUnionB {
fn default() -> Self {
Self::new_rng(&mut thread_rng(), &TypesConfig::default())
}
}
impl TypesUnionB {
pub fn to_mol(&self) -> types_api::UnionB {
let t = match self {
Self::Byte(v) => types_api::UnionBUnion::Byte(v.to_mol()),
Self::Word(v) => types_api::UnionBUnion::Word(v.to_mol2()),
};
types_api::UnionB::new_builder().set(t).build()
}

pub fn check(&self, d: &types_api2::UnionB) -> ResCheckErr {
// let item_id = d.item_id();

match self {
Self::Byte(v) => match d {
types_api2::UnionB::Byte(v2) => v.check(v2),
_ => Err(TypesCheckErr::Data(format!("check union type is failed"))),
},
Self::Word(v) => match d {
types_api2::UnionB::Word(v2) => v.check2(v2),
_ => Err(TypesCheckErr::Data(format!("check union type is failed"))),
},
}
}
}

pub enum TypesUnionD {
Word(TypesArrayWord), //2
Byte(TypesArray<u8, 1>), // 4
}
impl BaseTypes for TypesUnionD {
fn new_rng(rng: &mut ThreadRng, config: &TypesConfig) -> Self {
let v = if config.min_size {
0 // Self::Byte
} else {
rng.gen_range(0..1)
};
match v {
0 => Self::Word(TypesArrayWord::new_rng(rng, config)),
1 => Self::Byte(TypesArray::new_rng(rng, config)),

_ => panic!("unknow error"),
}
}
}
impl Default for TypesUnionD {
fn default() -> Self {
Self::new_rng(&mut thread_rng(), &TypesConfig::default())
}
}
impl TypesUnionD {
pub fn to_mol(&self) -> types_api::UnionD {
let t = match self {
Self::Word(v) => types_api::UnionDUnion::Word(v.to_mol2()),
Self::Byte(v) => types_api::UnionDUnion::Byte(v.to_mol()),
};
types_api::UnionD::new_builder().set(t).build()
}

pub fn check(&self, d: &types_api2::UnionD) -> ResCheckErr {
// let item_id = d.item_id();

match self {
Self::Word(v) => match d {
types_api2::UnionD::Word(v2) => v.check2(v2),
_ => Err(TypesCheckErr::Data(format!("check union type is failed"))),
},
Self::Byte(v) => match d {
types_api2::UnionD::Byte(v2) => v.check(v2),
_ => Err(TypesCheckErr::Data(format!("check union type is failed"))),
},
}
}
}
Loading