11use proc_macro2:: Span ;
22use quote:: { format_ident, quote, ToTokens } ;
33use syn:: {
4- Attribute , Expr , ExprLit , Fields , GenericArgument , Ident , ItemStruct , Lit , LitInt ,
5- PathArguments , Type , TypePath ,
4+ spanned :: Spanned , Attribute , Expr , ExprLit , Fields , GenericArgument , Ident , ItemStruct , Lit ,
5+ LitInt , PathArguments , Type , TypePath ,
66} ;
77
88pub ( crate ) fn expand_fixed_layout (
@@ -189,12 +189,19 @@ pub(crate) fn expand_fixed_layout(
189189 bytes: & [ u8 ] ,
190190 offset: usize ,
191191 capacity: usize ,
192+ len_width: usize ,
192193 field_name: & ' static str ,
193194 expect_msg: & ' static str
194195 ) -> :: core:: result:: Result <( ) , pinocchio:: error:: ProgramError > {
195- let len = {
196- let raw: [ u8 ; 8 ] = bytes[ offset..offset + 8 ] . try_into( ) . expect( expect_msg) ;
197- u64 :: from_le_bytes( raw) as usize
196+ let len = match len_width {
197+ 1 => bytes[ offset] as usize ,
198+ 2 => {
199+ let raw: [ u8 ; 2 ] =bytes[ offset..offset + 2 ] . try_into( ) . expect( "validated len" ) ;
200+ u16 :: from_le_bytes( raw) as usize
201+ } ,
202+ _ => {
203+ unreachable!( )
204+ }
198205 } ;
199206 if len > capacity {
200207 let mut logger = pinocchio_log:: logger:: Logger :: <200 >:: default ( ) ;
@@ -277,6 +284,7 @@ enum FixedFieldKind {
277284 Vec {
278285 elem : FixedValueKind ,
279286 capacity : usize ,
287+ len_width : usize ,
280288 } ,
281289}
282290
@@ -289,7 +297,11 @@ impl FixedFieldKind {
289297 fn slot_len ( & self ) -> usize {
290298 match self {
291299 Self :: Value { value, optional } => value. size ( ) + usize:: from ( * optional) ,
292- Self :: Vec { elem, capacity } => 8 + elem. size ( ) * capacity,
300+ Self :: Vec {
301+ elem,
302+ capacity,
303+ len_width,
304+ } => len_width + elem. size ( ) * capacity,
293305 }
294306 }
295307
@@ -373,21 +385,25 @@ impl FixedFieldKind {
373385 error : syn:: Error :: new ( field_ident. span ( ) , message) ,
374386 } ) )
375387 }
376- Self :: Vec { elem, .. } => {
388+ Self :: Vec {
389+ elem,
390+ capacity : _,
391+ len_width,
392+ } => {
377393 let align = elem. align ( ) ;
378394 if align > 8 {
379395 return Err ( syn:: Error :: new (
380396 field_ident. span ( ) ,
381397 format ! (
382- "field `{}` cannot expose a slice view in fixed_layout: each Vec element is {} byte(s) but alignment is {} byte(s), and fixed_layout only assumes the input buffer is 8-byte aligned" ,
398+ "field `{}` cannot expose a slice view in fixed_layout: each Vec element is {} byte(s) but alignment is {} byte(s), and fixed_layout only assumes the input buffer is 8-byte aligned, so it cannot support type which requires alignment greater than 8 " ,
383399 field_ident,
384400 elem. size( ) ,
385401 align,
386402 ) ,
387403 ) ) ;
388404 }
389405
390- let first_elem_offset = offset + 8 ;
406+ let first_elem_offset = offset + len_width ;
391407 let misalignment = first_elem_offset % align;
392408 if misalignment == 0 {
393409 return Ok ( None ) ;
@@ -399,9 +415,10 @@ impl FixedFieldKind {
399415 error : syn:: Error :: new (
400416 field_ident. span ( ) ,
401417 format ! (
402- "field `{}` needs {} byte(s) of padding before it: its Vec elements start after a 8 -byte length prefix, so element 0 would start at offset {}, but slice views require {}-byte alignment. Insert `_pad: [u8; {}]` before `{}` so element 0 starts at offset {}" ,
418+ "field `{}` needs {} byte(s) of padding before it: its Vec elements start after a {} -byte length prefix, so element 0 would start at offset {}, but slice views require {}-byte alignment. Insert `_pad: [u8; {}]` before `{}` so element 0 starts at offset {}" ,
403419 field_ident,
404420 padding,
421+ len_width,
405422 first_elem_offset,
406423 align,
407424 padding,
@@ -424,10 +441,14 @@ impl FixedFieldKind {
424441 quote ! ( core:: mem:: size_of:: <#ty>( ) )
425442 }
426443 }
427- Self :: Vec { elem, capacity } => {
444+ Self :: Vec {
445+ elem,
446+ capacity,
447+ len_width,
448+ } => {
428449 let elem_ty = elem. ty ( ) ;
429450 let capacity_lit = usize_lit ( * capacity) ;
430- let len_width_lit = usize_lit ( 8 ) ;
451+ let len_width_lit = usize_lit ( * len_width ) ;
431452 quote ! ( ( #len_width_lit + core:: mem:: size_of:: <#elem_ty>( ) * #capacity_lit) )
432453 }
433454 }
@@ -447,11 +468,19 @@ impl FixedFieldKind {
447468 quote ! { }
448469 }
449470 }
450- Self :: Vec { capacity, .. } => {
471+ Self :: Vec {
472+ capacity,
473+ len_width,
474+ ..
475+ } => {
451476 let capacity_lit = usize_lit ( * capacity) ;
452- let expect_msg = format ! ( "validate encoded-len for field '{}'" , field_name) ;
477+ let len_width_lit = usize_lit ( * len_width) ;
478+ let expect_msg = format ! (
479+ "validate encoded-len [len_width={}] for field '{}'" ,
480+ len_width, field_name
481+ ) ;
453482 quote ! {
454- Self :: __validate_vec_len( bytes, #offset_expr, #capacity_lit, #field_name, #expect_msg) ?;
483+ Self :: __validate_vec_len( bytes, #offset_expr, #capacity_lit, #len_width_lit , # field_name, #expect_msg) ?;
455484 }
456485 }
457486 }
@@ -487,20 +516,30 @@ impl FixedFieldKind {
487516 }
488517 }
489518 }
490- Self :: Vec { elem, capacity } => {
519+ Self :: Vec {
520+ elem,
521+ capacity,
522+ len_width,
523+ } => {
491524 let elem_size = usize_lit ( elem. size ( ) ) ;
492525 let capacity = usize_lit ( * capacity) ;
526+ let len_width_ty = match * len_width {
527+ 1 => quote ! ( u8 ) ,
528+ 2 => quote ! ( u16 ) ,
529+ _ => unreachable ! ( ) ,
530+ } ;
531+ let len_width = usize_lit ( * len_width) ;
493532 quote ! {
494533 #fields_encode_expr
495534
496535 if self . #field_ident. len( ) > #capacity {
497536 return Err ( pinocchio:: error:: ProgramError :: InvalidRealloc ) ;
498537 }
499538
500- bytes[ #offset..#offset + 8 ] . copy_from_slice( bytemuck:: bytes_of( & ( self . #field_ident. len( ) as u64 ) ) ) ;
501- bytes[ #offset + 8 ..#offset + 8 + self . #field_ident. len( ) * #elem_size] . copy_from_slice( bytemuck:: cast_slice( & self . #field_ident. as_slice( ) ) ) ;
539+ bytes[ #offset..#offset + #len_width ] . copy_from_slice( bytemuck:: bytes_of( & ( self . #field_ident. len( ) as #len_width_ty ) ) ) ;
540+ bytes[ #offset + #len_width ..#offset + #len_width + self . #field_ident. len( ) * #elem_size] . copy_from_slice( bytemuck:: cast_slice( & self . #field_ident. as_slice( ) ) ) ;
502541 if self . #field_ident. len( ) < #capacity {
503- bytes[ #offset + 8 + self . #field_ident. len( ) * #elem_size..#offset + 8 + #capacity * #elem_size] . fill( 0 ) ;
542+ bytes[ #offset + #len_width + self . #field_ident. len( ) * #elem_size..#offset + #len_width + #capacity * #elem_size] . fill( 0 ) ;
504543 }
505544 }
506545 }
@@ -555,11 +594,15 @@ impl FixedFieldKind {
555594 }
556595 }
557596 }
558- Self :: Vec { elem, capacity } => {
597+ Self :: Vec {
598+ elem,
599+ capacity,
600+ len_width,
601+ } => {
559602 let elem_ty = elem. ty ( ) ;
560- let len_expr = read_len_expr ( offset) ;
603+ let len_expr = read_len_expr ( offset, * len_width ) ;
561604 let offset = usize_lit ( offset) ;
562- let len_width_lit = usize_lit ( 8 ) ;
605+ let len_width_lit = usize_lit ( * len_width ) ;
563606 let capacity_name = format_ident ! ( "{}_capacity" , accessor_ident( field_ident) ) ;
564607 let capacity_lit = usize_lit ( * capacity) ;
565608 Ok ( quote ! {
@@ -592,6 +635,7 @@ fn parse_field_layout(field: &syn::Field) -> syn::Result<FixedFieldKind> {
592635 return Ok ( FixedFieldKind :: Vec {
593636 elem : parse_value_kind ( elem_ty) ?,
594637 capacity,
638+ len_width : len_width ( capacity, field. span ( ) ) ?,
595639 } ) ;
596640 }
597641
@@ -802,6 +846,19 @@ fn integer_primitive_name(ty: &Type) -> Option<String> {
802846 }
803847}
804848
849+ fn len_width ( capacity : usize , span : proc_macro2:: Span ) -> syn:: Result < usize > {
850+ if capacity <= 0xFF {
851+ Ok ( 1 )
852+ } else if capacity <= 0xFFFF {
853+ Ok ( 2 )
854+ } else {
855+ Err ( syn:: Error :: new (
856+ span,
857+ "capacity above 0xFFFF is not supported implying len_width can be at max 2 bytes" ,
858+ ) )
859+ }
860+ }
861+
805862fn is_string ( ty : & Type ) -> bool {
806863 let Type :: Path ( type_path) = ty else {
807864 return false ;
@@ -923,13 +980,22 @@ fn borrow_ref_expr(ty: &Type, bytes_expr: proc_macro2::TokenStream) -> proc_macr
923980 quote ! ( :: bytemuck:: from_bytes:: <#ty>( #bytes_expr) )
924981}
925982
926- fn read_len_expr ( offset : usize ) -> proc_macro2:: TokenStream {
927- quote ! ( {
928- let raw: [ u8 ; 8 ] = self . bytes[ #offset..#offset + 8 ]
929- . try_into( )
930- . expect( "validated len" ) ;
931- u64 :: from_le_bytes( raw) as usize
932- } )
983+ fn read_len_expr ( offset : usize , len_width : usize ) -> proc_macro2:: TokenStream {
984+ match len_width {
985+ 1 => quote ! ( self . bytes[ #offset] as usize ) ,
986+ 2 => quote ! ( {
987+ let raw: [ u8 ; 2 ] = self . bytes[ #offset..#offset + 2 ] . try_into( ) . expect( "validated len" ) ;
988+ u16 :: from_le_bytes( raw) as usize
989+ } ) ,
990+ 3 => quote ! ( {
991+ let mut raw = [ 0u8 ; 4 ] ;
992+ raw[ 0 ..3 ] . copy_from_slice( & self . bytes[ #offset..#offset + 3 ] ) ;
993+ u32 :: from_le_bytes( raw) as usize
994+ } ) ,
995+ _ => {
996+ unreachable ! ( )
997+ }
998+ }
933999}
9341000
9351001#[ cfg( test) ]
@@ -971,6 +1037,7 @@ mod tests {
9711037 let item: syn:: ItemStruct = parse_quote ! {
9721038 struct Args {
9731039 flag: u8 ,
1040+ padding: [ u8 ; 7 ] ,
9741041 #[ capacity = 2 ]
9751042 values: Vec <[ u64 ; 2 ] >,
9761043 }
0 commit comments