From 35c979c677282ccdecacc2573a2308096bed3c35 Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Tue, 1 Oct 2024 20:18:14 -0600 Subject: [PATCH 01/10] feat: attribute to override ctx for particular fields on derive(Pread) Enables using the syntax: ``` #[scroll(ctx = context_expr)] field: T ``` To use the `context_expr` expression as context when for `Pread` for `field`, regardless of the context for the rest of the struct. --- scroll_derive/src/lib.rs | 56 +++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/scroll_derive/src/lib.rs b/scroll_derive/src/lib.rs index 919517f..1b78914 100644 --- a/scroll_derive/src/lib.rs +++ b/scroll_derive/src/lib.rs @@ -2,11 +2,17 @@ extern crate proc_macro; use proc_macro2; -use quote::quote; +use quote::{quote, ToTokens}; use proc_macro::TokenStream; -fn impl_field(ident: &proc_macro2::TokenStream, ty: &syn::Type) -> proc_macro2::TokenStream { +fn impl_field( + ident: &proc_macro2::TokenStream, + ty: &syn::Type, + custom_ctx: Option<&proc_macro2::TokenStream>, +) -> proc_macro2::TokenStream { + let default_ctx = syn::Ident::new("ctx", proc_macro2::Span::call_site()).into_token_stream(); + let ctx = custom_ctx.unwrap_or(&default_ctx); match *ty { syn::Type::Array(ref array) => match array.len { syn::Expr::Lit(syn::ExprLit { @@ -15,20 +21,33 @@ fn impl_field(ident: &proc_macro2::TokenStream, ty: &syn::Type) -> proc_macro2:: }) => { let size = int.base10_parse::().unwrap(); quote! { - #ident: { let mut __tmp: #ty = [0u8.into(); #size]; src.gread_inout_with(offset, &mut __tmp, ctx)?; __tmp } + #ident: { let mut __tmp: #ty = [0u8.into(); #size]; src.gread_inout_with(offset, &mut __tmp, #ctx)?; __tmp } } } _ => panic!("Pread derive with bad array constexpr"), }, - syn::Type::Group(ref group) => impl_field(ident, &group.elem), + syn::Type::Group(ref group) => impl_field(ident, &group.elem, custom_ctx), _ => { quote! { - #ident: src.gread_with::<#ty>(offset, ctx)? + #ident: src.gread_with::<#ty>(offset, #ctx)? } } } } +/// Retrieve the field attribute with given ident e.g: +/// ```ignore +/// #[attr_ident(..)] +/// field: T, +/// ``` +fn get_attr<'a>(attr_ident: &str, field: &'a syn::Field) -> Option<&'a syn::Attribute> { + field + .attrs + .iter() + .filter(|attr| attr.path().is_ident(attr_ident)) + .next() +} + fn impl_struct( name: &syn::Ident, fields: &syn::punctuated::Punctuated, @@ -43,7 +62,30 @@ fn impl_struct( quote! {#t} }); let ty = &f.ty; - impl_field(ident, ty) + // parse the `expr` out of #[scroll(ctx = expr)] + let custom_ctx = get_attr("scroll", f).and_then(|x| { + // parsed #[scroll..] + // `expr` is `None` if the `ctx` key is not used. + let mut expr = None; + let res = x.parse_nested_meta(|meta| { + // parsed #[scroll(..)] + if meta.path.is_ident("ctx") { + // parsed #[scroll(ctx..)] + let value = meta.value()?; // parsed #[scroll(ctx = ..)] + expr = Some(value.parse::()?); // parsed #[scroll(ctx = expr)] + return Ok(()); + } + Err(meta.error(format!( + "unrecognized attribute: {}", + meta.path.get_ident().unwrap() + ))) + }); + match res { + Ok(_) => expr.map(|x| x.into_token_stream()), + Err(e) => Some(e.into_compile_error()), + } + }); + impl_field(ident, ty, custom_ctx.as_ref()) }) .collect(); @@ -104,7 +146,7 @@ fn impl_try_from_ctx(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { } } -#[proc_macro_derive(Pread)] +#[proc_macro_derive(Pread, attributes(scroll))] pub fn derive_pread(input: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(input).unwrap(); let gen = impl_try_from_ctx(&ast); From 8859cd9a5b1d07794f7645092207511299076c0f Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Tue, 1 Oct 2024 20:23:21 -0600 Subject: [PATCH 02/10] pull out custom_ctx logic to function --- scroll_derive/src/lib.rs | 53 +++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/scroll_derive/src/lib.rs b/scroll_derive/src/lib.rs index 1b78914..bb800a8 100644 --- a/scroll_derive/src/lib.rs +++ b/scroll_derive/src/lib.rs @@ -48,6 +48,36 @@ fn get_attr<'a>(attr_ident: &str, field: &'a syn::Field) -> Option<&'a syn::Attr .next() } +/// Gets the `TokenStream` for the custom ctx set in the `ctx` attribute. e.g. `expr` in the following +/// ```ignore +/// #[scroll(ctx = expr)] +/// field: T, +/// ``` +fn custom_ctx(field: &syn::Field) -> Option { + get_attr("scroll", field).and_then(|x| { + // parsed #[scroll..] + // `expr` is `None` if the `ctx` key is not used. + let mut expr = None; + let res = x.parse_nested_meta(|meta| { + // parsed #[scroll(..)] + if meta.path.is_ident("ctx") { + // parsed #[scroll(ctx..)] + let value = meta.value()?; // parsed #[scroll(ctx = ..)] + expr = Some(value.parse::()?); // parsed #[scroll(ctx = expr)] + return Ok(()); + } + Err(meta.error(format!( + "unrecognized attribute: {}", + meta.path.get_ident().unwrap() + ))) + }); + match res { + Ok(_) => expr.map(|x| x.into_token_stream()), + Err(e) => Some(e.into_compile_error()), + } + }) +} + fn impl_struct( name: &syn::Ident, fields: &syn::punctuated::Punctuated, @@ -63,28 +93,7 @@ fn impl_struct( }); let ty = &f.ty; // parse the `expr` out of #[scroll(ctx = expr)] - let custom_ctx = get_attr("scroll", f).and_then(|x| { - // parsed #[scroll..] - // `expr` is `None` if the `ctx` key is not used. - let mut expr = None; - let res = x.parse_nested_meta(|meta| { - // parsed #[scroll(..)] - if meta.path.is_ident("ctx") { - // parsed #[scroll(ctx..)] - let value = meta.value()?; // parsed #[scroll(ctx = ..)] - expr = Some(value.parse::()?); // parsed #[scroll(ctx = expr)] - return Ok(()); - } - Err(meta.error(format!( - "unrecognized attribute: {}", - meta.path.get_ident().unwrap() - ))) - }); - match res { - Ok(_) => expr.map(|x| x.into_token_stream()), - Err(e) => Some(e.into_compile_error()), - } - }); + let custom_ctx = custom_ctx(f); impl_field(ident, ty, custom_ctx.as_ref()) }) .collect(); From b8ebe4ae124ced810c479bc56e4337577e0e5bff Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Tue, 1 Oct 2024 20:47:11 -0600 Subject: [PATCH 03/10] use custom ctx for Pwrite --- scroll_derive/src/lib.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/scroll_derive/src/lib.rs b/scroll_derive/src/lib.rs index bb800a8..d40fba5 100644 --- a/scroll_derive/src/lib.rs +++ b/scroll_derive/src/lib.rs @@ -162,7 +162,13 @@ pub fn derive_pread(input: TokenStream) -> TokenStream { gen.into() } -fn impl_pwrite_field(ident: &proc_macro2::TokenStream, ty: &syn::Type) -> proc_macro2::TokenStream { +fn impl_pwrite_field( + ident: &proc_macro2::TokenStream, + ty: &syn::Type, + custom_ctx: Option<&proc_macro2::TokenStream>, +) -> proc_macro2::TokenStream { + let default_ctx = syn::Ident::new("ctx", proc_macro2::Span::call_site()).into_token_stream(); + let ctx = custom_ctx.unwrap_or(&default_ctx); match ty { syn::Type::Array(ref array) => match array.len { syn::Expr::Lit(syn::ExprLit { @@ -172,24 +178,24 @@ fn impl_pwrite_field(ident: &proc_macro2::TokenStream, ty: &syn::Type) -> proc_m let size = int.base10_parse::().unwrap(); quote! { for i in 0..#size { - dst.gwrite_with(&self.#ident[i], offset, ctx)?; + dst.gwrite_with(&self.#ident[i], offset, #ctx)?; } } } _ => panic!("Pwrite derive with bad array constexpr"), }, - syn::Type::Group(group) => impl_pwrite_field(ident, &group.elem), + syn::Type::Group(group) => impl_pwrite_field(ident, &group.elem, custom_ctx), syn::Type::Reference(reference) => match *reference.elem { syn::Type::Slice(_) => quote! { dst.gwrite_with(self.#ident, offset, ())? }, _ => quote! { - dst.gwrite_with(self.#ident, offset, ctx)? + dst.gwrite_with(self.#ident, offset, #ctx)? }, }, _ => { quote! { - dst.gwrite_with(&self.#ident, offset, ctx)? + dst.gwrite_with(&self.#ident, offset, #ctx)? } } } @@ -209,7 +215,8 @@ fn impl_try_into_ctx( quote! {#t} }); let ty = &f.ty; - impl_pwrite_field(ident, ty) + let custom_ctx = custom_ctx(f); + impl_pwrite_field(ident, ty, custom_ctx.as_ref()) }) .collect(); @@ -300,7 +307,7 @@ fn impl_pwrite(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { } } -#[proc_macro_derive(Pwrite)] +#[proc_macro_derive(Pwrite, attributes(scroll))] pub fn derive_pwrite(input: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(input).unwrap(); let gen = impl_pwrite(&ast); @@ -392,7 +399,7 @@ fn impl_size_with(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { } } -#[proc_macro_derive(SizeWith)] +#[proc_macro_derive(SizeWith, attributes(scroll))] pub fn derive_sizewith(input: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(input).unwrap(); let gen = impl_size_with(&ast); From 495125728d6c6a517c433fa1cb9383f6108dfeb6 Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Tue, 1 Oct 2024 20:55:41 -0600 Subject: [PATCH 04/10] use custom ctx for SizeWith --- scroll_derive/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scroll_derive/src/lib.rs b/scroll_derive/src/lib.rs index d40fba5..e5fc95b 100644 --- a/scroll_derive/src/lib.rs +++ b/scroll_derive/src/lib.rs @@ -323,6 +323,10 @@ fn size_with( .iter() .map(|f| { let ty = &f.ty; + let custom_ctx = custom_ctx(f).map(|x| quote! {&#x}); + let default_ctx = + syn::Ident::new("ctx", proc_macro2::Span::call_site()).into_token_stream(); + let ctx = custom_ctx.unwrap_or(default_ctx); match *ty { syn::Type::Array(ref array) => { let elem = &array.elem; @@ -333,7 +337,7 @@ fn size_with( }) => { let size = int.base10_parse::().unwrap(); quote! { - (#size * <#elem>::size_with(ctx)) + (#size * <#elem>::size_with(#ctx)) } } _ => panic!("Pread derive with bad array constexpr"), @@ -341,7 +345,7 @@ fn size_with( } _ => { quote! { - <#ty>::size_with(ctx) + <#ty>::size_with(#ctx) } } } From e17150c9d78d156286ef180e0acd9d3723ed4f48 Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Tue, 1 Oct 2024 21:44:33 -0600 Subject: [PATCH 05/10] use custom ctx for IOread and IOwrite --- scroll_derive/src/lib.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/scroll_derive/src/lib.rs b/scroll_derive/src/lib.rs index e5fc95b..6d73811 100644 --- a/scroll_derive/src/lib.rs +++ b/scroll_derive/src/lib.rs @@ -418,6 +418,10 @@ fn impl_cread_struct( let items: Vec<_> = fields.iter().enumerate().map(|(i, f)| { let ident = &f.ident.as_ref().map(|i|quote!{#i}).unwrap_or({let t = proc_macro2::Literal::usize_unsuffixed(i); quote!{#t}}); let ty = &f.ty; + let custom_ctx = custom_ctx(f); + let default_ctx = + syn::Ident::new("ctx", proc_macro2::Span::call_site()).into_token_stream(); + let ctx = custom_ctx.unwrap_or(default_ctx); match *ty { syn::Type::Array(ref array) => { let arrty = &array.elem; @@ -429,7 +433,7 @@ fn impl_cread_struct( #ident: { let mut __tmp: #ty = [0u8.into(); #size]; for i in 0..__tmp.len() { - __tmp[i] = src.cread_with(*offset, ctx); + __tmp[i] = src.cread_with(*offset, #ctx); *offset += #incr; } __tmp @@ -442,7 +446,7 @@ fn impl_cread_struct( _ => { let size = quote! { ::scroll::export::mem::size_of::<#ty>() }; quote! { - #ident: { let res = src.cread_with::<#ty>(*offset, ctx); *offset += #size; res } + #ident: { let res = src.cread_with::<#ty>(*offset, #ctx); *offset += #size; res } } } } @@ -502,7 +506,7 @@ fn impl_from_ctx(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { } } -#[proc_macro_derive(IOread)] +#[proc_macro_derive(IOread, attributes(scroll))] pub fn derive_ioread(input: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(input).unwrap(); let gen = impl_from_ctx(&ast); @@ -524,20 +528,24 @@ fn impl_into_ctx( }); let ty = &f.ty; let size = quote! { ::scroll::export::mem::size_of::<#ty>() }; + let custom_ctx = custom_ctx(f); + let default_ctx = + syn::Ident::new("ctx", proc_macro2::Span::call_site()).into_token_stream(); + let ctx = custom_ctx.unwrap_or(default_ctx); match *ty { syn::Type::Array(ref array) => { let arrty = &array.elem; quote! { let size = ::scroll::export::mem::size_of::<#arrty>(); for i in 0..self.#ident.len() { - dst.cwrite_with(self.#ident[i], *offset, ctx); + dst.cwrite_with(self.#ident[i], *offset, #ctx); *offset += size; } } } _ => { quote! { - dst.cwrite_with(self.#ident, *offset, ctx); + dst.cwrite_with(self.#ident, *offset, #ctx); *offset += #size; } } @@ -606,7 +614,7 @@ fn impl_iowrite(ast: &syn::DeriveInput) -> proc_macro2::TokenStream { } } -#[proc_macro_derive(IOwrite)] +#[proc_macro_derive(IOwrite, attributes(scroll))] pub fn derive_iowrite(input: TokenStream) -> TokenStream { let ast: syn::DeriveInput = syn::parse(input).unwrap(); let gen = impl_iowrite(&ast); From e4825b2249735a20df884000c30688deb2ba6258 Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Tue, 1 Oct 2024 21:44:39 -0600 Subject: [PATCH 06/10] add tests and example --- scroll_derive/examples/derive_custom_ctx.rs | 72 +++++++++++++++++++++ scroll_derive/tests/tests.rs | 39 ++++++++++- 2 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 scroll_derive/examples/derive_custom_ctx.rs diff --git a/scroll_derive/examples/derive_custom_ctx.rs b/scroll_derive/examples/derive_custom_ctx.rs new file mode 100644 index 0000000..3dd7d52 --- /dev/null +++ b/scroll_derive/examples/derive_custom_ctx.rs @@ -0,0 +1,72 @@ +use scroll_derive::{Pread, Pwrite, SizeWith}; + +#[derive(Debug, PartialEq)] +struct CustomCtx { + buf: Vec, +} +impl CustomCtx { + fn len() -> usize { + 3 + 2 + } +} +impl<'a> TryFromCtx<'a, usize> for CustomCtx { + type Error = scroll::Error; + + fn try_from_ctx(from: &'a [u8], ctx: usize) -> Result<(Self, usize), Self::Error> { + let offset = &mut 0; + let buf = from.gread_with::<&[u8]>(offset, ctx)?.to_owned(); + Ok((Self { buf }, *offset)) + } +} +impl<'a> TryIntoCtx for &'a CustomCtx { + type Error = scroll::Error; + fn try_into_ctx(self, dst: &mut [u8], ctx: usize) -> Result { + let offset = &mut 0; + for i in 0..(ctx.min(self.buf.len())) { + dst.gwrite(self.buf[i], offset)?; + } + Ok(*offset) + } +} +impl SizeWith for CustomCtx { + fn size_with(ctx: &usize) -> usize { + *ctx + } +} + +#[derive(Debug, PartialEq, Pread, Pwrite, SizeWith)] +#[repr(C)] +struct Data { + id: u32, + timestamp: f64, + #[scroll(ctx = BE)] + arr: [u16; 2], + #[scroll(ctx = CustomCtx::len())] + custom_ctx: CustomCtx, +} + +use scroll::{ + ctx::{SizeWith, TryFromCtx, TryIntoCtx}, + Pread, Pwrite, BE, LE, +}; + +fn main() { + let bytes = [ + 0xefu8, 0xbe, 0xad, 0xde, 0, 0, 0, 0, 0, 0, 224, 63, 0xad, 0xde, 0xef, 0xbe, 0xaa, 0xbb, + 0xcc, 0xdd, 0xee, + ]; + let data: Data = bytes.pread_with(0, LE).unwrap(); + println!("data: {data:?}"); + assert_eq!(data.id, 0xdeadbeefu32); + assert_eq!(data.arr, [0xadde, 0xefbe]); + let mut bytes2 = vec![0; ::std::mem::size_of::()]; + bytes2.pwrite_with(data, 0, LE).unwrap(); + let data: Data = bytes.pread_with(0, LE).unwrap(); + let data2: Data = bytes2.pread_with(0, LE).unwrap(); + assert_eq!(data, data2); + + /* + let data: Data = bytes.cread_with(0, LE); + assert_eq!(data, data2); + */ +} diff --git a/scroll_derive/tests/tests.rs b/scroll_derive/tests/tests.rs index 3c7f806..14dec4e 100644 --- a/scroll_derive/tests/tests.rs +++ b/scroll_derive/tests/tests.rs @@ -1,4 +1,4 @@ -use scroll::{Cread, Cwrite, Pread, Pwrite, LE}; +use scroll::{Cread, Cwrite, IOread, IOwrite, Pread, Pwrite, BE, LE}; use scroll_derive::{IOread, IOwrite, Pread, Pwrite, SizeWith}; use scroll::ctx::SizeWith; @@ -232,3 +232,40 @@ fn test_reference() { assert_eq!(bytes.pwrite_with(&data, 0, LE).unwrap(), 7); assert_eq!(bytes[..7], *b"\xff\x01\x00name"); } + +#[derive(Debug, PartialEq, Pwrite, Pread, IOwrite, IOread, SizeWith)] +struct Data11 { + pub a: u16, + #[scroll(ctx = LE)] + pub b: u16, + #[scroll(ctx = BE)] + pub c: u16, +} + +#[test] +fn test_custom_ctx_derive() { + let buf = [1, 2, 3, 4, 5, 6]; + let data = buf.pread_with(0, LE).unwrap(); + let data2 = Data11 { + a: 0x0201, + b: 0x0403, + c: 0x0506, + }; + assert_eq!(data, data2); + let mut bytes = vec![0; 32]; + assert_eq!(bytes.pwrite_with::<&Data11>(&data, 0, LE).unwrap(), 6); + assert_eq!(bytes[..Data11::size_with(&LE)], buf[..]); + let mut bytes = std::io::Cursor::new(bytes); + assert_eq!(data2, bytes.ioread_with(LE).unwrap()); + bytes.set_position(0); + bytes.iowrite_with(data, BE).unwrap(); + bytes.set_position(0); + assert_eq!(data2, bytes.ioread_with(BE).unwrap()); + bytes.set_position(0); + let data3 = Data11 { + a: 0x0102, + b: 0x0403, + c: 0x0506, + }; + assert_eq!(data3, bytes.ioread_with(LE).unwrap()); +} From f3cf2446eda670d7344618e093340e66ddea1080 Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Tue, 1 Oct 2024 22:51:58 -0600 Subject: [PATCH 07/10] remove unwrap --- scroll_derive/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scroll_derive/src/lib.rs b/scroll_derive/src/lib.rs index 6d73811..8ff5c02 100644 --- a/scroll_derive/src/lib.rs +++ b/scroll_derive/src/lib.rs @@ -66,10 +66,10 @@ fn custom_ctx(field: &syn::Field) -> Option { expr = Some(value.parse::()?); // parsed #[scroll(ctx = expr)] return Ok(()); } - Err(meta.error(format!( - "unrecognized attribute: {}", - meta.path.get_ident().unwrap() - ))) + Err(meta.error(match meta.path.get_ident() { + Some(ident) => format!("unrecognized attribute: {ident}"), + None => "unrecognized and invalid attribute".to_owned(), + })) }); match res { Ok(_) => expr.map(|x| x.into_token_stream()), From bb4aea6d739c3da55e0979b88175d2890caf5858 Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Mon, 21 Oct 2024 00:25:20 -0600 Subject: [PATCH 08/10] slightly clean `custom_ctx` impl --- scroll_derive/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scroll_derive/src/lib.rs b/scroll_derive/src/lib.rs index 8ff5c02..a5714dd 100644 --- a/scroll_derive/src/lib.rs +++ b/scroll_derive/src/lib.rs @@ -63,7 +63,7 @@ fn custom_ctx(field: &syn::Field) -> Option { if meta.path.is_ident("ctx") { // parsed #[scroll(ctx..)] let value = meta.value()?; // parsed #[scroll(ctx = ..)] - expr = Some(value.parse::()?); // parsed #[scroll(ctx = expr)] + expr = Some(value.parse::()?.into_token_stream()); // parsed #[scroll(ctx = expr)] return Ok(()); } Err(meta.error(match meta.path.get_ident() { @@ -72,7 +72,7 @@ fn custom_ctx(field: &syn::Field) -> Option { })) }); match res { - Ok(_) => expr.map(|x| x.into_token_stream()), + Ok(()) => expr, Err(e) => Some(e.into_compile_error()), } }) From 840fad32fadd0ae0ebe1d73cf3119ae4e743b38e Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Mon, 21 Oct 2024 00:42:23 -0600 Subject: [PATCH 09/10] clarify example --- scroll_derive/examples/derive_custom_ctx.rs | 43 +++++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/scroll_derive/examples/derive_custom_ctx.rs b/scroll_derive/examples/derive_custom_ctx.rs index 3dd7d52..543de00 100644 --- a/scroll_derive/examples/derive_custom_ctx.rs +++ b/scroll_derive/examples/derive_custom_ctx.rs @@ -1,15 +1,22 @@ use scroll_derive::{Pread, Pwrite, SizeWith}; +/// An example of using a method as the value for a ctx in a derive. +struct EndianDependent(Endian); +impl EndianDependent { + fn len(&self) -> usize { + match self.0 { + scroll::Endian::Little => 5, + scroll::Endian::Big => 6, + } + } +} + #[derive(Debug, PartialEq)] -struct CustomCtx { +struct VariableLengthData { buf: Vec, } -impl CustomCtx { - fn len() -> usize { - 3 + 2 - } -} -impl<'a> TryFromCtx<'a, usize> for CustomCtx { + +impl<'a> TryFromCtx<'a, usize> for VariableLengthData { type Error = scroll::Error; fn try_from_ctx(from: &'a [u8], ctx: usize) -> Result<(Self, usize), Self::Error> { @@ -18,7 +25,7 @@ impl<'a> TryFromCtx<'a, usize> for CustomCtx { Ok((Self { buf }, *offset)) } } -impl<'a> TryIntoCtx for &'a CustomCtx { +impl<'a> TryIntoCtx for &'a VariableLengthData { type Error = scroll::Error; fn try_into_ctx(self, dst: &mut [u8], ctx: usize) -> Result { let offset = &mut 0; @@ -28,7 +35,7 @@ impl<'a> TryIntoCtx for &'a CustomCtx { Ok(*offset) } } -impl SizeWith for CustomCtx { +impl SizeWith for VariableLengthData { fn size_with(ctx: &usize) -> usize { *ctx } @@ -39,15 +46,20 @@ impl SizeWith for CustomCtx { struct Data { id: u32, timestamp: f64, + // You can fix the ctx regardless of what is passed in. #[scroll(ctx = BE)] arr: [u16; 2], - #[scroll(ctx = CustomCtx::len())] - custom_ctx: CustomCtx, + // You can use arbitrary expressions for the ctx. + // You have access to the `ctx` parameter of the `{pread/gread}_with` inside the expression. + // TODO(implement) you have access to previous fields. + // TODO(check) will this break structs with fields named `ctx`?. + #[scroll(ctx = EndianDependent(ctx.clone()).len())] + custom_ctx: VariableLengthData, } use scroll::{ ctx::{SizeWith, TryFromCtx, TryIntoCtx}, - Pread, Pwrite, BE, LE, + Endian, Pread, Pwrite, BE, LE, }; fn main() { @@ -64,9 +76,6 @@ fn main() { let data: Data = bytes.pread_with(0, LE).unwrap(); let data2: Data = bytes2.pread_with(0, LE).unwrap(); assert_eq!(data, data2); - - /* - let data: Data = bytes.cread_with(0, LE); - assert_eq!(data, data2); - */ + // Not enough bytes because of ctx dependant length being too long. + assert!(bytes.pread_with::(0, BE).is_err()) } From 618e4cc709fb325a684e67db712becfc5eee55fd Mon Sep 17 00:00:00 2001 From: Easyoakland <97992568+Easyoakland@users.noreply.github.com> Date: Mon, 21 Oct 2024 00:55:54 -0600 Subject: [PATCH 10/10] spelling --- scroll_derive/examples/derive_custom_ctx.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scroll_derive/examples/derive_custom_ctx.rs b/scroll_derive/examples/derive_custom_ctx.rs index 543de00..3de31ee 100644 --- a/scroll_derive/examples/derive_custom_ctx.rs +++ b/scroll_derive/examples/derive_custom_ctx.rs @@ -76,6 +76,6 @@ fn main() { let data: Data = bytes.pread_with(0, LE).unwrap(); let data2: Data = bytes2.pread_with(0, LE).unwrap(); assert_eq!(data, data2); - // Not enough bytes because of ctx dependant length being too long. + // Not enough bytes because of ctx dependent length being too long. assert!(bytes.pread_with::(0, BE).is_err()) }