Skip to content

Commit bffaf66

Browse files
Fix handling of standalone .cbor and tagged types
1 parent 5a7e680 commit bffaf66

File tree

3 files changed

+116
-5
lines changed

3 files changed

+116
-5
lines changed

src/parsing.rs

Lines changed: 100 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use cddl::ast::parent::ParentVisitor;
22
use cddl::{ast::*, token};
33
use either::{Either};
4-
use std::collections::{BTreeMap};
4+
use std::collections::{BTreeMap, HashSet};
5+
use std::mem::Discriminant;
56

67
use crate::comment_ast::{RuleMetadata, metadata_from_comments};
78
use 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+
}
10311051
fn 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+
}

tests/core/input.cddl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,7 @@ signed_ints = [
6161
; The fix would be ideal as even though the true min in CBOR would be -u64::MAX
6262
; we can't test that since isize::BITS is never > 64 in any normal system and likely never will be
6363
i64_min: -9223372036854775808
64-
]
64+
]
65+
66+
no_embed_tag = #6.24(uint)
67+
no_embed_cbor = bytes .cbor uint

tests/core/tests.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,16 @@ mod tests {
126126
let max = SignedInts::new(u8::MAX, u16::MAX, u32::MAX, u64::MAX, i8::MAX, i16::MAX, i32::MAX, i64::MAX, u64::MAX);
127127
deser_test(&max);
128128
}
129+
130+
#[test]
131+
fn toplevel_types() {
132+
{
133+
let tag = NoEmbedTag::new(5);
134+
assert_eq!(tag.to_bytes(), vec![0xd8, 0x18, 0x05]);
135+
}
136+
{
137+
let cbor = NoEmbedCbor::new(5);
138+
assert_eq!(cbor.to_bytes(), vec![0x41, 0x05]);
139+
}
140+
}
129141
}

0 commit comments

Comments
 (0)