nervosnetwork / molecule

Another serialization system: minimalist and canonicalization.
MIT License
36 stars 23 forks source link

Idea: More Conversion #63

Closed blckngm closed 9 months ago

blckngm commented 1 year ago

Many Pack/Unpack/PackVec functionalities can be integrated into molecule codegen using standard conversion traits:

WDYT?

yangby-cryptape commented 1 year ago

LGTM!

TODOs

p.s. I'm sorry to said that these features won't be implemented soon, but they are on the TODO list, we will do them asap.

eval-exec commented 1 year ago

Consider there is a foo.mol molecule schema file which content is

array Foo [byte;2];

option FooOpt       (Foo);
vector FooVec       <Foo>;
array  FooArray     [Foo; 10];
array  FooArray_MVP [Foo; 10];

Since Rust MVP has already be stable. We can make FooArray_MVP's rust code be this:

pub struct FooArray_MVP<const N: usize>([Foo; N]);

then we can implement this for FooArray_MVP :

impl<const N: usize> From<[Foo; N]> for FooArray_MVP<N> {
    fn from(value: [Foo; N]) -> Self {
        FooArray_MVP(value)
    }
}

molecule's codegen/generator/rust can implement those traits like this:

impl From<Foo> for FooOpt {
    fn from(v: Foo) -> Self {
        FooOpt::new_builder().set(Some(v)).build()
    }
}

impl FromIterator<Foo> for FooVec {
    fn from_iter<T: IntoIterator<Item = Foo>>(iter: T) -> Self {
        let mut builder = FooVec::new_builder();
        for v in iter {
            builder = builder.push(v);
        }
        builder.build()
    }
}
impl From<&[Foo]> for FooVec {
    fn from(v: &[Foo]) -> Self {
        let mut builder = FooVec::new_builder();
        for v in v {
            builder = builder.push(v.clone());
        }
        builder.build()
    }
}

pub struct FooArray_MVP<const N: usize>([Foo; N]);

impl<const N: usize> From<[Foo; N]> for FooArray_MVP<N> {
    fn from(value: [Foo; N]) -> Self {
        FooArray_MVP(value)
    }
}

impl TryFrom<&[Foo]> for FooArray {
    type Error = molecule::error::VerificationError;
    fn try_from(value: &[Foo]) -> Result<Self, Self::Error> {
        let mut builder = FooArray::new_builder();
        let mut value: &[Foo; FooArray::ITEM_COUNT] = value.try_into().map_err(|_| {
            molecule::error::VerificationError::TotalSizeNotMatch(
                "total size not match".to_string(),
                FooArray::ITEM_COUNT,
                value.len(),
            )
        })?;
        builder.set(value.clone());
        Ok(builder.build())
    }
}
blckngm commented 9 months ago

It's unclear to me how Const Generics can make fixed length array better. Maybe you should elaborate in a separate issue.

blckngm commented 9 months ago

Most are implemented in #80, except for:

blckngm commented 9 months ago

On second thought, type inference won't work for foo_slice.try_into().unwrap().into(), so it would be still nice to have TryFrom<&[Foo]> directly.

blckngm commented 9 months ago

There's a complication: Byte is not u8. We often want to work with &[u8] or [u8; n], not &[Byte] or [Byte; n].

blckngm commented 9 months ago

Also implemented conversion for [u8; n] / &[u8] / u8 iterator.