Skip to content

Commit

Permalink
support Tuples (unnamed members) as well as 128 bit integral types in…
Browse files Browse the repository at this point in the history
… the rust streamable macro
  • Loading branch information
arvidn committed Oct 7, 2022
1 parent 350fe2f commit 7f3f3b5
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 19 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ py-bindings = ["dep:pyo3"]
clvmr = "=0.1.23"
hex = "=0.4.3"
pyo3 = { version = "=0.15.1", features = ["extension-module"], optional = true }
chia_streamable_macro = { version = "=0.2.2", path = "chia_streamable_macro" }
chia_streamable_macro = { version = "=0.2.3", path = "chia_streamable_macro" }

[dev-dependencies]
num-traits = "=0.2.15"
Expand Down
2 changes: 1 addition & 1 deletion chia_streamable_macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "chia_streamable_macro"
version = "0.2.2"
version = "0.2.3"
edition = "2021"
license = "Apache-2.0"
description = "Streamable derive macro for serializing/deserializing types in Chia protocol format"
Expand Down
56 changes: 40 additions & 16 deletions chia_streamable_macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ extern crate proc_macro;
#[macro_use]
extern crate quote;

use syn::{parse_macro_input, DeriveInput, FieldsNamed};
use syn::{parse_macro_input, DeriveInput, FieldsNamed, FieldsUnnamed};

use proc_macro::TokenStream;

Expand All @@ -11,6 +11,7 @@ pub fn chia_streamable_macro(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);

let mut fnames = Vec::<syn::Ident>::new();
let mut findices = Vec::<syn::Index>::new();
let mut ftypes = Vec::<syn::Type>::new();
match data {
syn::Data::Enum(_) => {
Expand All @@ -20,8 +21,11 @@ pub fn chia_streamable_macro(input: TokenStream) -> TokenStream {
panic!("Streamable does not support Unions");
}
syn::Data::Struct(s) => match s.fields {
syn::Fields::Unnamed(_) => {
panic!("Streamable does not support tuples");
syn::Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
for (index, f) in unnamed.iter().enumerate() {
findices.push(syn::Index::from(index));
ftypes.push(f.ty.clone());
}
}
syn::Fields::Unit => {
panic!("Streamable does not support the unit type");
Expand All @@ -35,19 +39,39 @@ pub fn chia_streamable_macro(input: TokenStream) -> TokenStream {
},
};

let ret = quote! {
impl Streamable for #ident {
fn update_digest(&self, digest: &mut clvmr::sha2::Sha256) {
#(self.#fnames.update_digest(digest);)*
}
fn stream(&self, out: &mut Vec<u8>) -> chia_error::Result<()> {
#(self.#fnames.stream(out)?;)*
Ok(())
if !fnames.is_empty() {
let ret = quote! {
impl Streamable for #ident {
fn update_digest(&self, digest: &mut clvmr::sha2::Sha256) {
#(self.#fnames.update_digest(digest);)*
}
fn stream(&self, out: &mut Vec<u8>) -> chia_error::Result<()> {
#(self.#fnames.stream(out)?;)*
Ok(())
}
fn parse(input: &mut std::io::Cursor<&[u8]>) -> chia_error::Result<Self> {
Ok(#ident{ #( #fnames: <#ftypes as Streamable>::parse(input)?, )* })
}
}
fn parse(input: &mut std::io::Cursor<&[u8]>) -> chia_error::Result<Self> {
Ok(#ident{ #( #fnames: <#ftypes as Streamable>::parse(input)?, )* })
};
ret.into()
} else if !findices.is_empty() {
let ret = quote! {
impl Streamable for #ident {
fn update_digest(&self, digest: &mut clvmr::sha2::Sha256) {
#(self.#findices.update_digest(digest);)*
}
fn stream(&self, out: &mut Vec<u8>) -> chia_error::Result<()> {
#(self.#findices.stream(out)?;)*
Ok(())
}
fn parse(input: &mut std::io::Cursor<&[u8]>) -> chia_error::Result<Self> {
Ok(#ident( #( <#ftypes as Streamable>::parse(input)?, )* ))
}
}
}
};
ret.into()
};
ret.into()
} else {
panic!("unknown error");
}
}
62 changes: 62 additions & 0 deletions src/streamable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ streamable_primitive!(u32);
streamable_primitive!(i32);
streamable_primitive!(u64);
streamable_primitive!(i64);
streamable_primitive!(u128);
streamable_primitive!(i128);

impl<T: Streamable> Streamable for Vec<T> {
fn update_digest(&self, digest: &mut Sha256) {
Expand Down Expand Up @@ -276,6 +278,37 @@ fn test_parse_u64() {
from_bytes_fail::<u64>(&[0, 0], Error::EndOfBuffer);
}

#[test]
fn test_parse_u128() {
from_bytes::<u128>(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0);
from_bytes::<u128>(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 1);
from_bytes::<u128>(
&[0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
0x80000000000000000000000000000000,
);
from_bytes::<u128>(
&[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff,
],
0xffffffffffffffffffffffffffffffff,
);

// truncated
from_bytes_fail::<u128>(
&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
Error::EndOfBuffer,
);
from_bytes_fail::<u128>(
&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
Error::EndOfBuffer,
);
from_bytes_fail::<u128>(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], Error::EndOfBuffer);
from_bytes_fail::<u128>(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], Error::EndOfBuffer);
from_bytes_fail::<u128>(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], Error::EndOfBuffer);
from_bytes_fail::<u128>(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], Error::EndOfBuffer);
}

#[test]
fn test_parse_bytes32() {
let buf: &[u8] = &[
Expand Down Expand Up @@ -472,6 +505,16 @@ fn test_parse_struct() {
);
}

#[cfg(test)]
#[derive(Streamable, PartialEq, Debug)]
struct TestTuple(String, u32);

#[test]
fn test_parse_custom_tuple() {
let buf: &[u8] = &[0, 0, 0, 3, b'b', b'a', b'z', 0, 0, 0, 42];
from_bytes::<TestTuple>(buf, TestTuple("baz".to_string(), 42));
}

#[cfg(test)]
fn stream<T: Streamable>(v: &T) -> Vec<u8> {
let mut buf = Vec::<u8>::new();
Expand Down Expand Up @@ -632,6 +675,13 @@ fn test_stream_struct() {
);
}

#[test]
fn test_stream_custom_tuple() {
let b = TestTuple("abc".to_string(), 1337);
let buf = stream(&b);
assert_eq!(&buf[..], [0, 0, 0, 3, b'a', b'b', b'c', 0, 0, 0x05, 0x39]);
}

#[test]
fn test_stream_bytes32() {
let buf: &[u8] = &[
Expand Down Expand Up @@ -679,3 +729,15 @@ fn test_stream_list_list() {
]
);
}

#[test]
fn test_stream_u128() {
let out = stream(&(1337_u128, -1337_i128));
assert_eq!(
&out,
&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x05, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xc7
]
);
}
2 changes: 1 addition & 1 deletion wheel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ chia = { path = "..", features = ["py-bindings"] }
clvmr = "=0.1.23"
pyo3 = { version = "=0.15.1", features = ["extension-module", "multiple-pymethods"] }
py_streamable = { path = "py_streamable" }
chia_streamable_macro = { version = "0.2.2", path = "../chia_streamable_macro" }
chia_streamable_macro = { version = "0.2.3", path = "../chia_streamable_macro" }
hex = "=0.4.3"

0 comments on commit 7f3f3b5

Please sign in to comment.