11use cddl:: ast:: parent:: ParentVisitor ;
22use cddl:: { ast:: * , token} ;
33use either:: { Either } ;
4- use std:: collections:: { BTreeMap } ;
4+ use std:: collections:: { BTreeMap , HashSet } ;
5+ use std:: mem:: Discriminant ;
56
67use crate :: comment_ast:: { RuleMetadata , metadata_from_comments} ;
78use crate :: intermediate:: {
@@ -277,7 +278,11 @@ fn parse_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, typ
277278 } ,
278279 ControlOperator :: CBOR ( ty) => match field_type ( ) {
279280 RustType :: Primitive ( Primitive :: Bytes ) => {
280- types. register_type_alias ( type_name. clone ( ) , RustType :: CBORBytes ( Box :: new ( ty) ) , true , true ) ;
281+ if has_embed ( parent_visitor, get_rule ( parent_visitor, & CDDLType :: from ( type1) ) ) {
282+ types. register_type_alias ( type_name. clone ( ) , RustType :: CBORBytes ( Box :: new ( ty) ) , true , true ) ;
283+ } else {
284+ types. register_rust_struct ( parent_visitor, RustStruct :: new_wrapper ( type_name. clone ( ) , None , RustType :: CBORBytes ( Box :: new ( ty) ) , None ) ) ;
285+ }
281286 } ,
282287 _ => panic ! ( ".cbor is only allowed on bytes as per CDDL spec" ) ,
283288 } ,
@@ -349,7 +354,11 @@ fn parse_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, typ
349354 let base_type = types
350355 . apply_type_aliases ( & AliasIdent :: new ( CDDLIdent :: new ( ident. to_string ( ) ) ) )
351356 . expect ( & format ! ( "Please move definition for {} above {}" , type_name, ident) ) ;
352- types. register_type_alias ( type_name. clone ( ) , RustType :: Tagged ( tag_unwrap, Box :: new ( RustType :: CBORBytes ( Box :: new ( base_type) ) ) ) , true , true ) ;
357+ if has_embed ( parent_visitor, get_rule ( parent_visitor, & CDDLType :: from ( & inner_type. type1 . type2 ) ) ) {
358+ types. register_type_alias ( type_name. clone ( ) , RustType :: Tagged ( tag_unwrap, Box :: new ( RustType :: CBORBytes ( Box :: new ( base_type) ) ) ) , true , true )
359+ } else {
360+ types. register_rust_struct ( parent_visitor, RustStruct :: new_wrapper ( type_name. clone ( ) , Some ( tag_unwrap) , RustType :: CBORBytes ( Box :: new ( base_type) ) , None ) ) ;
361+ }
353362 } ,
354363 Some ( ControlOperator :: Range ( min_max) ) => {
355364 match ident. to_string ( ) . as_str ( ) {
@@ -366,7 +375,11 @@ fn parse_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, typ
366375 let base_type = types
367376 . apply_type_aliases ( & AliasIdent :: new ( CDDLIdent :: new ( ident. to_string ( ) ) ) )
368377 . expect ( & format ! ( "Please move definition for {} above {}" , type_name, ident) ) ;
369- types. register_type_alias ( type_name. clone ( ) , RustType :: Tagged ( tag_unwrap, Box :: new ( base_type) ) , true , true ) ;
378+ if has_embed ( parent_visitor, get_rule ( parent_visitor, & CDDLType :: from ( & inner_type. type1 . type2 ) ) ) {
379+ types. register_type_alias ( type_name. clone ( ) , RustType :: Tagged ( tag_unwrap, Box :: new ( base_type) ) , false , true ) ;
380+ } else {
381+ types. register_rust_struct ( parent_visitor, RustStruct :: new_wrapper ( type_name. clone ( ) , Some ( tag_unwrap) , base_type, None ) ) ;
382+ }
370383 } ,
371384 }
372385 } ,
@@ -1028,6 +1041,13 @@ fn get_comment_after<'a>(parent_visitor: &'a ParentVisitor<'a, 'a>, cddl_type: &
10281041 }
10291042}
10301043
1044+ fn get_rule < ' a , ' b > ( parent_visitor : & ' a ParentVisitor , cddl_type : & CDDLType < ' a , ' b > ) -> & ' a Rule < ' a > {
1045+ match cddl_type {
1046+ CDDLType :: CDDL ( _) => panic ! ( "Cannot get the rule name of a top-level CDDL node" ) ,
1047+ CDDLType :: Rule ( rule) => rule,
1048+ other => get_rule ( parent_visitor, other. parent ( parent_visitor) . unwrap ( ) ) ,
1049+ }
1050+ }
10311051fn get_rule_name < ' a , ' b > ( parent_visitor : & ' a ParentVisitor , cddl_type : & CDDLType < ' a , ' b > ) -> Identifier < ' a > {
10321052 match cddl_type {
10331053 CDDLType :: CDDL ( _) => panic ! ( "Cannot get the rule name of a top-level CDDL node" ) ,
@@ -1041,3 +1061,79 @@ fn get_rule_name<'a, 'b>(parent_visitor: &'a ParentVisitor, cddl_type: &CDDLType
10411061 other => get_rule_name ( parent_visitor, other. parent ( parent_visitor) . unwrap ( ) ) ,
10421062 }
10431063}
1064+
1065+ /// An embedded type is a type embedded inside a larger structure (group, array, etc)
1066+ fn has_embed < ' a > ( parent_visitor : & ' a ParentVisitor , rule : & Rule < ' a > ) -> bool {
1067+ _has_embed ( parent_visitor, & CDDLType :: from ( rule) )
1068+ }
1069+ fn _has_embed < ' a , ' b > ( parent_visitor : & ' a ParentVisitor , cddl_type : & CDDLType < ' a , ' b > ) -> bool {
1070+ match cddl_type {
1071+ CDDLType :: CDDL ( _) => panic ! ( "has_embed cannot be called on a root CDDL type" ) ,
1072+ CDDLType :: Rule ( rule) => match rule {
1073+ Rule :: Type { rule, .. } => _has_embed ( parent_visitor, & CDDLType :: from ( rule) ) ,
1074+ Rule :: Group { rule, .. } => _has_embed ( parent_visitor, & CDDLType :: from ( & rule. entry ) )
1075+ } ,
1076+ CDDLType :: TypeRule ( rule) => _has_embed ( parent_visitor, & CDDLType :: from ( & rule. value ) ) ,
1077+ CDDLType :: GroupRule ( _) => true ,
1078+ CDDLType :: Group ( _) => true ,
1079+ CDDLType :: GroupChoice ( _) => true ,
1080+ CDDLType :: GenericParams ( _) => false ,
1081+ CDDLType :: GenericParam ( _) => false ,
1082+ CDDLType :: GenericArgs ( t) => {
1083+ match t. args . len ( ) {
1084+ 1 => _has_embed ( parent_visitor, & CDDLType :: from ( t. args . first ( ) . unwrap ( ) ) ) ,
1085+ _ => true ,
1086+ }
1087+ } ,
1088+ CDDLType :: GenericArg ( t) => _has_embed ( parent_visitor, & CDDLType :: from ( t. arg . as_ref ( ) ) ) ,
1089+ CDDLType :: GroupEntry ( _) => true ,
1090+ CDDLType :: Identifier ( _) => false ,
1091+ CDDLType :: Type ( t) => {
1092+ match t. type_choices . len ( ) {
1093+ 1 => _has_embed ( parent_visitor, & CDDLType :: from ( t. type_choices . first ( ) . unwrap ( ) ) ) ,
1094+ _ => true ,
1095+ }
1096+ } ,
1097+ CDDLType :: TypeChoice ( _) => false ,
1098+ CDDLType :: Type1 ( t) => {
1099+ match _has_embed ( parent_visitor, & CDDLType :: from ( & t. type2 ) ) {
1100+ true => true ,
1101+ false => match & t. operator {
1102+ None => false ,
1103+ Some ( op) => _has_embed ( parent_visitor, & CDDLType :: from ( op) ) ,
1104+ }
1105+ }
1106+
1107+ } ,
1108+ CDDLType :: Type2 ( t) => match t {
1109+ Type2 :: ParenthesizedType { pt, .. } => _has_embed ( parent_visitor, & CDDLType :: from ( pt) ) ,
1110+ Type2 :: Map { .. } => true ,
1111+ Type2 :: Array { .. } => true ,
1112+ Type2 :: Unwrap { .. } => true ,
1113+ Type2 :: ChoiceFromInlineGroup { .. } => true ,
1114+ Type2 :: ChoiceFromGroup { .. } => true ,
1115+ Type2 :: TaggedData { t, .. } => _has_embed ( parent_visitor, & CDDLType :: from ( t) ) ,
1116+ _ => false ,
1117+ } ,
1118+ CDDLType :: Operator ( op) => _has_embed ( parent_visitor, & CDDLType :: from ( & op. type2 ) ) ,
1119+ CDDLType :: Occurrence ( _) => true ,
1120+ CDDLType :: Occur ( _) => true ,
1121+ CDDLType :: Value ( _) => false ,
1122+ CDDLType :: ValueMemberKeyEntry ( _) => true ,
1123+ CDDLType :: TypeGroupnameEntry ( _) => true ,
1124+ CDDLType :: MemberKey ( _) => true ,
1125+ CDDLType :: NonMemberKey ( _) => true ,
1126+ _ => false
1127+ }
1128+ }
1129+
1130+ /// A recursive type is defied as one that has a node of the same type in its parent hierarchy
1131+ fn is_recursive < ' a , ' b > ( parent_visitor : & ' a ParentVisitor , cddl_type : & CDDLType < ' a , ' b > ) -> bool {
1132+ _is_recursive ( parent_visitor, & mut HashSet :: new ( ) , cddl_type)
1133+ }
1134+ fn _is_recursive < ' a , ' b > ( parent_visitor : & ' a ParentVisitor , seen_set : & mut HashSet < Discriminant < CDDLType < ' a , ' b > > > , cddl_type : & CDDLType < ' a , ' b > ) -> bool {
1135+ match seen_set. insert ( std:: mem:: discriminant ( cddl_type) ) {
1136+ true => _is_recursive ( parent_visitor, seen_set, cddl_type. parent ( parent_visitor) . unwrap ( ) ) ,
1137+ false => false
1138+ }
1139+ }
0 commit comments