Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix handling of standalone .cbor and tagged types #112

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions src/intermediate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,6 @@ impl<'a> IntermediateTypes<'a> {
}
}

pub fn has_ident(&self, ident: &RustIdent) -> bool {
let foo: Vec<RustIdent> = self.type_aliases.keys().fold(vec![], |mut acc, alias| {
match alias {
AliasIdent::Reserved(_) => {},
AliasIdent::Rust(ident) => { acc.push(ident.clone()) }
};
acc
});
println!("{:?}", self.plain_groups.keys().chain(foo.iter()).chain(self.rust_structs.keys()).chain(self.generic_defs.keys()).chain(self.generic_instances.keys()));
self.plain_groups.contains_key(ident)
|| self.type_aliases.contains_key(&AliasIdent::Rust(ident.clone()))
|| self.rust_structs.contains_key(ident)
|| self.generic_defs.contains_key(ident)
|| self.generic_instances.contains_key(ident)
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI the code removed in this file is all unused. It comes from a previous PR that I forgot to delete and it didn't work because has_ident isn't stable across passes of the parsing.rs


pub fn type_aliases(&self) -> &BTreeMap<AliasIdent, (RustType, bool, bool)> {
&self.type_aliases
}
Expand Down Expand Up @@ -1755,12 +1739,3 @@ impl GenericInstance {
orig.clone()
}
}

fn try_ident_with_id(intermediate_types: &IntermediateTypes, name: &CDDLIdent, value: u32) -> CDDLIdent {
let new_ident = CDDLIdent::new(format!("{}{}", name, value));
let rust_ident = RustIdent::new(new_ident.clone());
match intermediate_types.has_ident(&rust_ident) {
false => new_ident,
true => try_ident_with_id(intermediate_types, name, value + 1)
}
}
93 changes: 89 additions & 4 deletions src/parsing.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use cddl::ast::parent::ParentVisitor;
use cddl::{ast::*, token};
use either::{Either};
use std::collections::{BTreeMap};
use std::collections::{BTreeMap, HashSet};
use std::mem::Discriminant;

use crate::comment_ast::{RuleMetadata, metadata_from_comments};
use crate::intermediate::{
Expand Down Expand Up @@ -279,7 +280,11 @@ fn parse_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, typ
},
ControlOperator::CBOR(ty) => match field_type() {
RustType::Primitive(Primitive::Bytes) => {
types.register_type_alias(type_name.clone(), RustType::CBORBytes(Box::new(ty)), true, true);
if has_embed(parent_visitor, get_rule(parent_visitor, &CDDLType::from(type1))) {
types.register_type_alias(type_name.clone(), RustType::CBORBytes(Box::new(ty)), true, true);
} else {
types.register_rust_struct(parent_visitor, RustStruct::new_wrapper(type_name.clone(), None, RustType::CBORBytes(Box::new(ty)), None));
}
},
_ => panic!(".cbor is only allowed on bytes as per CDDL spec"),
},
Expand Down Expand Up @@ -351,7 +356,11 @@ fn parse_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, typ
let base_type = types
.apply_type_aliases(&AliasIdent::new(CDDLIdent::new(ident.to_string())))
.expect(&format!("Please move definition for {} above {}", type_name, ident));
types.register_type_alias(type_name.clone(), RustType::Tagged(tag_unwrap, Box::new(RustType::CBORBytes(Box::new(base_type)))), true, true);
if has_embed(parent_visitor, get_rule(parent_visitor, &CDDLType::from(&inner_type.type1.type2))) {
types.register_type_alias(type_name.clone(), RustType::Tagged(tag_unwrap, Box::new(RustType::CBORBytes(Box::new(base_type)))), true, true)
} else {
types.register_rust_struct(parent_visitor, RustStruct::new_wrapper(type_name.clone(), Some(tag_unwrap), RustType::CBORBytes(Box::new(base_type)), None));
}
},
Some(ControlOperator::Range(min_max)) => {
match ident.to_string().as_str() {
Expand All @@ -368,7 +377,11 @@ fn parse_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, typ
let base_type = types
.apply_type_aliases(&AliasIdent::new(CDDLIdent::new(ident.to_string())))
.expect(&format!("Please move definition for {} above {}", type_name, ident));
types.register_type_alias(type_name.clone(), RustType::Tagged(tag_unwrap, Box::new(base_type)), true, true);
if has_embed(parent_visitor, get_rule(parent_visitor, &CDDLType::from(&inner_type.type1.type2))) {
types.register_type_alias(type_name.clone(), RustType::Tagged(tag_unwrap, Box::new(base_type)), false, true);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will need a minor change for conflict with #111

} else {
types.register_rust_struct(parent_visitor, RustStruct::new_wrapper(type_name.clone(), Some(tag_unwrap), base_type, None));
}
},
}
},
Expand Down Expand Up @@ -1033,6 +1046,13 @@ fn get_comment_after<'a>(parent_visitor: &'a ParentVisitor<'a, 'a>, cddl_type: &
}
}

