@@ -294,6 +294,80 @@ impl NamedDeclaration {
294294 DeclarationKind :: Optional ( o) => o. optional_default_value ( tab) ,
295295 }
296296 }
297+
298+ fn is_varlen_reader ( & self , tab : & ValidatedSymbolTable ) -> bool {
299+ match & self . kind {
300+ DeclarationKind :: Scalar ( ty) | DeclarationKind :: Optional ( ty) => {
301+ ty. is_reader ( tab) && ty. size ( tab) . is_none ( )
302+ }
303+ _ => false ,
304+ }
305+ }
306+
307+ fn is_self_referential ( & self , tab : & ValidatedSymbolTable ) -> bool {
308+ match & self . kind {
309+ DeclarationKind :: Scalar ( xdr_type) | DeclarationKind :: Optional ( xdr_type) => {
310+ xdr_type. self_referential_optional ( tab)
311+ }
312+ DeclarationKind :: Array ( _) => false ,
313+ }
314+ }
315+
316+ fn get_width ( & self , buf : & mut CodeBuf , name : & str , tab : & ValidatedSymbolTable ) {
317+ match & self . kind {
318+ DeclarationKind :: Scalar ( t) => t. get_width ( buf, name, tab) ,
319+ DeclarationKind :: Array ( array) => match & array. kind {
320+ ArrayKind :: Byte | ArrayKind :: Ascii => {
321+ buf. add_line ( & format ! ( "xdr_lib::padding_4byte({}.len())" , name) )
322+ }
323+ ArrayKind :: UserType ( xdr_type) => {
324+ let elem_size = xdr_type. size ( tab) ;
325+ if let Some ( elem_size) = elem_size {
326+ buf. add_line ( & format ! (
327+ "xdr_lib::padding_4byte({}.len() * {})" ,
328+ name, elem_size
329+ ) ) ;
330+ } else {
331+ let count_addition = if let ArraySize :: Fixed ( _) = & array. size {
332+ ""
333+ } else {
334+ "4usize + "
335+ } ;
336+ buf. block_with_trailer (
337+ & format ! (
338+ "{count_addition}xdr_lib::padding_4byte({}.iter().map(|_v|" ,
339+ name
340+ ) ,
341+ ").sum::<usize>())" ,
342+ |buf| {
343+ xdr_type. get_width ( buf, "_v" , tab) ;
344+ } ,
345+ ) ;
346+ }
347+ }
348+ } ,
349+ DeclarationKind :: Optional ( xdr_type) => {
350+ if self . is_self_referential ( tab) {
351+ buf. block_with_trailer (
352+ & format ! ( "4usize + xdr_lib::padding_4byte({}.iter().map(|_v|" , name) ,
353+ ").sum::<usize>())" ,
354+ |buf| {
355+ buf. code_block ( "4usize +" , |buf| {
356+ xdr_type. get_width ( buf, "_v" , tab) ;
357+ } ) ;
358+ } ,
359+ ) ;
360+ } else {
361+ buf. code_block ( & format ! ( "4usize + match &{}" , name) , |buf| {
362+ buf. add_line ( "None => 0," ) ;
363+ buf. code_block ( "Some(_val) =>" , |buf| {
364+ xdr_type. get_width ( buf, "_val" , tab) ;
365+ } ) ;
366+ } )
367+ }
368+ }
369+ }
370+ }
297371}
298372
299373impl ValidatedUnion {
@@ -308,6 +382,8 @@ impl ValidatedUnion {
308382 }
309383 buf. add_line ( "" ) ;
310384 self . deserialize_definition ( buf, tab) ;
385+ buf. add_line ( "" ) ;
386+ self . width_getter ( buf, tab) ;
311387 } ) ;
312388 buf. add_line ( "" ) ;
313389 }
@@ -326,6 +402,44 @@ impl ValidatedUnion {
326402 } )
327403 } ) ;
328404 }
405+ fn width_getter ( & self , buf : & mut CodeBuf , tab : & ValidatedSymbolTable ) {
406+ buf. code_block ( "pub fn get_width(&self) -> usize" , |buf| match & self . body {
407+ ValidatedUnionBody :: Bool ( validated_union_bool_body) => {
408+ buf. code_block ( "4usize + match &self.inner" , |buf| {
409+ buf. add_line ( "None => 0," ) ;
410+ buf. code_block ( "Some(_val) =>" , |buf| {
411+ validated_union_bool_body
412+ . true_arm
413+ . get_width ( buf, "_val" , tab) ;
414+ } ) ;
415+ } )
416+ }
417+ ValidatedUnionBody :: Enum ( e) => {
418+ buf. code_block ( "4usize + match &self" , |buf| {
419+ for arm in e. arms . iter ( ) {
420+ let name = ValidatedUnionEnumBody :: arm_name ( & arm. 0 ) ;
421+ match & arm. 1 {
422+ Declaration :: Void => buf. add_line ( & format ! ( "Self::{name} => 0," ) ) ,
423+ Declaration :: Named ( n) => {
424+ buf. code_block ( & format ! ( "Self::{name}(_val) =>" ) , |buf| {
425+ n. get_width ( buf, "_val" , tab) ;
426+ } ) ;
427+ }
428+ } ;
429+ }
430+ match & e. default_arm {
431+ Some ( Declaration :: Void ) => buf. add_line ( "Self::Default => 0," ) ,
432+ Some ( Declaration :: Named ( n) ) => {
433+ buf. code_block ( "Self::Default(_val) =>" , |buf| {
434+ n. get_width ( buf, "_val" , tab) ;
435+ } ) ;
436+ }
437+ None => { }
438+ }
439+ } ) ;
440+ }
441+ } ) ;
442+ }
329443}
330444
331445impl ValidatedUnionBoolBody {
@@ -545,10 +659,45 @@ impl ValidatedStruct {
545659 }
546660 buf. add_line ( "" ) ;
547661 self . deserialize_definition ( buf, tab) ;
662+ buf. add_line ( "" ) ;
663+ self . width_getters ( buf, tab) ;
548664 } ) ;
549665 buf. add_line ( "" ) ;
550666 }
551667
668+ fn width_getters ( & self , buf : & mut CodeBuf , tab : & ValidatedSymbolTable ) {
669+ let varlen_members = self . get_variable_width_members ( tab) ;
670+
671+ for name in varlen_members {
672+ let ( member, _) = self . members . iter ( ) . find ( |val| val. 0 . name == * name) . unwrap ( ) ;
673+
674+ buf. code_block ( & format ! ( "fn get_{}_width(&self) -> usize" , name) , |buf| {
675+ member. get_width ( buf, & format ! ( "self.{}" , name) , tab)
676+ } ) ;
677+ }
678+
679+ buf. code_block ( "pub fn get_width(&self) -> usize" , |buf| {
680+ if let Some ( ( last, last_off) ) = self . members . last ( ) {
681+ let last_size = last. size ( tab) ;
682+ let mut overall_definition_size = DefinitionSize {
683+ known : last_off. known + last_size. unwrap_or ( 0 ) ,
684+ deps : last_off. deps . clone ( ) ,
685+ } ;
686+
687+ if last_size. is_none ( ) {
688+ overall_definition_size. deps . push ( last. name . clone ( ) ) ;
689+ }
690+
691+ buf. add_line ( & Self :: offset_to_string_with_unwrapper (
692+ & overall_definition_size,
693+ "" ,
694+ ) ) ;
695+ } else {
696+ buf. add_line ( "0" ) ;
697+ }
698+ } ) ;
699+ }
700+
552701 fn definition ( & self , buf : & mut CodeBuf , tab : & ValidatedSymbolTable ) {
553702 buf. type_header ( ) ;
554703 buf. code_block ( & format ! ( "pub struct {}" , self . name) , |buf| {
@@ -786,6 +935,33 @@ impl XdrType {
786935 }
787936 . to_string ( )
788937 }
938+
939+ fn get_width ( & self , buf : & mut CodeBuf , name : & str , tab : & ValidatedSymbolTable ) {
940+ match self {
941+ XdrType :: Name ( n) => {
942+ let found = tab. lookup_definition ( n) ;
943+
944+ let defsize = found. size ( tab) ;
945+
946+ if defsize. is_determinate ( ) {
947+ buf. add_line ( & format ! ( "{}" , defsize. known) ) ;
948+ } else {
949+ match found {
950+ ValidatedDefinition :: Const ( _) => unreachable ! ( ) ,
951+ ValidatedDefinition :: TypeDef ( td) => td. decl . get_width ( buf, name, tab) ,
952+ ValidatedDefinition :: Struct ( _) => {
953+ buf. add_line ( & format ! ( "{name}.get_width()" ) ) ;
954+ }
955+ ValidatedDefinition :: Enum ( _) => buf. add_line ( "4" ) ,
956+ ValidatedDefinition :: Union ( _) => {
957+ buf. add_line ( & format ! ( "{name}.get_width()" ) ) ;
958+ }
959+ }
960+ }
961+ }
962+ _ => buf. add_line ( & format ! ( "{}" , self . size( tab) . unwrap( ) ) ) ,
963+ }
964+ }
789965}
790966
791967struct CodeBuf {
0 commit comments