fn get_rule<'a, 'b>(parent_visitor: &'a ParentVisitor, cddl_type: &CDDLType<'a, 'b>) -> &'a Rule<'a> {
match cddl_type {
CDDLType::CDDL(_) => panic!("Cannot get the rule name of a top-level CDDL node"),
CDDLType::Rule(rule) => rule,
other => get_rule(parent_visitor, other.parent(parent_visitor).unwrap()),
}
}
fn get_rule_name<'a, 'b>(parent_visitor: &'a ParentVisitor, cddl_type: &CDDLType<'a, 'b>) -> Identifier<'a> {
match cddl_type {
CDDLType::CDDL(_) => panic!("Cannot get the rule name of a top-level CDDL node"),
Expand All @@ -1046,3 +1066,68 @@ fn get_rule_name<'a, 'b>(parent_visitor: &'a ParentVisitor, cddl_type: &CDDLType
other => get_rule_name(parent_visitor, other.parent(parent_visitor).unwrap()),
}
}

/// An embedded type is a type embedded inside a larger structure (group, array, etc)
fn has_embed<'a>(parent_visitor: &'a ParentVisitor, rule: &Rule<'a>) -> bool {
_has_embed(parent_visitor, &CDDLType::from(rule))
}
fn _has_embed<'a, 'b>(parent_visitor: &'a ParentVisitor, cddl_type: &CDDLType<'a, 'b>) -> bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't use this name as _ prefixes in rust are to signify they're unused.

match cddl_type {
CDDLType::CDDL(_) => panic!("has_embed cannot be called on a root CDDL type"),
CDDLType::Rule(rule) => match rule {
Rule::Type { rule, .. } => _has_embed(parent_visitor, &CDDLType::from(rule)),
Rule::Group { rule, .. } => _has_embed(parent_visitor, &CDDLType::from(&rule.entry))
},
CDDLType::TypeRule(rule) => _has_embed(parent_visitor, &CDDLType::from(&rule.value)),
CDDLType::GroupRule(_) => true,
CDDLType::Group(_) => true,
CDDLType::GroupChoice(_) => true,
CDDLType::GenericParams(_) => false,
CDDLType::GenericParam(_) => false,
CDDLType::GenericArgs(t) => {
match t.args.len() {
1 => _has_embed(parent_visitor, &CDDLType::from(t.args.first().unwrap())),
_ => true,
}
},
CDDLType::GenericArg(t) => _has_embed(parent_visitor, &CDDLType::from(t.arg.as_ref())),
CDDLType::GroupEntry(_) => true,
CDDLType::Identifier(_) => false,
CDDLType::Type(t) => {
match t.type_choices.len() {
1 => _has_embed(parent_visitor, &CDDLType::from(t.type_choices.first().unwrap())),
_ => true,
}
},
CDDLType::TypeChoice(_) => false,
CDDLType::Type1(t) => {
match _has_embed(parent_visitor, &CDDLType::from(&t.type2)) {
true => true,
false => match &t.operator {
None => false,
Some(op) => _has_embed(parent_visitor, &CDDLType::from(op)),
}
}

},
CDDLType::Type2(t) => match t {
Type2::ParenthesizedType { pt, .. } => _has_embed(parent_visitor, &CDDLType::from(pt)),
Type2::Map { .. } => true,
Type2::Array { .. } => true,
Type2::Unwrap { .. } => true,
Type2::ChoiceFromInlineGroup { .. } => true,
Type2::ChoiceFromGroup { .. } => true,
Type2::TaggedData { t, .. } => _has_embed(parent_visitor, &CDDLType::from(t)),
_ => false,
},
CDDLType::Operator(op) => _has_embed(parent_visitor, &CDDLType::from(&op.type2)),
CDDLType::Occurrence(_) => true,
CDDLType::Occur(_) => true,
CDDLType::Value(_) => false,
CDDLType::ValueMemberKeyEntry(_) => true,
CDDLType::TypeGroupnameEntry(_) => true,
CDDLType::MemberKey(_) => true,
CDDLType::NonMemberKey(_) => true,
_ => false
}
}
3 changes: 3 additions & 0 deletions tests/core/input.cddl
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,6 @@ signed_ints = [

paren_size = uint .size (1)
paren_cbor = bytes .cbor (text)

no_embed_tag = #6.24(uint)
no_embed_cbor = bytes .cbor uint
24 changes: 24 additions & 0 deletions tests/core/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,28 @@ mod tests {
let max = SignedInts::new(u8::MAX, u16::MAX, u32::MAX, u64::MAX, i8::MAX, i16::MAX, i32::MAX, i64::MAX, u64::MAX);
deser_test(&max);
}

#[test]
fn paren_types() {
{
let _: ParenSize = 5u8;
}
{
let cbor = ParenCbor::new("foo".to_string());
// TODO: fix this assert by inputting the right value
assert_eq!(cbor.to_bytes(), vec![]);
}
}

#[test]
fn toplevel_types() {
{
let tag = NoEmbedTag::new(5);
assert_eq!(tag.to_bytes(), vec![0xd8, 0x18, 0x05]);
}
{
let cbor = NoEmbedCbor::new(5);
assert_eq!(cbor.to_bytes(), vec![0x41, 0x05]);
}
}
}