From 249f7fdb8d0598d554da28ddaed8389e215f97ab Mon Sep 17 00:00:00 2001 From: Eugene Gostkin Date: Wed, 16 Nov 2022 15:01:32 +0100 Subject: [PATCH 1/4] Enhance .gitignore, beautify ci steps --- .github/workflows/build.yml | 35 ++++++++++++++++++++++++++++++----- .gitignore | 17 ++++++++++++++++- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fb8bbe0..49e39eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,20 +1,45 @@ -on: [ push, pull_request ] +name: Linter and unit tests -name: build +on: [ push, pull_request ] jobs: test: name: Rust project runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Install latest nightly + - name: "Checkout" + uses: actions/checkout@v2 + + - name: "Install latest nightly" uses: actions-rs/toolchain@v1 with: + profile: minimal toolchain: nightly override: true components: rustfmt, clippy - - name: Run cargo test + + - name: "Run cargo test" uses: actions-rs/cargo@v1 with: command: test + args: --all-features --all-targets + +# Uncomment when supported: +# - name: "Format check" +# uses: actions-rs/cargo@v1 +# with: +# command: fmt +# args: -- --check +# - name: "Linter checks" +# uses: actions-rs/cargo@v1 +# with: +# command: clippy +# args: --all-features --all-targets -- --deny "clippy::all" +# +# - name: "Check" +# uses: actions-rs/cargo@v1 +# with: +# command: check +# args: --all-features --all-targets +# +# diff --git a/.gitignore b/.gitignore index 5f0b2de..25ba0cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,18 @@ +# global .gitignore +*.swp + +# IDE +.idea/ +.vscode/ + +# Rust +target/ +book/ +Cargo.lock + +# Mac files +**/.DS_STore + +# Test files tests/*/export/** tests/*/export_wasm/** -target/** From 25d1b00b6c88b230e1be3663ce818ca9f863a1da Mon Sep 17 00:00:00 2001 From: Eugene Gostkin Date: Wed, 16 Nov 2022 15:11:03 +0100 Subject: [PATCH 2/4] Specify paths to run tests --- .github/workflows/build.yml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 49e39eb..fa66da6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,20 @@ name: Linter and unit tests -on: [ push, pull_request ] +on: + push: + branches: [ master ] + paths: + - '.github/workflows/build.yml' + - "**/Cargo.*" + - "src/**" + - "tests/**" + pull_request: + branches: [ master ] + paths: + - '.github/workflows/build.yml' + - "**/Cargo.*" + - "src/**" + - "tests/**" jobs: test: From a70d3f1eb37a86f6194fa7062e0a6beb6983e912 Mon Sep 17 00:00:00 2001 From: Eugene Gostkin Date: Fri, 18 Nov 2022 12:50:53 +0100 Subject: [PATCH 3/4] Fix .lock --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 25ba0cd..da1446a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ # Rust target/ book/ -Cargo.lock # Mac files **/.DS_STore From 8ed11db7265c210f8a57f63764e81af49665e23e Mon Sep 17 00:00:00 2001 From: Sebastien Guillemot Date: Tue, 31 Jan 2023 13:05:16 +0900 Subject: [PATCH 4/4] rustfmt --- src/cli.rs | 4 +- src/comment_ast.rs | 118 +- src/dep_graph.rs | 111 +- src/generation.rs | 3327 ++++++++++++++++++++++++++++-------------- src/intermediate.rs | 912 ++++++++---- src/main.rs | 88 +- src/parsing.rs | 1525 +++++++++++++------ src/rust_reserved.rs | 4 +- src/test.rs | 101 +- src/utils.rs | 16 +- 10 files changed, 4224 insertions(+), 1982 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 2195de5..5b238fc 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,4 @@ -use clap::{Parser}; +use clap::Parser; use once_cell::sync::Lazy; // TODO: make non-annotation generate different DeserializeError that is simpler // and works with From only @@ -51,4 +51,4 @@ pub struct Cli { pub package_json: bool, } -pub static CLI_ARGS: Lazy = Lazy::new(|| Cli::parse()); \ No newline at end of file +pub static CLI_ARGS: Lazy = Lazy::new(|| Cli::parse()); diff --git a/src/comment_ast.rs b/src/comment_ast.rs index 3d40a9f..6227525 100644 --- a/src/comment_ast.rs +++ b/src/comment_ast.rs @@ -1,7 +1,9 @@ extern crate nom; use nom::{ + branch::alt, + bytes::complete::{tag, take_while, take_while1}, + multi::many0, IResult, - bytes::complete::{tag, take_while1, take_while}, branch::alt, multi::many0, }; #[derive(Default, Debug, PartialEq)] @@ -14,9 +16,11 @@ pub struct RuleMetadata { pub fn merge_metadata(r1: &RuleMetadata, r2: &RuleMetadata) -> RuleMetadata { let merged = RuleMetadata { name: match (r1.name.as_ref(), r2.name.as_ref()) { - (Some(val1), Some(val2)) => panic!("Key \"name\" specified twice: {:?} {:?}", val1, val2), - (val@Some(_), _) => val.cloned(), - (_, val) => val.cloned() + (Some(val1), Some(val2)) => { + panic!("Key \"name\" specified twice: {:?} {:?}", val1, val2) + } + (val @ Some(_), _) => val.cloned(), + (_, val) => val.cloned(), }, is_newtype: r1.is_newtype || r2.is_newtype, no_alias: r1.no_alias || r2.no_alias, @@ -36,14 +40,20 @@ impl RuleMetadata { let mut base = RuleMetadata::default(); for result in results { match result { - ParseResult::Name(name) => { - match base.name.as_ref() { - Some(old_name) => panic!("Key \"name\" specified twice: {:?} {:?}", old_name, name), - None => { base.name = Some(name.to_string()); } + ParseResult::Name(name) => match base.name.as_ref() { + Some(old_name) => { + panic!("Key \"name\" specified twice: {:?} {:?}", old_name, name) + } + None => { + base.name = Some(name.to_string()); } }, - ParseResult::NewType => { base.is_newtype = true; }, - ParseResult::DontGenAlias => { base.no_alias = true; }, + ParseResult::NewType => { + base.is_newtype = true; + } + ParseResult::DontGenAlias => { + base.no_alias = true; + } } } base.verify(); @@ -87,17 +97,15 @@ fn whitespace_then_tag(input: &str) -> IResult<&str, ParseResult> { fn rule_metadata(input: &str) -> IResult<&str, RuleMetadata> { let (input, parse_results) = many0(whitespace_then_tag)(input)?; - Ok((input, RuleMetadata::from_parse_results(&parse_results))) } - -impl <'a> From>> for RuleMetadata { +impl<'a> From>> for RuleMetadata { fn from(comments: Option<&'a cddl::ast::Comments<'a>>) -> RuleMetadata { match comments { None => RuleMetadata::default(), - Some(c) => metadata_from_comments(&c.0) + Some(c) => metadata_from_comments(&c.0), } } } @@ -108,53 +116,83 @@ pub fn metadata_from_comments(comments: &[&str]) -> RuleMetadata { if let Ok(comment_metadata) = rule_metadata(comment) { result = merge_metadata(&result, &comment_metadata.1); } - }; + } result } #[test] fn parse_comment_name() { - assert_eq!(rule_metadata("@name foo"), Ok(("", RuleMetadata { - name: Some("foo".to_string()), - is_newtype: false, - no_alias: false, - }))); + assert_eq!( + rule_metadata("@name foo"), + Ok(( + "", + RuleMetadata { + name: Some("foo".to_string()), + is_newtype: false, + no_alias: false, + } + )) + ); } #[test] fn parse_comment_newtype() { - assert_eq!(rule_metadata("@newtype"), Ok(("", RuleMetadata { - name: None, - is_newtype: true, - no_alias: false, - }))); + assert_eq!( + rule_metadata("@newtype"), + Ok(( + "", + RuleMetadata { + name: None, + is_newtype: true, + no_alias: false, + } + )) + ); } #[test] fn parse_comment_newtype_and_name() { - assert_eq!(rule_metadata("@newtype @name foo"), Ok(("", RuleMetadata { - name: Some("foo".to_string()), - is_newtype: true, - no_alias: false, - }))); + assert_eq!( + rule_metadata("@newtype @name foo"), + Ok(( + "", + RuleMetadata { + name: Some("foo".to_string()), + is_newtype: true, + no_alias: false, + } + )) + ); } #[test] fn parse_comment_newtype_and_name_inverse() { - assert_eq!(rule_metadata("@name foo @newtype"), Ok(("", RuleMetadata { - name: Some("foo".to_string()), - is_newtype: true, - no_alias: false, - }))); + assert_eq!( + rule_metadata("@name foo @newtype"), + Ok(( + "", + RuleMetadata { + name: Some("foo".to_string()), + is_newtype: true, + no_alias: false, + } + )) + ); } #[test] fn parse_comment_name_noalias() { - assert_eq!(rule_metadata("@no_alias @name foo"), Ok(("", RuleMetadata { - name: Some("foo".to_string()), - is_newtype: false, - no_alias: true, - }))); + assert_eq!( + rule_metadata("@no_alias @name foo"), + Ok(( + "", + RuleMetadata { + name: Some("foo".to_string()), + is_newtype: false, + no_alias: true, + } + )) + ); } #[test] diff --git a/src/dep_graph.rs b/src/dep_graph.rs index a977fcb..3c65b1d 100644 --- a/src/dep_graph.rs +++ b/src/dep_graph.rs @@ -8,11 +8,20 @@ pub fn topological_rule_order<'a>(rules: &'a Vec<&'a Rule<'a>>) -> Vec<&'a Rule< let (ident, refs) = find_references(cddl_rule); adj_list.insert(ident.ident, (*cddl_rule, refs)); } - let mut unvisited = adj_list.iter().map(|(k, _v)| *k).collect::>(); + let mut unvisited = adj_list + .iter() + .map(|(k, _v)| *k) + .collect::>(); let mut topo_order = Vec::new(); let mut processing: BTreeSet<&'a str> = BTreeSet::new(); while let Some(u) = unvisited.iter().next().map(|u| *u) { - dfs_visit(&mut topo_order, &mut unvisited, &mut processing, &adj_list, u); + dfs_visit( + &mut topo_order, + &mut unvisited, + &mut processing, + &adj_list, + u, + ); } topo_order } @@ -22,7 +31,8 @@ fn dfs_visit<'a>( unvisited: &mut BTreeSet<&'a str>, processing: &mut BTreeSet<&'a str>, adj_list: &BTreeMap<&'a str, (&'a cddl::ast::Rule<'a>, Vec<&'a Identifier<'a>>)>, - u: &'a str) { + u: &'a str, +) { processing.insert(u); let (rule, neighbors) = adj_list.get(u).unwrap(); for v in neighbors.iter() { @@ -42,41 +52,68 @@ fn dfs_visit<'a>( fn find_references<'a>(cddl_rule: &'a Rule<'a>) -> (&'a Identifier, Vec<&'a Identifier<'a>>) { let mut refs = Vec::new(); let ident = match cddl_rule { - Rule::Type{ rule, .. } => { - rule.value.type_choices.iter().for_each(|tc| find_refs_type1(&mut refs, &tc.type1)); + Rule::Type { rule, .. } => { + rule.value + .type_choices + .iter() + .for_each(|tc| find_refs_type1(&mut refs, &tc.type1)); &rule.name - }, - Rule::Group{ rule, .. } => { - assert_eq!(rule.generic_params, None, "{}: Generics not supported on plain groups", rule.name); + } + Rule::Group { rule, .. } => { + assert_eq!( + rule.generic_params, None, + "{}: Generics not supported on plain groups", + rule.name + ); match &rule.entry { - cddl::ast::GroupEntry::InlineGroup{ group, .. } => find_refs_group(&mut refs, group), + cddl::ast::GroupEntry::InlineGroup { group, .. } => { + find_refs_group(&mut refs, group) + } x => panic!("Group rule with non-inline group? {:?}", x), } &rule.name - }, + } }; (ident, refs) } fn find_refs_type1<'a>(refs: &mut Vec<&'a Identifier<'a>>, type1: &'a Type1<'a>) { match &type1.type2 { - Type2::Typename{ ident, generic_args, .. } => { + Type2::Typename { + ident, + generic_args, + .. + } => { refs.push(ident); find_refs_generic_args(refs, generic_args); - }, - Type2::ParenthesizedType{ pt, .. } => pt.type_choices.iter().for_each(|tc| find_refs_type1(refs, &tc.type1)), - Type2::Map{ group, .. } => find_refs_group(refs, group), - Type2::Array{ group, .. } => find_refs_group(refs, group), - Type2::Unwrap{ ident, generic_args, .. } => { + } + Type2::ParenthesizedType { pt, .. } => pt + .type_choices + .iter() + .for_each(|tc| find_refs_type1(refs, &tc.type1)), + Type2::Map { group, .. } => find_refs_group(refs, group), + Type2::Array { group, .. } => find_refs_group(refs, group), + Type2::Unwrap { + ident, + generic_args, + .. + } => { refs.push(ident); find_refs_generic_args(refs, generic_args); - }, - Type2::ChoiceFromInlineGroup{ group, .. } => find_refs_group(refs, group), - Type2::ChoiceFromGroup{ ident, generic_args, .. } => { + } + Type2::ChoiceFromInlineGroup { group, .. } => find_refs_group(refs, group), + Type2::ChoiceFromGroup { + ident, + generic_args, + .. + } => { refs.push(ident); find_refs_generic_args(refs, generic_args); - }, - Type2::TaggedData{ t, .. } => t.type_choices.iter().for_each(|tc| find_refs_type1(refs, &tc.type1)), + } + Type2::TaggedData { t, .. } => t + .type_choices + .iter() + .for_each(|tc| find_refs_type1(refs, &tc.type1)), _ => (), } } @@ -85,26 +122,36 @@ fn find_refs_group<'a>(refs: &mut Vec<&'a Identifier<'a>>, group: &'a Group<'a>) for group_choice in group.group_choices.iter() { for (group_entry, _) in group_choice.group_entries.iter() { match group_entry { - GroupEntry::InlineGroup{ group, .. } => find_refs_group(refs, group), - GroupEntry::TypeGroupname{ ge, .. } => { + GroupEntry::InlineGroup { group, .. } => find_refs_group(refs, group), + GroupEntry::TypeGroupname { ge, .. } => { refs.push(&ge.name); find_refs_generic_args(refs, &ge.generic_args); - }, - GroupEntry::ValueMemberKey{ ge, .. } => { - ge.entry_type.type_choices.iter().for_each(|tc| find_refs_type1(refs, &tc.type1)); + } + GroupEntry::ValueMemberKey { ge, .. } => { + ge.entry_type + .type_choices + .iter() + .for_each(|tc| find_refs_type1(refs, &tc.type1)); match &ge.member_key { - Some(MemberKey::Type1{ t1, .. }) => find_refs_type1(refs, t1), - Some(MemberKey::NonMemberKey{ .. }) => unimplemented!("Please open a github issue with repro steps"), + Some(MemberKey::Type1 { t1, .. }) => find_refs_type1(refs, t1), + Some(MemberKey::NonMemberKey { .. }) => { + unimplemented!("Please open a github issue with repro steps") + } _ => (), } - }, + } } } } } -fn find_refs_generic_args<'a>(refs: &mut Vec<&'a Identifier<'a>>, generic_arg: &'a Option>) { +fn find_refs_generic_args<'a>( + refs: &mut Vec<&'a Identifier<'a>>, + generic_arg: &'a Option>, +) { if let Some(arg) = generic_arg { - arg.args.iter().for_each(|arg| find_refs_type1(refs, arg.arg.as_ref())); + arg.args + .iter() + .for_each(|arg| find_refs_type1(refs, arg.arg.as_ref())); } -} \ No newline at end of file +} diff --git a/src/generation.rs b/src/generation.rs index ebd2421..3a7cbe2 100644 --- a/src/generation.rs +++ b/src/generation.rs @@ -1,34 +1,18 @@ -use codegen::{Block, TypeAlias}; use cbor_event::Type as CBORType; +use codegen::{Block, TypeAlias}; use std::borrow::Cow; use std::collections::{BTreeMap, BTreeSet}; -use std::process::{Command, Stdio}; use std::io::Write; +use std::process::{Command, Stdio}; use crate::cli::CLI_ARGS; use crate::intermediate::{ - AliasIdent, - CBOREncodingOperation, - CDDLIdent, - ConceptualRustType, - EnumVariant, - FixedValue, - IntermediateTypes, - Representation, - RustIdent, - RustType, - RustField, - RustRecord, - RustStructCBORLen, - RustStructType, - Primitive, - ToWasmBoundaryOperations, - VariantIdent, -}; -use crate::utils::{ - convert_to_snake_case, + AliasIdent, CBOREncodingOperation, CDDLIdent, ConceptualRustType, EnumVariant, FixedValue, + IntermediateTypes, Primitive, Representation, RustField, RustIdent, RustRecord, + RustStructCBORLen, RustStructType, RustType, ToWasmBoundaryOperations, VariantIdent, }; +use crate::utils::convert_to_snake_case; #[derive(Debug, Clone)] struct SerializeConfig<'a> { @@ -104,49 +88,62 @@ impl<'a> SerializeConfig<'a> { Some(c) => format!("_{}", c), None => "".to_owned(), }; - let clone_call = if is_copy { - "" - } else { - ".clone()" - }; + let clone_call = if is_copy { "" } else { ".clone()" }; match &self.encoding_var_in_option_struct { Some(namespace) => format!( "{}.as_ref().map(|encs| encs.{}{}_encoding{}).unwrap_or_default()", - namespace, - self.var_name, - child_suffix, - clone_call), + namespace, self.var_name, child_suffix, clone_call + ), None => format!("{}{}_encoding", self.var_name, child_suffix), } } /// for looking up encoding vars stored within a Vec / Map and declaring them as local variables - fn container_encoding_lookup(&self, prefix: &str, encoding_fields: &Vec, var: &str) -> String { + fn container_encoding_lookup( + &self, + prefix: &str, + encoding_fields: &Vec, + var: &str, + ) -> String { let encoding_lookup = match &self.encoding_var_in_option_struct { Some(namespace) => format!( "{}.as_ref().and_then(|encs| encs.{}_{}_encodings.get({})).cloned()", - namespace, - self.var_name, - prefix, - var), + namespace, self.var_name, prefix, var + ), None => format!( "{}_{}_encodings.get({}).cloned()", - self.var_name, - prefix, - var), + self.var_name, prefix, var + ), }; // for clippy::redundant_closure if encoding_fields.len() > 1 { format!( "let {} = {}.unwrap_or_else(|| {});", - tuple_str(encoding_fields.iter().map(|enc| enc.field_name.clone()).collect()), + tuple_str( + encoding_fields + .iter() + .map(|enc| enc.field_name.clone()) + .collect() + ), encoding_lookup, - tuple_str(encoding_fields.iter().map(|enc| enc.default_expr.to_owned()).collect())) + tuple_str( + encoding_fields + .iter() + .map(|enc| enc.default_expr.to_owned()) + .collect() + ) + ) } else { format!( "let {} = {}.unwrap_or_default();", - tuple_str(encoding_fields.iter().map(|enc| enc.field_name.clone()).collect()), - encoding_lookup) + tuple_str( + encoding_fields + .iter() + .map(|enc| enc.field_name.clone()) + .collect() + ), + encoding_lookup + ) } } } @@ -155,7 +152,7 @@ impl<'a> SerializeConfig<'a> { struct DeserializeConfig<'a> { /// for creating unique identifiers for temporaries var_name: &'a str, - /// whether we're generating inside of a DeserializeEmbeddedGroup impl + /// whether we're generating inside of a DeserializeEmbeddedGroup impl in_embedded: bool, /// whether this is an optional field optional_field: bool, @@ -221,7 +218,11 @@ impl<'a> DeserializeConfig<'a> { fn concat_files(paths: Vec<&str>) -> std::io::Result { let mut buf = String::new(); for path in paths { - buf.push_str(&std::fs::read_to_string(path).map_err(|_| panic!("can't read: {}", path)).unwrap()); + buf.push_str( + &std::fs::read_to_string(path) + .map_err(|_| panic!("can't read: {}", path)) + .unwrap(), + ); } Ok(buf) } @@ -249,11 +250,7 @@ impl EncodingVarIsCopy for FixedValue { fn encoding_var_is_copy(&self) -> bool { match self { // bool / null have no encoding var - Self::Bool(_) | - Self::Nint(_) | - Self::Null | - Self::Float(_) | - Self::Uint(_) => true, + Self::Bool(_) | Self::Nint(_) | Self::Null | Self::Float(_) | Self::Uint(_) => true, Self::Text(_) => false, } } @@ -269,20 +266,19 @@ impl EncodingVarIsCopy for ConceptualRustType { Self::Optional(ty) => SerializingRustType::from(&**ty).encoding_var_is_copy(), Self::Primitive(p) => match p { // bool has no encoding var - Primitive::Bool | - Primitive::F64 | - Primitive::F32 | - Primitive::I8 | - Primitive::I16 | - Primitive::I32 | - Primitive::I64 | - Primitive::U8 | - Primitive::U16 | - Primitive::U32 | - Primitive::U64 | - Primitive::N64 => true, - Primitive::Bytes | - Primitive::Str => false, + Primitive::Bool + | Primitive::F64 + | Primitive::F32 + | Primitive::I8 + | Primitive::I16 + | Primitive::I32 + | Primitive::I64 + | Primitive::U8 + | Primitive::U16 + | Primitive::U32 + | Primitive::U64 + | Primitive::N64 => true, + Primitive::Bytes | Primitive::Str => false, }, // technically no encoding var Self::Rust(_) => true, @@ -291,7 +287,7 @@ impl EncodingVarIsCopy for ConceptualRustType { } } -impl <'a> std::convert::From<&'a RustType> for SerializingRustType<'a> { +impl<'a> std::convert::From<&'a RustType> for SerializingRustType<'a> { fn from(rust_type: &'a RustType) -> Self { let mut root = Self::Root(&rust_type.conceptual_type); for cbor_encoding_op in rust_type.encodings.iter() { @@ -301,7 +297,7 @@ impl <'a> std::convert::From<&'a RustType> for SerializingRustType<'a> { } } -impl <'a> std::convert::From<&'a ConceptualRustType> for SerializingRustType<'a> { +impl<'a> std::convert::From<&'a ConceptualRustType> for SerializingRustType<'a> { fn from(conceptual_rust_type: &'a ConceptualRustType) -> Self { Self::Root(conceptual_rust_type) } @@ -317,7 +313,10 @@ struct DeserializationCode { } impl DeserializationCode { - fn add_to(self, body: &mut T) where T: CodeBlock + Sized { + fn add_to(self, body: &mut T) + where + T: CodeBlock + Sized, + { body.push_all(self.content); } @@ -343,14 +342,10 @@ impl DeserializationCode { /// the block to avoid clippy warnings. fn annotate(mut self, annotation: &str, before: &str, after: &str) -> Self { if let Some(single_line) = self.content.as_single_line() { - self.content = BlocksOrLines(vec![ - BlockOrLine::Line(format!( - "{}{}.map_err(|e: DeserializeError| e.annotate(\"{}\")){}", - before, - single_line, - annotation, - after)) - ]); + self.content = BlocksOrLines(vec![BlockOrLine::Line(format!( + "{}{}.map_err(|e: DeserializeError| e.annotate(\"{}\")){}", + before, single_line, annotation, after + ))]); self } else { self.throws = false; @@ -406,11 +401,10 @@ impl<'a> DeserializeBeforeAfter<'a> { match (self.expects_result, is_result) { // Result -> T (false, true) => format!("?{}", self.after), - // T -> + // T -> (true, false) => format!("){}", self.before), // expected == found, nothing to be done - (false, false) | - (true, true) => self.after.to_owned(), + (false, false) | (true, true) => self.after.to_owned(), } } } @@ -455,18 +449,17 @@ impl GenerationScope { // does not work. if CLI_ARGS.preserve_encodings && CLI_ARGS.canonical_form { self.rust_lib() - .push_import("cbor_event", "self", None) - .push_import("cbor_event::de", "Deserializer", None) - .push_import("cbor_event::se", "Serializer", None); + .push_import("cbor_event", "self", None) + .push_import("cbor_event::de", "Deserializer", None) + .push_import("cbor_event::se", "Serializer", None); } else { self.rust_lib() - .push_import("cbor_event", "self", None) - .push_import("cbor_event::de", "Deserializer", None) - .push_import("cbor_event::se", "Serialize", None) - .push_import("cbor_event::se", "Serializer", None); + .push_import("cbor_event", "self", None) + .push_import("cbor_event::de", "Deserializer", None) + .push_import("cbor_event::se", "Serialize", None) + .push_import("cbor_event::se", "Serializer", None); } - self - .rust_lib() + self.rust_lib() .push_import("std::io", "BufRead", None) .push_import("std::io", "Write", None) .push_import("std::io", "Write", None) @@ -480,8 +473,7 @@ impl GenerationScope { .raw("pub mod prelude;") .raw("pub mod serialization;"); if CLI_ARGS.preserve_encodings { - self - .rust_lib() + self.rust_lib() .raw("pub mod ordered_hash_map;") .push_import("ordered_hash_map", "OrderedHashMap", None) .push_import("cbor_event", "Sz", None) @@ -489,13 +481,12 @@ impl GenerationScope { .push_import("cbor_encodings", "*", None) .push_import("derivative", "Derivative", None) .raw("extern crate derivative;"); - self - .cbor_encodings() - .push_import("super", "*", None); + self.cbor_encodings().push_import("super", "*", None); } self.rust_serialize().push_import("super", "*", None); self.rust_serialize().push_import("std::io", "Seek", None); - self.rust_serialize().push_import("std::io", "SeekFrom", None); + self.rust_serialize() + .push_import("std::io", "SeekFrom", None); // Wasm (populate wasm_lib() - used for top of file before structs) if CLI_ARGS.wasm { @@ -505,9 +496,11 @@ impl GenerationScope { .push_import("wasm_bindgen::prelude", "wasm_bindgen", None) .push_import("wasm_bindgen::prelude", "JsValue", None); if CLI_ARGS.preserve_encodings { - self.wasm_lib().push_import("core::ordered_hash_map", "OrderedHashMap", None); + self.wasm_lib() + .push_import("core::ordered_hash_map", "OrderedHashMap", None); } else { - self.wasm_lib().push_import("std::collections", "BTreeMap", None); + self.wasm_lib() + .push_import("std::collections", "BTreeMap", None); } } @@ -517,9 +510,11 @@ impl GenerationScope { if let AliasIdent::Rust(ident) = alias { // also make sure not to generate it if we instead generated a binary wrapper type if *gen_rust_alias { - self - .rust_lib() - .push_type_alias(TypeAlias::new(ident, base_type.for_rust_member(false)).vis("pub").clone()); + self.rust_lib().push_type_alias( + TypeAlias::new(ident, base_type.for_rust_member(false)) + .vis("pub") + .clone(), + ); } if *gen_wasm_alias { if let ConceptualRustType::Fixed(constant) = &base_type.conceptual_type { @@ -532,17 +527,18 @@ impl GenerationScope { FixedValue::Float(f) => ("f64", f.to_string()), FixedValue::Text(s) => ("String", format!("\"{}\".to_owned()", s)), }; - self - .wasm(types, ident) + self.wasm(types, ident) .new_fn(&convert_to_snake_case(&ident.to_string())) .attr("wasm_bindgen") .vis("pub") .ret(ty) .line(val); } else { - self - .wasm(types, ident) - .push_type_alias(TypeAlias::new(ident, base_type.for_wasm_member()).vis("pub").clone()); + self.wasm(types, ident).push_type_alias( + TypeAlias::new(ident, base_type.for_wasm_member()) + .vis("pub") + .clone(), + ); } } } @@ -552,48 +548,73 @@ impl GenerationScope { { // we can ignore types already handled by the alias // otherwise wasm_wrappers_generated may cause us to pointlessly create aliases to aliases - let mut existing_aliases = types.type_aliases().iter().fold(BTreeSet::::new(), |mut acc, (alias, _)| { - match alias { - AliasIdent::Reserved(_) => {}, - AliasIdent::Rust(ident) => { acc.insert(ident.clone()); } - }; - acc - }); + let mut existing_aliases = types.type_aliases().iter().fold( + BTreeSet::::new(), + |mut acc, (alias, _)| { + match alias { + AliasIdent::Reserved(_) => {} + AliasIdent::Rust(ident) => { + acc.insert(ident.clone()); + } + }; + acc + }, + ); let mut wasm_wrappers_generated = BTreeSet::new(); for (rust_ident, rust_struct) in types.rust_structs() { assert_eq!(rust_ident, rust_struct.ident()); if CLI_ARGS.wasm { - rust_struct.visit_types_excluding(types, &mut |ty| { - match ty { + rust_struct.visit_types_excluding( + types, + &mut |ty| match ty { ConceptualRustType::Array(elem) => { if !ty.directly_wasm_exposable() { let array_ident = elem.name_as_wasm_array(); if wasm_wrappers_generated.insert(array_ident.clone()) { - self.generate_array_type(types, *elem.clone(), &RustIdent::new(CDDLIdent::new(array_ident))); + self.generate_array_type( + types, + *elem.clone(), + &RustIdent::new(CDDLIdent::new(array_ident)), + ); } } - }, + } ConceptualRustType::Map(k, v) => { let map_ident = ConceptualRustType::name_for_wasm_map(&k, &v); if wasm_wrappers_generated.insert(map_ident.to_string()) { - codegen_table_type(self, types, &map_ident, *k.clone(), *v.clone(), None, false); + codegen_table_type( + self, + types, + &map_ident, + *k.clone(), + *v.clone(), + None, + false, + ); } - if !ConceptualRustType::Array(Box::new(*k.clone())).directly_wasm_exposable() { + if !ConceptualRustType::Array(Box::new(*k.clone())) + .directly_wasm_exposable() + { let keys_ident = k.name_as_wasm_array(); if wasm_wrappers_generated.insert(keys_ident.clone()) { - self.generate_array_type(types, *k.clone(), &RustIdent::new(CDDLIdent::new(keys_ident))); + self.generate_array_type( + types, + *k.clone(), + &RustIdent::new(CDDLIdent::new(keys_ident)), + ); } } - }, + } _ => (), - } - }, &mut existing_aliases); + }, + &mut existing_aliases, + ); } match rust_struct.variant() { RustStructType::Record(record) => { codegen_struct(self, types, rust_ident, rust_struct.tag(), record); - }, + } RustStructType::Table { domain, range } => { if CLI_ARGS.wasm { let map_ident = ConceptualRustType::name_for_wasm_map(domain, range); @@ -601,15 +622,24 @@ impl GenerationScope { // since although map_ident may not be required for this struct // we may still have to generate it later if a table of the same shape is embedded inside different struct if !wasm_wrappers_generated.contains(&map_ident.to_string()) { - codegen_table_type(self, types, rust_ident, domain.clone(), range.clone(), rust_struct.tag(), true); + codegen_table_type( + self, + types, + rust_ident, + domain.clone(), + range.clone(), + rust_struct.tag(), + true, + ); } else { - self.wasm(types, rust_ident).push_type_alias(TypeAlias::new(rust_ident, map_ident)); + self.wasm(types, rust_ident) + .push_type_alias(TypeAlias::new(rust_ident, map_ident)); } } //self // .rust() // .push_type_alias(TypeAlias::new(rust_struct.ident(), ConceptualRustType::name_for_rust_map(domain, range, false))); - }, + } RustStructType::Array { element_type } => { if CLI_ARGS.wasm { self.generate_array_type(types, element_type.clone(), rust_ident); @@ -617,27 +647,49 @@ impl GenerationScope { //self // .rust() // .push_type_alias(TypeAlias::new(rust_struct.ident(), element_type.name_as_rust_array(false))); - }, + } RustStructType::TypeChoice { variants } => { - self.generate_type_choices_from_variants(types, rust_ident, variants, rust_struct.tag()); - }, - RustStructType::GroupChoice { variants, rep } => { - codegen_group_choices(self, types, rust_ident, variants, *rep, rust_struct.tag()) - }, - RustStructType::Wrapper{ wrapped, min_max } => { - match rust_struct.tag() { - Some(tag) => generate_wrapper_struct(self, types, rust_ident, &wrapped.clone().tag(tag), min_max.clone()), - None => generate_wrapper_struct(self, types, rust_ident, wrapped, min_max.clone()), - } + self.generate_type_choices_from_variants( + types, + rust_ident, + variants, + rust_struct.tag(), + ); + } + RustStructType::GroupChoice { variants, rep } => codegen_group_choices( + self, + types, + rust_ident, + variants, + *rep, + rust_struct.tag(), + ), + RustStructType::Wrapper { wrapped, min_max } => match rust_struct.tag() { + Some(tag) => generate_wrapper_struct( + self, + types, + rust_ident, + &wrapped.clone().tag(tag), + min_max.clone(), + ), + None => generate_wrapper_struct( + self, + types, + rust_ident, + wrapped, + min_max.clone(), + ), }, RustStructType::Extern => { match rust_ident.to_string().as_ref() { - "Int" => if types.is_referenced(rust_ident) { - generate_int(self, types) - }, - _ => ()/* user-specified external types */, + "Int" => { + if types.is_referenced(rust_ident) { + generate_int(self, types) + } + } + _ => (), /* user-specified external types */ } - }, + } } } } @@ -659,8 +711,8 @@ impl GenerationScope { main.push_block(path_exists); for (rust_ident, rust_struct) in types.rust_structs() { let is_typedef = match rust_struct.variant() { - RustStructType::Array{ .. } => true, - RustStructType::Table{ .. } => true, + RustStructType::Array { .. } => true, + RustStructType::Table { .. } => true, _ => false, }; if !is_typedef { @@ -678,9 +730,18 @@ impl GenerationScope { let rust_dir = if CLI_ARGS.package_json { if CLI_ARGS.json_schema_export { std::fs::create_dir_all(CLI_ARGS.output.join("scripts"))?; - std::fs::copy("static/run-json2ts.js", CLI_ARGS.output.join("scripts/run-json2ts.js"))?; - std::fs::copy("static/json-ts-types.js", CLI_ARGS.output.join("scripts/json-ts-types.js"))?; - std::fs::copy("static/package_json_schemas.json", CLI_ARGS.output.join("package.json"))?; + std::fs::copy( + "static/run-json2ts.js", + CLI_ARGS.output.join("scripts/run-json2ts.js"), + )?; + std::fs::copy( + "static/json-ts-types.js", + CLI_ARGS.output.join("scripts/json-ts-types.js"), + )?; + std::fs::copy( + "static/package_json_schemas.json", + CLI_ARGS.output.join("package.json"), + )?; } else { std::fs::copy("static/package.json", CLI_ARGS.output.join("package.json"))?; } @@ -698,8 +759,7 @@ impl GenerationScope { .map(|scope| scope.clone()) .collect::>(); for scope in scope_names { - self - .rust_lib() + self.rust_lib() .raw(&format!("pub mod {};", scope)) .push_import(scope, "*", None); } @@ -710,10 +770,16 @@ impl GenerationScope { merged_rust_scope.append(&content.clone()); } else { content.push_import("super", "*", None); - std::fs::write(rust_dir.join(format!("core/src/{}.rs", scope)), rustfmt_generated_string(&content.to_string())?.as_ref())?; + std::fs::write( + rust_dir.join(format!("core/src/{}.rs", scope)), + rustfmt_generated_string(&content.to_string())?.as_ref(), + )?; } } - std::fs::write(rust_dir.join("core/src/lib.rs"), rustfmt_generated_string(&merged_rust_scope.to_string())?.as_ref())?; + std::fs::write( + rust_dir.join("core/src/lib.rs"), + rustfmt_generated_string(&merged_rust_scope.to_string())?.as_ref(), + )?; // serialiation.rs let mut serialize_paths = vec!["static/serialization.rs"]; @@ -731,7 +797,10 @@ impl GenerationScope { } let mut serialize_contents = concat_files(serialize_paths)?; serialize_contents.push_str(&self.rust_serialize().to_string()); - std::fs::write(rust_dir.join("core/src/serialization.rs"), rustfmt_generated_string(&serialize_contents)?.as_ref())?; + std::fs::write( + rust_dir.join("core/src/serialization.rs"), + rustfmt_generated_string(&serialize_contents)?.as_ref(), + )?; // Cargo.toml let mut rust_cargo_toml = std::fs::read_to_string("static/Cargo_rust.toml")?; @@ -753,15 +822,24 @@ impl GenerationScope { // cbor_encodings.rs + ordered_hash_map.rs if CLI_ARGS.preserve_encodings { - std::fs::write(rust_dir.join("core/src/cbor_encodings.rs"), rustfmt_generated_string(&self.cbor_encodings().to_string())?.as_ref())?; + std::fs::write( + rust_dir.join("core/src/cbor_encodings.rs"), + rustfmt_generated_string(&self.cbor_encodings().to_string())?.as_ref(), + )?; let mut ordered_hash_map_rs = std::fs::read_to_string("static/ordered_hash_map.rs")?; if CLI_ARGS.json_serde_derives { - ordered_hash_map_rs.push_str(&std::fs::read_to_string("static/ordered_hash_map_json.rs")?); + ordered_hash_map_rs + .push_str(&std::fs::read_to_string("static/ordered_hash_map_json.rs")?); } if CLI_ARGS.json_schema_export { - ordered_hash_map_rs.push_str(&std::fs::read_to_string("static/ordered_hash_map_schemars.rs")?); + ordered_hash_map_rs.push_str(&std::fs::read_to_string( + "static/ordered_hash_map_schemars.rs", + )?); } - std::fs::write(rust_dir.join("core/src/ordered_hash_map.rs"), rustfmt_generated_string(&ordered_hash_map_rs)?.as_ref())?; + std::fs::write( + rust_dir.join("core/src/ordered_hash_map.rs"), + rustfmt_generated_string(&ordered_hash_map_rs)?.as_ref(), + )?; } // wasm crate @@ -774,8 +852,7 @@ impl GenerationScope { .map(|scope| scope.clone()) .collect::>(); for scope in scope_names { - self - .wasm_lib() + self.wasm_lib() .raw(&format!("pub mod {};", scope)) .push_import(&scope, "*", None); } @@ -786,10 +863,16 @@ impl GenerationScope { merged_wasm_scope.append(&content.clone()); } else { content.push_import("super", "*", None); - std::fs::write(rust_dir.join(format!("wasm/src/{}.rs", scope)), rustfmt_generated_string(&content.to_string())?.as_ref())?; + std::fs::write( + rust_dir.join(format!("wasm/src/{}.rs", scope)), + rustfmt_generated_string(&content.to_string())?.as_ref(), + )?; } } - std::fs::write(rust_dir.join("wasm/src/lib.rs"), rustfmt_generated_string(&merged_wasm_scope.to_string())?.as_ref())?; + std::fs::write( + rust_dir.join("wasm/src/lib.rs"), + rustfmt_generated_string(&merged_wasm_scope.to_string())?.as_ref(), + )?; let mut wasm_toml = std::fs::read_to_string("static/Cargo_wasm.toml")?; if CLI_ARGS.json_serde_derives { wasm_toml.push_str("serde_json = \"1.0.57\"\n"); @@ -801,8 +884,14 @@ impl GenerationScope { // json-gen crate for exporting JSON schemas if CLI_ARGS.json_schema_export { std::fs::create_dir_all(rust_dir.join("json-gen/src"))?; - std::fs::copy("static/Cargo_json_gen.toml", rust_dir.join("json-gen/Cargo.toml"))?; - std::fs::write(rust_dir.join("json-gen/src/main.rs"), rustfmt_generated_string(&self.json().to_string())?.as_ref())?; + std::fs::copy( + "static/Cargo_json_gen.toml", + rust_dir.join("json-gen/Cargo.toml"), + )?; + std::fs::write( + rust_dir.join("json-gen/src/main.rs"), + rustfmt_generated_string(&self.json().to_string())?.as_ref(), + )?; } Ok(()) @@ -812,7 +901,9 @@ impl GenerationScope { /// Used for all the generated structs and associated traits (besides serialization ones) pub fn rust(&mut self, types: &IntermediateTypes, ident: &RustIdent) -> &mut codegen::Scope { let scope_name = types.scope(ident).to_owned(); - self.rust_scopes.entry(scope_name).or_insert(codegen::Scope::new()) + self.rust_scopes + .entry(scope_name) + .or_insert(codegen::Scope::new()) } /// Scope header above the rest of the "lib" rust scope. @@ -832,7 +923,9 @@ impl GenerationScope { /// Used for all the generated WASM wrapper structs and associated traits pub fn wasm(&mut self, types: &IntermediateTypes, ident: &RustIdent) -> &mut codegen::Scope { let scope_name = types.scope(ident).to_owned(); - self.wasm_scopes.entry(scope_name).or_insert(codegen::Scope::new()) + self.wasm_scopes + .entry(scope_name) + .or_insert(codegen::Scope::new()) } /// Scope header above the rest of the "lib" WASM scope. @@ -853,13 +946,15 @@ impl GenerationScope { } /// Write code for serializing {serializing_rust_type} directly into {body} - fn generate_serialize<'a>(&mut self, types: &IntermediateTypes, serializing_rust_type: SerializingRustType<'a>, body: &mut dyn CodeBlock, config: SerializeConfig) { + fn generate_serialize<'a>( + &mut self, + types: &IntermediateTypes, + serializing_rust_type: SerializingRustType<'a>, + body: &mut dyn CodeBlock, + config: SerializeConfig, + ) { //body.line(&format!("// DEBUG - generated from: {:?}", rust_type)); - let line_ender = if config.is_end { - "" - } else { - "?;" - }; + let line_ender = if config.is_end { "" } else { "?;" }; let expr_deref = if config.expr_is_ref { format!("*{}", config.expr) } else { @@ -870,23 +965,38 @@ impl GenerationScope { } else { format!("&{}", config.expr) }; - let (serializer_use, serializer_pass) = config.serializer_name_overload - .map(|(name, is_local)| if is_local { (name, format!("&mut {}", name)) } else { (name, name.to_owned()) }) + let (serializer_use, serializer_pass) = config + .serializer_name_overload + .map(|(name, is_local)| { + if is_local { + (name, format!("&mut {}", name)) + } else { + (name, name.to_owned()) + } + }) .unwrap_or(("serializer", "serializer".to_owned())); - let encoding_deref = if config.encoding_var_is_ref { - "*" - } else { - "" - }; + let encoding_deref = if config.encoding_var_is_ref { "*" } else { "" }; let encoding_var_is_copy = serializing_rust_type.encoding_var_is_copy(); let encoding_var = config.encoding_var(None, encoding_var_is_copy); let encoding_var_deref = format!("{}{}", encoding_deref, encoding_var); match serializing_rust_type { SerializingRustType::EncodingOperation(CBOREncodingOperation::Tagged(tag), child) => { let expr = format!("{}u64", tag); - write_using_sz(body, "write_tag", serializer_use, &expr, &expr, "?;", &format!("{}{}", encoding_deref, config.encoding_var(Some("tag"), encoding_var_is_copy))); + write_using_sz( + body, + "write_tag", + serializer_use, + &expr, + &expr, + "?;", + &format!( + "{}{}", + encoding_deref, + config.encoding_var(Some("tag"), encoding_var_is_copy) + ), + ); self.generate_serialize(types, *child, body, config); - }, + } SerializingRustType::EncodingOperation(CBOREncodingOperation::CBORBytes, child) => { let inner_se = format!("{}_inner_se", config.var_name); body.line(&format!("let mut {} = Serializer::new_vec();", inner_se)); @@ -895,23 +1005,50 @@ impl GenerationScope { .is_end(false) .serializer_name_overload((&inner_se, true)); self.generate_serialize(types, *child, body, inner_config); - body.line(&format!("let {}_bytes = {}.finalize();", config.var_name, inner_se)); - write_string_sz(body, "write_bytes", serializer_use, &format!("{}_bytes", config.var_name), line_ender, &config.encoding_var(Some("bytes"), encoding_var_is_copy)); - }, + body.line(&format!( + "let {}_bytes = {}.finalize();", + config.var_name, inner_se + )); + write_string_sz( + body, + "write_bytes", + serializer_use, + &format!("{}_bytes", config.var_name), + line_ender, + &config.encoding_var(Some("bytes"), encoding_var_is_copy), + ); + } SerializingRustType::Root(ConceptualRustType::Fixed(value)) => match value { FixedValue::Null => { - body.line(&format!("{}.write_special(CBORSpecial::Null){}", serializer_use, line_ender)); - }, + body.line(&format!( + "{}.write_special(CBORSpecial::Null){}", + serializer_use, line_ender + )); + } FixedValue::Bool(b) => { - body.line(&format!("{}.write_special(CBORSpecial::Bool({})){}", serializer_use, b, line_ender)); - }, + body.line(&format!( + "{}.write_special(CBORSpecial::Bool({})){}", + serializer_use, b, line_ender + )); + } FixedValue::Uint(u) => { let expr = format!("{}u64", u); - write_using_sz(body, "write_unsigned_integer", serializer_use, &expr, &expr, line_ender, &encoding_var_deref); - }, + write_using_sz( + body, + "write_unsigned_integer", + serializer_use, + &expr, + &expr, + line_ender, + &encoding_var_deref, + ); + } FixedValue::Nint(i) => { assert!(*i < 0); - if !CLI_ARGS.preserve_encodings && isize::BITS >= i64::BITS && *i <= i64::MIN as isize { + if !CLI_ARGS.preserve_encodings + && isize::BITS >= i64::BITS + && *i <= i64::MIN as isize + { // cbor_event's write_negative_integer doesn't support serializing i64::MIN (https://github.com/primetype/cbor_event/issues/9) // we need to use the write_negative_integer_sz endpoint which does support it. // the bits check is since the constant parsed by cddl might not even be able to @@ -927,104 +1064,206 @@ impl GenerationScope { } else { "cbor_event::Sz::Eight" }; - body.line(&format!("{}.write_negative_integer_sz({}i128, {}){}", serializer_use, i, sz_str, line_ender)); + body.line(&format!( + "{}.write_negative_integer_sz({}i128, {}){}", + serializer_use, i, sz_str, line_ender + )); } else { - write_using_sz(body, "write_negative_integer", serializer_use, &i.to_string(), &format!("({}i128 + 1).abs() as u64", i), line_ender, &encoding_var_deref); + write_using_sz( + body, + "write_negative_integer", + serializer_use, + &i.to_string(), + &format!("({}i128 + 1).abs() as u64", i), + line_ender, + &encoding_var_deref, + ); } - }, + } FixedValue::Float(f) => { - body.line(&format!("{}.write_special(CBORSpecial::Float({})){}", serializer_use, f, line_ender)); + body.line(&format!( + "{}.write_special(CBORSpecial::Float({})){}", + serializer_use, f, line_ender + )); } FixedValue::Text(s) => { - write_string_sz(body, "write_text", serializer_use, &format!("\"{}\"", s), line_ender, &encoding_var); - }, + write_string_sz( + body, + "write_text", + serializer_use, + &format!("\"{}\"", s), + line_ender, + &encoding_var, + ); + } }, - SerializingRustType::Root(ConceptualRustType::Primitive(primitive)) => match primitive { - Primitive::Bool => { - body.line(&format!("{}.write_special(cbor_event::Special::Bool({})){}", serializer_use, expr_deref, line_ender)); - }, - Primitive::F32 => { - body.line(&format!("{}.write_special(cbor_event::Special::Float({} as f64)){}", serializer_use, expr_deref, line_ender)); - }, - Primitive::F64 => { - body.line(&format!("{}.write_special(cbor_event::Special::Float({})){}", serializer_use, expr_deref, line_ender)); - }, - Primitive::Bytes => { - write_string_sz(body, "write_bytes", serializer_use, &config.expr, line_ender, &encoding_var); - }, - Primitive::Str => { - write_string_sz(body, "write_text", serializer_use, &config.expr, line_ender, &encoding_var); - }, - Primitive::I8 | - Primitive::I16 | - Primitive::I32 | - Primitive::I64 => { - let mut pos = Block::new(&format!("if {} >= 0", expr_deref)); - let expr_pos = format!("{} as u64", expr_deref); - write_using_sz(&mut pos, "write_unsigned_integer", serializer_use, &expr_pos, &expr_pos, line_ender, &encoding_var_deref); - body.push_block(pos); - let mut neg = Block::new("else"); - // only the _sz variants support i128, the other endpoint is i64 - let expr = if CLI_ARGS.preserve_encodings { - format!("{} as i128", expr_deref) - } else { - format!("{} as i64", expr_deref) - }; - if !CLI_ARGS.preserve_encodings && *primitive == Primitive::I64 { - // https://github.com/primetype/cbor_event/issues/9 - // cbor_event doesn't support i64::MIN on write_negative_integer() so we use write_negative_integer_sz() for i64s - // even when not preserving encodings - neg.line(&format!("{}.write_negative_integer_sz({} as i128, cbor_event::Sz::canonical(({} + 1).abs() as u64)){}", serializer_use, expr_deref, expr_deref, line_ender)); - } else { - write_using_sz(&mut neg, "write_negative_integer", serializer_use, &expr, &format!("({} + 1).abs() as u64", expr_deref), line_ender, &encoding_var_deref); + SerializingRustType::Root(ConceptualRustType::Primitive(primitive)) => { + match primitive { + Primitive::Bool => { + body.line(&format!( + "{}.write_special(cbor_event::Special::Bool({})){}", + serializer_use, expr_deref, line_ender + )); } - body.push_block(neg); - }, - Primitive::U8 | - Primitive::U16 | - Primitive::U32 => { - let expr = format!("{} as u64", expr_deref); - write_using_sz(body, "write_unsigned_integer", serializer_use, &expr, &expr, line_ender, &encoding_var_deref); - }, - Primitive::U64 => { - write_using_sz(body, "write_unsigned_integer", serializer_use, &expr_deref, &expr_deref, line_ender, &encoding_var_deref); - }, - Primitive::N64 => { - if CLI_ARGS.preserve_encodings { - write_using_sz(body, "write_negative_integer", serializer_use, &format!("-({} as i128 + 1)", expr_deref), &expr_deref, line_ender, &encoding_var_deref); - } else { - // https://github.com/primetype/cbor_event/issues/9 - // cbor_event doesn't support i64::MIN on write_negative_integer() so we use write_negative_integer_sz() - // even when not preserving encodings - body.line(&format!("{}.write_negative_integer_sz(-({} as i128 + 1), cbor_event::Sz::canonical({})){}", serializer_use, expr_deref, expr_deref, line_ender)); + Primitive::F32 => { + body.line(&format!( + "{}.write_special(cbor_event::Special::Float({} as f64)){}", + serializer_use, expr_deref, line_ender + )); } - }, - }, + Primitive::F64 => { + body.line(&format!( + "{}.write_special(cbor_event::Special::Float({})){}", + serializer_use, expr_deref, line_ender + )); + } + Primitive::Bytes => { + write_string_sz( + body, + "write_bytes", + serializer_use, + &config.expr, + line_ender, + &encoding_var, + ); + } + Primitive::Str => { + write_string_sz( + body, + "write_text", + serializer_use, + &config.expr, + line_ender, + &encoding_var, + ); + } + Primitive::I8 | Primitive::I16 | Primitive::I32 | Primitive::I64 => { + let mut pos = Block::new(&format!("if {} >= 0", expr_deref)); + let expr_pos = format!("{} as u64", expr_deref); + write_using_sz( + &mut pos, + "write_unsigned_integer", + serializer_use, + &expr_pos, + &expr_pos, + line_ender, + &encoding_var_deref, + ); + body.push_block(pos); + let mut neg = Block::new("else"); + // only the _sz variants support i128, the other endpoint is i64 + let expr = if CLI_ARGS.preserve_encodings { + format!("{} as i128", expr_deref) + } else { + format!("{} as i64", expr_deref) + }; + if !CLI_ARGS.preserve_encodings && *primitive == Primitive::I64 { + // https://github.com/primetype/cbor_event/issues/9 + // cbor_event doesn't support i64::MIN on write_negative_integer() so we use write_negative_integer_sz() for i64s + // even when not preserving encodings + neg.line(&format!("{}.write_negative_integer_sz({} as i128, cbor_event::Sz::canonical(({} + 1).abs() as u64)){}", serializer_use, expr_deref, expr_deref, line_ender)); + } else { + write_using_sz( + &mut neg, + "write_negative_integer", + serializer_use, + &expr, + &format!("({} + 1).abs() as u64", expr_deref), + line_ender, + &encoding_var_deref, + ); + } + body.push_block(neg); + } + Primitive::U8 | Primitive::U16 | Primitive::U32 => { + let expr = format!("{} as u64", expr_deref); + write_using_sz( + body, + "write_unsigned_integer", + serializer_use, + &expr, + &expr, + line_ender, + &encoding_var_deref, + ); + } + Primitive::U64 => { + write_using_sz( + body, + "write_unsigned_integer", + serializer_use, + &expr_deref, + &expr_deref, + line_ender, + &encoding_var_deref, + ); + } + Primitive::N64 => { + if CLI_ARGS.preserve_encodings { + write_using_sz( + body, + "write_negative_integer", + serializer_use, + &format!("-({} as i128 + 1)", expr_deref), + &expr_deref, + line_ender, + &encoding_var_deref, + ); + } else { + // https://github.com/primetype/cbor_event/issues/9 + // cbor_event doesn't support i64::MIN on write_negative_integer() so we use write_negative_integer_sz() + // even when not preserving encodings + body.line(&format!("{}.write_negative_integer_sz(-({} as i128 + 1), cbor_event::Sz::canonical({})){}", serializer_use, expr_deref, expr_deref, line_ender)); + } + } + } + } SerializingRustType::Root(ConceptualRustType::Rust(t)) => { if types.is_plain_group(t) { - body.line(&format!("{}.serialize_as_embedded_group({}{}){}", config.expr, serializer_pass, canonical_param(), line_ender)); + body.line(&format!( + "{}.serialize_as_embedded_group({}{}){}", + config.expr, + serializer_pass, + canonical_param(), + line_ender + )); } else { - body.line(&format!("{}.serialize({}{}){}", config.expr, serializer_pass, canonical_param(), line_ender)); + body.line(&format!( + "{}.serialize({}{}){}", + config.expr, + serializer_pass, + canonical_param(), + line_ender + )); } - }, + } SerializingRustType::Root(ConceptualRustType::Array(ty)) => { let len_expr = match &ty.conceptual_type { ConceptualRustType::Rust(elem_ident) if types.is_plain_group(elem_ident) => { // you should not be able to indiscriminately encode a plain group like this as it // could be multiple elements. This would require special handling if it's even permitted in CDDL. assert!(ty.encodings.is_empty()); - if let Some(fixed_elem_size) = ty.conceptual_type.expanded_field_count(types) { + if let Some(fixed_elem_size) = + ty.conceptual_type.expanded_field_count(types) + { format!("{} * {}.len() as u64", fixed_elem_size, config.expr) } else { format!( "{}.iter().map(|e| {}).sum()", config.expr, - ty.conceptual_type.definite_info("e", types)) + ty.conceptual_type.definite_info("e", types) + ) } - }, - _ => format!("{}.len() as u64", config.expr) + } + _ => format!("{}.len() as u64", config.expr), }; - start_len(body, Representation::Array, serializer_use, &encoding_var, &len_expr); + start_len( + body, + Representation::Array, + serializer_use, + &encoding_var, + &len_expr, + ); let elem_var_name = format!("{}_elem", config.var_name); let elem_encs = if CLI_ARGS.preserve_encodings { encoding_fields(&elem_var_name, &ty.clone().resolve_aliases(), false) @@ -1032,7 +1271,10 @@ impl GenerationScope { vec![] }; let mut loop_block = if !elem_encs.is_empty() { - let mut block = Block::new(&format!("for (i, element) in {}.iter().enumerate()", config.expr)); + let mut block = Block::new(&format!( + "for (i, element) in {}.iter().enumerate()", + config.expr + )); block.line(config.container_encoding_lookup("elem", &elem_encs, "i")); block } else { @@ -1049,38 +1291,60 @@ impl GenerationScope { self.generate_serialize(types, (&**ty).into(), &mut loop_block, elem_config); body.push_block(loop_block); end_len(body, serializer_use, &encoding_var, config.is_end); - }, + } SerializingRustType::Root(ConceptualRustType::Map(key, value)) => { - start_len(body, Representation::Map, serializer_use, &encoding_var, &format!("{}.len() as u64", config.expr)); + start_len( + body, + Representation::Map, + serializer_use, + &encoding_var, + &format!("{}.len() as u64", config.expr), + ); let ser_loop = if CLI_ARGS.preserve_encodings { - let key_enc_fields = encoding_fields(&format!("{}_key", config.var_name), &key.clone().resolve_aliases(), false); - let value_enc_fields = encoding_fields(&format!("{}_value", config.var_name), &value.clone().resolve_aliases(), false); + let key_enc_fields = encoding_fields( + &format!("{}_key", config.var_name), + &key.clone().resolve_aliases(), + false, + ); + let value_enc_fields = encoding_fields( + &format!("{}_value", config.var_name), + &value.clone().resolve_aliases(), + false, + ); let mut ser_loop = if CLI_ARGS.canonical_form { - let mut key_order = codegen::Block::new(&format!("let mut key_order = {}.iter().map(|(k, v)|", config.expr)); - key_order - .line("let mut buf = cbor_event::se::Serializer::new_vec();"); + let mut key_order = codegen::Block::new(&format!( + "let mut key_order = {}.iter().map(|(k, v)|", + config.expr + )); + key_order.line("let mut buf = cbor_event::se::Serializer::new_vec();"); if !key_enc_fields.is_empty() { - key_order.line(config.container_encoding_lookup("key", &key_enc_fields, "k")); + key_order.line(config.container_encoding_lookup( + "key", + &key_enc_fields, + "k", + )); } - let key_config = SerializeConfig::new("k", format!("{}_key", config.var_name)) - .expr_is_ref(true) - .is_end(false) - .serializer_name_overload(("buf", true)) - .encoding_var_is_ref(false); + let key_config = + SerializeConfig::new("k", format!("{}_key", config.var_name)) + .expr_is_ref(true) + .is_end(false) + .serializer_name_overload(("buf", true)) + .encoding_var_is_ref(false); self.generate_serialize(types, (&**key).into(), &mut key_order, key_config); - key_order - .line("Ok((buf.finalize(), k, v))") - .after(").collect::, &_, &_)>, cbor_event::Error>>()?;"); + key_order.line("Ok((buf.finalize(), k, v))").after( + ").collect::, &_, &_)>, cbor_event::Error>>()?;", + ); body.push_block(key_order); let mut key_order_if = codegen::Block::new("if force_canonical"); - let mut key_order_sort = codegen::Block::new("key_order.sort_by(|(lhs_bytes, _, _), (rhs_bytes, _, _)|"); - let mut key_order_sort_match = codegen::Block::new("match lhs_bytes.len().cmp(&rhs_bytes.len())"); + let mut key_order_sort = codegen::Block::new( + "key_order.sort_by(|(lhs_bytes, _, _), (rhs_bytes, _, _)|", + ); + let mut key_order_sort_match = + codegen::Block::new("match lhs_bytes.len().cmp(&rhs_bytes.len())"); key_order_sort_match .line("std::cmp::Ordering::Equal => lhs_bytes.cmp(rhs_bytes),") .line("diff_ord => diff_ord,"); - key_order_sort - .push_block(key_order_sort_match) - .after(");"); + key_order_sort.push_block(key_order_sort_match).after(");"); key_order_if.push_block(key_order_sort); body.push_block(key_order_if); let key_loop_var = if value_enc_fields.is_empty() { @@ -1088,13 +1352,21 @@ impl GenerationScope { } else { "key" }; - let mut ser_loop = Block::new(&format!("for (key_bytes, {}, value) in key_order", key_loop_var)); + let mut ser_loop = Block::new(&format!( + "for (key_bytes, {}, value) in key_order", + key_loop_var + )); ser_loop.line(format!("{}.write_raw_bytes(&key_bytes)?;", serializer_use)); ser_loop } else { - let mut ser_loop = Block::new(&format!("for (key, value) in {}.iter()", config.expr)); + let mut ser_loop = + Block::new(&format!("for (key, value) in {}.iter()", config.expr)); if !key_enc_fields.is_empty() { - ser_loop.line(config.container_encoding_lookup("key", &key_enc_fields, "key")); + ser_loop.line(config.container_encoding_lookup( + "key", + &key_enc_fields, + "key", + )); } let key_config = config .clone() @@ -1108,28 +1380,33 @@ impl GenerationScope { ser_loop }; if !value_enc_fields.is_empty() { - ser_loop.line(config.container_encoding_lookup("value", &value_enc_fields, "key")); + ser_loop.line(config.container_encoding_lookup( + "value", + &value_enc_fields, + "key", + )); } let value_config = config - .clone() - .expr("value") - .expr_is_ref(true) - .var_name(format!("{}_value", config.var_name)) - .is_end(false) - .encoding_var_no_option_struct() - .encoding_var_is_ref(false); + .clone() + .expr("value") + .expr_is_ref(true) + .var_name(format!("{}_value", config.var_name)) + .is_end(false) + .encoding_var_no_option_struct() + .encoding_var_is_ref(false); self.generate_serialize(types, (&**value).into(), &mut ser_loop, value_config); ser_loop } else { - let mut ser_loop = Block::new(&format!("for (key, value) in {}.iter()", config.expr)); + let mut ser_loop = + Block::new(&format!("for (key, value) in {}.iter()", config.expr)); let key_config = config - .clone() - .expr("key") - .expr_is_ref(true) - .var_name(format!("{}_key", config.var_name)) - .is_end(false) - .encoding_var_no_option_struct() - .encoding_var_is_ref(false); + .clone() + .expr("key") + .expr_is_ref(true) + .var_name(format!("{}_key", config.var_name)) + .is_end(false) + .encoding_var_no_option_struct() + .encoding_var_is_ref(false); let value_config = key_config .clone() .expr("value") @@ -1140,34 +1417,41 @@ impl GenerationScope { }; body.push_block(ser_loop); end_len(body, serializer_use, &encoding_var, config.is_end); - }, + } SerializingRustType::Root(ConceptualRustType::Optional(ty)) => { let mut opt_block = Block::new(&format!("match {}", expr_ref)); // TODO: do this in one line without a block if possible somehow. // see other comment in generate_enum() let mut some_block = Block::new("Some(x) =>"); - let opt_config = config - .clone() - .expr("x") - .expr_is_ref(true) - .is_end(true); + let opt_config = config.clone().expr("x").expr_is_ref(true).is_end(true); self.generate_serialize(types, (&**ty).into(), &mut some_block, opt_config); some_block.after(","); opt_block.push_block(some_block); - opt_block.line(&format!("None => {}.write_special(CBORSpecial::Null),", serializer_use)); + opt_block.line(&format!( + "None => {}.write_special(CBORSpecial::Null),", + serializer_use + )); if !config.is_end { opt_block.after("?;"); } body.push_block(opt_block); - }, - SerializingRustType::Root(ConceptualRustType::Alias(_ident, ty)) => self.generate_serialize(types, (&**ty).into(), body, config), + } + SerializingRustType::Root(ConceptualRustType::Alias(_ident, ty)) => { + self.generate_serialize(types, (&**ty).into(), body, config) + } }; } /// Generates a DeserializationCode to serialize {serializing_rust_type} using the context in {before_after} /// This returned value must be in turn pushed into deserialization code to be used. #[must_use] - fn generate_deserialize(&mut self, types: &IntermediateTypes, serializing_rust_type: SerializingRustType, before_after: DeserializeBeforeAfter, mut config: DeserializeConfig) -> DeserializationCode { + fn generate_deserialize( + &mut self, + types: &IntermediateTypes, + serializing_rust_type: SerializingRustType, + before_after: DeserializeBeforeAfter, + mut config: DeserializeConfig, + ) -> DeserializationCode { //body.line(&format!("println!(\"deserializing {}\");", var_name)); if !CLI_ARGS.preserve_encodings { assert!(config.final_exprs.is_empty()); @@ -1175,38 +1459,42 @@ impl GenerationScope { let mut deser_code = DeserializationCode::default(); // joins all config.final_expr together (possibly) with the actual value into a tuple type (if multiple) // or otherwise the value just goes through on its own - let final_expr = |mut encoding_exprs: Vec, actual_value: Option| -> String { - if let Some(e) = actual_value { - // possibly less efficient but more concise - encoding_exprs.insert(0, e); - } - if encoding_exprs.len() > 1 { - format!("({})", encoding_exprs.join(", ")) - } else { - encoding_exprs.join(", ") - } - }; + let final_expr = + |mut encoding_exprs: Vec, actual_value: Option| -> String { + if let Some(e) = actual_value { + // possibly less efficient but more concise + encoding_exprs.insert(0, e); + } + if encoding_exprs.len() > 1 { + format!("({})", encoding_exprs.join(", ")) + } else { + encoding_exprs.join(", ") + } + }; // Gives a total final expression including the before_after context // as well as dealing with avoiding clippy warning which is why we can // be conditionally a direct value (if there are encoding vars thus a tuple) // or we can be a result that goes straight through (subject to before_after) // This helps avoid clippy::needless_question_mark here. - let final_result_expr_complete = |throws: &mut bool, final_exprs: Vec, result_expr: &str| -> String { - if final_exprs.is_empty() { - format!( - "{}{}{}", - before_after.before_str(true), - result_expr, - before_after.after_str(true)) - } else { - *throws = true; - format!( - "{}{}{}", - before_after.before_str(false), - final_expr(final_exprs, Some(format!("{}?", result_expr))), - before_after.after_str(false)) - } - }; + let final_result_expr_complete = + |throws: &mut bool, final_exprs: Vec, result_expr: &str| -> String { + if final_exprs.is_empty() { + format!( + "{}{}{}", + before_after.before_str(true), + result_expr, + before_after.after_str(true) + ) + } else { + *throws = true; + format!( + "{}{}{}", + before_after.before_str(false), + final_expr(final_exprs, Some(format!("{}?", result_expr))), + before_after.after_str(false) + ) + } + }; let deserializer_name = config.deserializer_name(); match serializing_rust_type { SerializingRustType::Root(ConceptualRustType::Fixed(f)) => { @@ -1224,81 +1512,127 @@ impl GenerationScope { } match f { FixedValue::Null => { - let mut special_block = Block::new(&format!("if {}.special()? != CBORSpecial::Null", deserializer_name)); + let mut special_block = Block::new(&format!( + "if {}.special()? != CBORSpecial::Null", + deserializer_name + )); special_block.line("return Err(DeserializeFailure::ExpectedNull.into());"); deser_code.content.push_block(special_block); if CLI_ARGS.preserve_encodings { - deser_code.content.line(&format!("{}{}{}", before_after.before_str(false), final_expr(config.final_exprs, None), before_after.after_str(false))); + deser_code.content.line(&format!( + "{}{}{}", + before_after.before_str(false), + final_expr(config.final_exprs, None), + before_after.after_str(false) + )); } - }, + } FixedValue::Uint(x) => { if CLI_ARGS.preserve_encodings { deser_code.content.line(&format!( "let ({}_value, {}_encoding) = {}.unsigned_integer_sz()?;", - config.var_name, - config.var_name, - deserializer_name)); + config.var_name, config.var_name, deserializer_name + )); } else { - deser_code.content.line(&format!("let {}_value = {}.unsigned_integer()?;", config.var_name, deserializer_name)); + deser_code.content.line(&format!( + "let {}_value = {}.unsigned_integer()?;", + config.var_name, deserializer_name + )); } - let mut compare_block = Block::new(&format!("if {}_value != {}", config.var_name, x)); + let mut compare_block = + Block::new(&format!("if {}_value != {}", config.var_name, x)); compare_block.line(format!("return Err(DeserializeFailure::FixedValueMismatch{{ found: Key::Uint({}_value), expected: Key::Uint({}) }}.into());", config.var_name, x)); deser_code.content.push_block(compare_block); if CLI_ARGS.preserve_encodings { - config.final_exprs.push(format!("Some({}_encoding)", config.var_name)); - deser_code.content.line(&format!("{}{}{}", before_after.before_str(false), final_expr(config.final_exprs, None), before_after.after_str(false))); + config + .final_exprs + .push(format!("Some({}_encoding)", config.var_name)); + deser_code.content.line(&format!( + "{}{}{}", + before_after.before_str(false), + final_expr(config.final_exprs, None), + before_after.after_str(false) + )); //body.line(&format!("{}{}{}_encoding{}{}", before, sp, var_name, ep, after)); } - }, + } FixedValue::Nint(x) => { if CLI_ARGS.preserve_encodings { - deser_code.content.line(&format!("let ({}_value, {}_encoding) = {}.negative_integer_sz()?;", config.var_name, config.var_name, deserializer_name)); + deser_code.content.line(&format!( + "let ({}_value, {}_encoding) = {}.negative_integer_sz()?;", + config.var_name, config.var_name, deserializer_name + )); } else { // we use the _sz variant here too to get around imcomplete nint support in the regular negative_integer() - deser_code.content.line(&format!("let ({}_value, _) = {}.negative_integer_sz()?;", config.var_name, deserializer_name)); + deser_code.content.line(&format!( + "let ({}_value, _) = {}.negative_integer_sz()?;", + config.var_name, deserializer_name + )); } let x_abs = (x + 1).abs(); - let mut compare_block = Block::new(&format!("if {}_value != {}", config.var_name, x)); + let mut compare_block = + Block::new(&format!("if {}_value != {}", config.var_name, x)); compare_block.line(format!("return Err(DeserializeFailure::FixedValueMismatch{{ found: Key::Uint(({}_value + 1).abs() as u64), expected: Key::Uint({}) }}.into());", config.var_name, x_abs)); deser_code.content.push_block(compare_block); if CLI_ARGS.preserve_encodings { - config.final_exprs.push(format!("Some({}_encoding)", config.var_name)); - deser_code.content.line( - &format!( - "{}{}{}", - before_after.before_str(false), - final_expr(config.final_exprs, None), - before_after.after_str(false))); + config + .final_exprs + .push(format!("Some({}_encoding)", config.var_name)); + deser_code.content.line(&format!( + "{}{}{}", + before_after.before_str(false), + final_expr(config.final_exprs, None), + before_after.after_str(false) + )); //body.line(&format!("{}{}{}_encoding{}{}", before, sp, var_name, ep, after)); } - }, + } FixedValue::Text(x) => { if CLI_ARGS.preserve_encodings { - deser_code.content.line(&format!("let ({}_value, {}_encoding) = {}.text_sz()?;", config.var_name, config.var_name, deserializer_name)); + deser_code.content.line(&format!( + "let ({}_value, {}_encoding) = {}.text_sz()?;", + config.var_name, config.var_name, deserializer_name + )); } else { - deser_code.content.line(&format!("let {}_value = {}.text()?;", config.var_name, deserializer_name)); + deser_code.content.line(&format!( + "let {}_value = {}.text()?;", + config.var_name, deserializer_name + )); } - let mut compare_block = Block::new(&format!("if {}_value != \"{}\"", config.var_name, x)); + let mut compare_block = + Block::new(&format!("if {}_value != \"{}\"", config.var_name, x)); compare_block.line(format!("return Err(DeserializeFailure::FixedValueMismatch{{ found: Key::Str({}_value), expected: Key::Str(String::from(\"{}\")) }}.into());", config.var_name, x)); deser_code.content.push_block(compare_block); if CLI_ARGS.preserve_encodings { - config.final_exprs.push(format!("StringEncoding::from({}_encoding)", config.var_name)); - deser_code.content.line(&format!("{}{}{}", before_after.before_str(false), final_expr(config.final_exprs, None), before_after.after_str(false))); + config.final_exprs.push(format!( + "StringEncoding::from({}_encoding)", + config.var_name + )); + deser_code.content.line(&format!( + "{}{}{}", + before_after.before_str(false), + final_expr(config.final_exprs, None), + before_after.after_str(false) + )); } - }, + } FixedValue::Float(x) => { - deser_code.content.line(&format!("let {}_value = {}.float()?;", config.var_name, deserializer_name)); - let mut compare_block = Block::new(&format!("if {}_value != {}", config.var_name, x)); + deser_code.content.line(&format!( + "let {}_value = {}.float()?;", + config.var_name, deserializer_name + )); + let mut compare_block = + Block::new(&format!("if {}_value != {}", config.var_name, x)); compare_block.line(format!("return Err(DeserializeFailure::FixedValueMismatch{{ found: Key::Float({}_value), expected: Key::Float({}) }}.into());", config.var_name, x)); deser_code.content.push_block(compare_block); if CLI_ARGS.preserve_encodings { unimplemented!("preserve_encodings is not implemented for float") } - }, + } _ => unimplemented!(), }; deser_code.throws = true; - }, + } SerializingRustType::Root(ConceptualRustType::Primitive(p)) => { if config.optional_field { deser_code.content.line("read_len.read_elems(1)?;"); @@ -1310,54 +1644,72 @@ impl GenerationScope { } else { "" }; - let mut deser_primitive = |mut final_exprs: Vec, func: &str, x: &str, x_expr: &str| if CLI_ARGS.preserve_encodings { - let enc_expr = match func { - "text" | "bytes" => "StringEncoding::from(enc)", - _ => "Some(enc)", + let mut deser_primitive = + |mut final_exprs: Vec, func: &str, x: &str, x_expr: &str| { + if CLI_ARGS.preserve_encodings { + let enc_expr = match func { + "text" | "bytes" => "StringEncoding::from(enc)", + _ => "Some(enc)", + }; + final_exprs.push(enc_expr.to_owned()); + deser_code.content.line(&format!( + "{}{}.{}_sz().map(|({}, enc)| {}){}{}", + before_after.before_str(true), + deserializer_name, + func, + x, + final_expr(final_exprs, Some(x_expr.to_owned())), + error_convert, + before_after.after_str(true) + )); + } else { + deser_code.content.line(&format!( + "{}{}.{}()? as {}{}", + before_after.before_str(false), + deserializer_name, + func, + p.to_string(), + before_after.after_str(false) + )); + deser_code.throws = true; + } }; - final_exprs.push(enc_expr.to_owned()); - deser_code.content.line( - &format!( - "{}{}.{}_sz().map(|({}, enc)| {}){}{}", - before_after.before_str(true), - deserializer_name, - func, - x, - final_expr(final_exprs, Some(x_expr.to_owned())), - error_convert, - before_after.after_str(true))); - } else { - deser_code.content.line(&format!( - "{}{}.{}()? as {}{}", - before_after.before_str(false), - deserializer_name, - func, - p.to_string(), - before_after.after_str(false))); - deser_code.throws = true; - }; match p { - Primitive::Bytes => deser_primitive(config.final_exprs, "bytes", "bytes", "bytes"), - Primitive::U8 | Primitive::U16 | Primitive::U32 => deser_primitive(config.final_exprs, "unsigned_integer", "x", &format!("x as {}", p.to_string())), - Primitive::U64 => deser_primitive(config.final_exprs, "unsigned_integer", "x", "x"), - Primitive::I8 | - Primitive::I16 | - Primitive::I32 | - Primitive::I64 => { - let mut type_check = Block::new(&format!("{}match {}.cbor_type()?", before_after.before_str(false), deserializer_name)); + Primitive::Bytes => { + deser_primitive(config.final_exprs, "bytes", "bytes", "bytes") + } + Primitive::U8 | Primitive::U16 | Primitive::U32 => deser_primitive( + config.final_exprs, + "unsigned_integer", + "x", + &format!("x as {}", p.to_string()), + ), + Primitive::U64 => { + deser_primitive(config.final_exprs, "unsigned_integer", "x", "x") + } + Primitive::I8 | Primitive::I16 | Primitive::I32 | Primitive::I64 => { + let mut type_check = Block::new(&format!( + "{}match {}.cbor_type()?", + before_after.before_str(false), + deserializer_name + )); if CLI_ARGS.preserve_encodings { let mut pos = Block::new("cbor_event::Type::UnsignedInteger =>"); - pos - .line(&format!("let (x, enc) = {}.unsigned_integer_sz()?;", deserializer_name)) - .line(format!("(x as {}, Some(enc))", p.to_string())) - .after(","); + pos.line(&format!( + "let (x, enc) = {}.unsigned_integer_sz()?;", + deserializer_name + )) + .line(format!("(x as {}, Some(enc))", p.to_string())) + .after(","); type_check.push_block(pos); // let this cover both the negative int case + error case let mut neg = Block::new("_ =>"); - neg - .line(&format!("let (x, enc) = {}.negative_integer_sz()?;", deserializer_name)) - .line(format!("(x as {}, Some(enc))", p.to_string())) - .after(","); + neg.line(&format!( + "let (x, enc) = {}.negative_integer_sz()?;", + deserializer_name + )) + .line(format!("(x as {}, Some(enc))", p.to_string())) + .after(","); type_check.push_block(neg); } else { type_check @@ -1365,74 +1717,117 @@ impl GenerationScope { // https://github.com/primetype/cbor_event/issues/9 // cbor_event's negative_integer() doesn't support i64::MIN so we use the _sz function here instead as that one supports all nints if *p == Primitive::I64 { - type_check.line(format!("_ => {}.negative_integer_sz().map(|(x, _enc)| x)? as {},", deserializer_name, p.to_string())); + type_check.line(format!( + "_ => {}.negative_integer_sz().map(|(x, _enc)| x)? as {},", + deserializer_name, + p.to_string() + )); } else { - type_check.line(format!("_ => {}.negative_integer()? as {},", deserializer_name, p.to_string())); + type_check.line(format!( + "_ => {}.negative_integer()? as {},", + deserializer_name, + p.to_string() + )); } } type_check.after(&before_after.after_str(false)); deser_code.content.push_block(type_check); deser_code.throws = true; - }, - Primitive::N64 => if CLI_ARGS.preserve_encodings{ - deser_primitive(config.final_exprs, "negative_integer", "x", "(x + 1).abs() as u64") - } else { - // https://github.com/primetype/cbor_event/issues/9 - // cbor_event's negative_integer() doesn't support full nint range so we use the _sz function here instead as that one supports all nints - deser_code.content.line(&format!("{}{}.negative_integer_sz().map(|(x, _enc)| (x + 1).abs() as u64){}{}", before_after.before_str(true), deserializer_name, error_convert, before_after.after_str(true))); - }, + } + Primitive::N64 => { + if CLI_ARGS.preserve_encodings { + deser_primitive( + config.final_exprs, + "negative_integer", + "x", + "(x + 1).abs() as u64", + ) + } else { + // https://github.com/primetype/cbor_event/issues/9 + // cbor_event's negative_integer() doesn't support full nint range so we use the _sz function here instead as that one supports all nints + deser_code.content.line(&format!("{}{}.negative_integer_sz().map(|(x, _enc)| (x + 1).abs() as u64){}{}", before_after.before_str(true), deserializer_name, error_convert, before_after.after_str(true))); + } + } Primitive::Str => deser_primitive(config.final_exprs, "text", "s", "s"), Primitive::Bool => { // no encoding differences for bool - deser_code.content.line(&final_result_expr_complete(&mut deser_code.throws, config.final_exprs, "raw.bool()")); - }, + deser_code.content.line(&final_result_expr_complete( + &mut deser_code.throws, + config.final_exprs, + "raw.bool()", + )); + } Primitive::F32 => { - deser_code.content.line(&final_result_expr_complete(&mut deser_code.throws, config.final_exprs, "f32::deserialize(raw)")); + deser_code.content.line(&final_result_expr_complete( + &mut deser_code.throws, + config.final_exprs, + "f32::deserialize(raw)", + )); if CLI_ARGS.preserve_encodings { unimplemented!("preserve_encodings is not implemented for float") } - }, + } Primitive::F64 => { - deser_code.content.line(&final_result_expr_complete(&mut deser_code.throws, config.final_exprs, "f64::deserialize(raw)")); + deser_code.content.line(&final_result_expr_complete( + &mut deser_code.throws, + config.final_exprs, + "f64::deserialize(raw)", + )); if CLI_ARGS.preserve_encodings { unimplemented!("preserve_encodings is not implemented for float") } - }, + } }; - }, - SerializingRustType::Root(ConceptualRustType::Rust(ident)) => if types.is_plain_group(ident) { - // This would mess up with length checks otherwise and is probably not a likely situation if this is even valid in CDDL. - // To have this work (if it's valid) you'd either need to generate 2 embedded deserialize methods or pass - // a parameter whether it was an optional field, and if so, read_len.read_elems(embedded mandatory fields)?; - // since otherwise it'd only length check the optional fields within the type. - assert!(!config.optional_field); - deser_code.read_len_used = true; - let final_expr_value = format!( - "{}::deserialize_as_embedded_group({}, {}, len)", - ident, - deserializer_name, - config.pass_read_len()); - - deser_code.content.line(&final_result_expr_complete(&mut deser_code.throws, config.final_exprs, &final_expr_value)); - } else { - if config.optional_field { - deser_code.content.line("read_len.read_elems(1)?;"); + } + SerializingRustType::Root(ConceptualRustType::Rust(ident)) => { + if types.is_plain_group(ident) { + // This would mess up with length checks otherwise and is probably not a likely situation if this is even valid in CDDL. + // To have this work (if it's valid) you'd either need to generate 2 embedded deserialize methods or pass + // a parameter whether it was an optional field, and if so, read_len.read_elems(embedded mandatory fields)?; + // since otherwise it'd only length check the optional fields within the type. + assert!(!config.optional_field); deser_code.read_len_used = true; - deser_code.throws = true; + let final_expr_value = format!( + "{}::deserialize_as_embedded_group({}, {}, len)", + ident, + deserializer_name, + config.pass_read_len() + ); + + deser_code.content.line(&final_result_expr_complete( + &mut deser_code.throws, + config.final_exprs, + &final_expr_value, + )); + } else { + if config.optional_field { + deser_code.content.line("read_len.read_elems(1)?;"); + deser_code.read_len_used = true; + deser_code.throws = true; + } + let final_expr_value = format!("{}::deserialize({})", ident, deserializer_name); + deser_code.content.line(&final_result_expr_complete( + &mut deser_code.throws, + config.final_exprs, + &final_expr_value, + )); } - let final_expr_value = format!("{}::deserialize({})", ident, deserializer_name); - deser_code.content.line(&final_result_expr_complete(&mut deser_code.throws, config.final_exprs, &final_expr_value)); - }, + } SerializingRustType::Root(ConceptualRustType::Optional(ty)) => { - let read_len_check = config.optional_field || (ty.expanded_field_count(types) != Some(1)); + let read_len_check = + config.optional_field || (ty.expanded_field_count(types) != Some(1)); // codegen crate doesn't support if/else or appending a block after a block, only strings // so we need to create a local bool var and use a match instead let if_label = if ty.cbor_types().contains(&CBORType::Special) { let is_some_check_var = format!("{}_is_some", config.var_name); - let mut is_some_check = Block::new(&format!("let {} = match cbor_type()?", is_some_check_var)); + let mut is_some_check = + Block::new(&format!("let {} = match cbor_type()?", is_some_check_var)); let mut special_block = Block::new("CBORType::Special =>"); special_block.line(&format!("let special = {}.special()?;", deserializer_name)); - special_block.line(&format!("{}.as_mut_ref().seek(SeekFrom::Current(-1)).unwrap();", deserializer_name)); + special_block.line(&format!( + "{}.as_mut_ref().seek(SeekFrom::Current(-1)).unwrap();", + deserializer_name + )); let mut special_match = Block::new("match special"); // TODO: we need to check that we don't have null / null somewhere special_match.line("CBORSpecial::Null => false,"); @@ -1449,9 +1844,16 @@ impl GenerationScope { deser_code.content.push_block(is_some_check); is_some_check_var } else { - String::from(&format!("{}.cbor_type()? != CBORType::Special", deserializer_name)) + String::from(&format!( + "{}.cbor_type()? != CBORType::Special", + deserializer_name + )) }; - let mut deser_block = Block::new(&format!("{}match {}", before_after.before_str(false), if_label)); + let mut deser_block = Block::new(&format!( + "{}match {}", + before_after.before_str(false), + if_label + )); let mut some_block = Block::new("true =>"); if read_len_check { let mandatory_fields = ty.expanded_mandatory_field_count(types); @@ -1470,7 +1872,8 @@ impl GenerationScope { types, (&**ty).into(), DeserializeBeforeAfter::new("Some(", ")", false), - config.optional_field(false)) + config.optional_field(false), + ) .add_to(&mut some_block); } else { let (map_some_before, map_some_after) = if ty.is_fixed_value() { @@ -1484,13 +1887,20 @@ impl GenerationScope { .collect::>() .join(", "); // we need to annotate the Ok's error type since the compiler gets confused otherwise - ("Result::<_, DeserializeError>::Ok(", format!(").map(|(x, {})| (Some(x), {}))?", enc_vars_str, enc_vars_str)) + ( + "Result::<_, DeserializeError>::Ok(", + format!( + ").map(|(x, {})| (Some(x), {}))?", + enc_vars_str, enc_vars_str + ), + ) }; self.generate_deserialize( types, (&**ty).into(), DeserializeBeforeAfter::new(map_some_before, &map_some_after, false), - config.optional_field(false)) + config.optional_field(false), + ) .add_to(&mut some_block); } some_block.after(","); @@ -1502,7 +1912,10 @@ impl GenerationScope { } // we don't use this to avoid the new (true) if CLI_ARGS.preserve_encodings is set //self.generate_deserialize(types, &ConceptualRustType::Fixed(FixedValue::Null), var_name, "", "", in_embedded, false, add_parens, &mut none_block); - let mut check_null = Block::new(&format!("if {}.special()? != CBORSpecial::Null", deserializer_name)); + let mut check_null = Block::new(&format!( + "if {}.special()? != CBORSpecial::Null", + deserializer_name + )); check_null.line("return Err(DeserializeFailure::ExpectedNull.into());"); none_block.push_block(check_null); if CLI_ARGS.preserve_encodings { @@ -1511,7 +1924,11 @@ impl GenerationScope { } else { vec!["None".to_owned()] }; - none_elems.extend(ty_enc_fields.iter().map(|enc_field| enc_field.default_expr.to_owned())); + none_elems.extend( + ty_enc_fields + .iter() + .map(|enc_field| enc_field.default_expr.to_owned()), + ); match none_elems.len() { // this probably isn't properly supported by other parts of code and is so unlikely to be encountered // that we really don't care right now. if you run into this open an issue and it can be investigated @@ -1526,18 +1943,20 @@ impl GenerationScope { deser_block.push_block(none_block); deser_code.content.push_block(deser_block); deser_code.throws = true; - }, + } SerializingRustType::Root(ConceptualRustType::Array(ty)) => { //if !self.deserialize_generated_for_type(&element_type) { - // TODO: check this elsehwere??? - //self.dont_generate_deserialize(&array_type_ident, format!("inner type {} doesn't support deserialize", element_type.for_rust_member())); + // TODO: check this elsehwere??? + //self.dont_generate_deserialize(&array_type_ident, format!("inner type {} doesn't support deserialize", element_type.for_rust_member())); //} if config.optional_field { deser_code.content.line("read_len.read_elems(1)?;"); deser_code.read_len_used = true; } let arr_var_name = format!("{}_arr", config.var_name); - deser_code.content.line(&format!("let mut {} = Vec::new();", arr_var_name)); + deser_code + .content + .line(&format!("let mut {} = Vec::new();", arr_var_name)); let elem_var_name = format!("{}_elem", config.var_name); let elem_encs = if CLI_ARGS.preserve_encodings { encoding_fields(&elem_var_name, &ty.clone().resolve_aliases(), false) @@ -1545,14 +1964,23 @@ impl GenerationScope { vec![] }; if CLI_ARGS.preserve_encodings { - deser_code.content + deser_code + .content .line(&format!("let len = {}.array_sz()?;", deserializer_name)) - .line(&format!("let mut {}_encoding = len.into();", config.var_name)); + .line(&format!( + "let mut {}_encoding = len.into();", + config.var_name + )); if !elem_encs.is_empty() { - deser_code.content.line(&format!("let mut {}_elem_encodings = Vec::new();", config.var_name)); + deser_code.content.line(&format!( + "let mut {}_elem_encodings = Vec::new();", + config.var_name + )); } } else { - deser_code.content.line(&format!("let len = {}.array()?;", deserializer_name)); + deser_code + .content + .line(&format!("let len = {}.array()?;", deserializer_name)); } let mut elem_config = DeserializeConfig::new(&elem_var_name); let (mut deser_loop, plain_len_check) = match &ty.conceptual_type { @@ -1561,20 +1989,28 @@ impl GenerationScope { // 1) We can't directly read the CBOR len's number of items since it could be >1 // 2) We need a different cbor read len var to pass into embedded deserialize let read_len_overload = format!("{}_read_len", config.var_name); - deser_code.content.line(&format!("let mut {} = CBORReadLen::new(len);", read_len_overload)); + deser_code.content.line(&format!( + "let mut {} = CBORReadLen::new(len);", + read_len_overload + )); // inside of deserialize_as_embedded_group we only modify read_len for things we couldn't // statically know beforehand. This was done for other areas that use plain groups in order // to be able to do static length checks for statically sized groups that contain plain groups // at the start of deserialization instead of many checks for every single field. - let plain_len_check = match ty.conceptual_type.expanded_mandatory_field_count(types) { - 0 => None, - n => Some(format!("{}.read_elems({})?;", read_len_overload, n)), - }; + let plain_len_check = + match ty.conceptual_type.expanded_mandatory_field_count(types) { + 0 => None, + n => Some(format!("{}.read_elems({})?;", read_len_overload, n)), + }; elem_config = elem_config.overload_read_len(read_len_overload); - let deser_loop = make_deser_loop("len", &format!("{}_read_len.read()", config.var_name)); + let deser_loop = + make_deser_loop("len", &format!("{}_read_len.read()", config.var_name)); (deser_loop, plain_len_check) - }, - _ => (make_deser_loop("len", &format!("({}.len() as u64)", arr_var_name)), None) + } + _ => ( + make_deser_loop("len", &format!("({}.len() as u64)", arr_var_name)), + None, + ), }; deser_loop.push_block(make_deser_loop_break_check()); if let Some(plain_len_check) = plain_len_check { @@ -1583,40 +2019,63 @@ impl GenerationScope { elem_config.deserializer_name_overload = config.deserializer_name_overload; if !elem_encs.is_empty() { let elem_var_names_str = encoding_var_names_str(&elem_var_name, ty); - self - .generate_deserialize( - types, - (&**ty).into(), - DeserializeBeforeAfter::new(&format!("let {} = ", elem_var_names_str), ";", false), - elem_config) - .add_to(&mut deser_loop); + self.generate_deserialize( + types, + (&**ty).into(), + DeserializeBeforeAfter::new( + &format!("let {} = ", elem_var_names_str), + ";", + false, + ), + elem_config, + ) + .add_to(&mut deser_loop); deser_loop .line(format!("{}.push({});", arr_var_name, elem_var_name)) .line(format!( "{}_elem_encodings.push({});", config.var_name, - tuple_str(elem_encs.iter().map(|enc| enc.field_name.clone()).collect()))); + tuple_str(elem_encs.iter().map(|enc| enc.field_name.clone()).collect()) + )); } else { - self - .generate_deserialize( - types, - (&**ty).into(), - DeserializeBeforeAfter::new(&format!("{}.push(", arr_var_name), ");", false), - elem_config) - .add_to(&mut deser_loop); + self.generate_deserialize( + types, + (&**ty).into(), + DeserializeBeforeAfter::new( + &format!("{}.push(", arr_var_name), + ");", + false, + ), + elem_config, + ) + .add_to(&mut deser_loop); } deser_code.content.push_block(deser_loop); if CLI_ARGS.preserve_encodings { - config.final_exprs.push(format!("{}_encoding", config.var_name)); + config + .final_exprs + .push(format!("{}_encoding", config.var_name)); if !elem_encs.is_empty() { - config.final_exprs.push(format!("{}_elem_encodings", config.var_name)); + config + .final_exprs + .push(format!("{}_elem_encodings", config.var_name)); } - deser_code.content.line(&format!("{}{}{}", before_after.before_str(false), final_expr(config.final_exprs, Some(arr_var_name)), before_after.after_str(false))); + deser_code.content.line(&format!( + "{}{}{}", + before_after.before_str(false), + final_expr(config.final_exprs, Some(arr_var_name)), + before_after.after_str(false) + )); } else { - deser_code.content.line(&format!("{}{}{}", before_after.before_str(false), arr_var_name, before_after.after_str(false))); + deser_code.content.line(&format!( + "{}{}{}", + before_after.before_str(false), + arr_var_name, + before_after.after_str(false) + )); } deser_code.throws = true; - }, + } SerializingRustType::Root(ConceptualRustType::Map(key_type, value_type)) => { if config.optional_field { deser_code.content.line("read_len.read_elems(1)?;"); @@ -1631,7 +2090,11 @@ impl GenerationScope { //self.dont_generate_deserialize(name, format!("value type {} doesn't support deserialize", value_type.for_rust_member())); } else { let table_var = format!("{}_table", config.var_name); - deser_code.content.line(&format!("let mut {} = {}::new();", table_var, table_type())); + deser_code.content.line(&format!( + "let mut {} = {}::new();", + table_var, + table_type() + )); let key_var_name = format!("{}_key", config.var_name); let value_var_name = format!("{}_value", config.var_name); let key_encs = if CLI_ARGS.preserve_encodings { @@ -1640,65 +2103,105 @@ impl GenerationScope { vec![] }; let value_encs = if CLI_ARGS.preserve_encodings { - encoding_fields(&value_var_name, &value_type.clone().resolve_aliases(), false) + encoding_fields( + &value_var_name, + &value_type.clone().resolve_aliases(), + false, + ) } else { vec![] }; let len_var = format!("{}_len", config.var_name); if CLI_ARGS.preserve_encodings { - deser_code.content - .line(&format!("let {} = {}.map_sz()?;", len_var, deserializer_name)) - .line(&format!("let {}_encoding = {}.into();", config.var_name, len_var)); + deser_code + .content + .line(&format!( + "let {} = {}.map_sz()?;", + len_var, deserializer_name + )) + .line(&format!( + "let {}_encoding = {}.into();", + config.var_name, len_var + )); if !key_encs.is_empty() { - deser_code.content.line(&format!("let mut {}_key_encodings = BTreeMap::new();", config.var_name)); + deser_code.content.line(&format!( + "let mut {}_key_encodings = BTreeMap::new();", + config.var_name + )); } if !value_encs.is_empty() { - deser_code.content.line(&format!("let mut {}_value_encodings = BTreeMap::new();", config.var_name)); + deser_code.content.line(&format!( + "let mut {}_value_encodings = BTreeMap::new();", + config.var_name + )); } } else { - deser_code.content.line(&format!("let {} = {}.map()?;", len_var, deserializer_name)); + deser_code + .content + .line(&format!("let {} = {}.map()?;", len_var, deserializer_name)); } - let mut deser_loop = make_deser_loop(&len_var, &format!("({}.len() as u64)", table_var)); + let mut deser_loop = + make_deser_loop(&len_var, &format!("({}.len() as u64)", table_var)); deser_loop.push_block(make_deser_loop_break_check()); let mut key_config = DeserializeConfig::new(&key_var_name); key_config.deserializer_name_overload = config.deserializer_name_overload; let mut value_config = DeserializeConfig::new(&value_var_name); value_config.deserializer_name_overload = config.deserializer_name_overload; let (key_var_names_str, value_var_names_str) = if CLI_ARGS.preserve_encodings { - (encoding_var_names_str(&key_var_name, key_type), encoding_var_names_str(&value_var_name, value_type)) + ( + encoding_var_names_str(&key_var_name, key_type), + encoding_var_names_str(&value_var_name, value_type), + ) } else { (key_var_name.clone(), value_var_name.clone()) }; - self - .generate_deserialize( - types, - (&**key_type).into(), - DeserializeBeforeAfter::new(&format!("let {} = ", key_var_names_str), ";", false), - key_config) - .add_to(&mut deser_loop); - self - .generate_deserialize( - types, - (&**value_type).into(), - DeserializeBeforeAfter::new(&format!("let {} = ", value_var_names_str), ";", false), - value_config) - .add_to(&mut deser_loop); + self.generate_deserialize( + types, + (&**key_type).into(), + DeserializeBeforeAfter::new( + &format!("let {} = ", key_var_names_str), + ";", + false, + ), + key_config, + ) + .add_to(&mut deser_loop); + self.generate_deserialize( + types, + (&**value_type).into(), + DeserializeBeforeAfter::new( + &format!("let {} = ", value_var_names_str), + ";", + false, + ), + value_config, + ) + .add_to(&mut deser_loop); let mut dup_check = Block::new(&format!( "if {}.insert({}{}, {}).is_some()", table_var, key_var_name, if key_type.is_copy() { "" } else { ".clone()" }, - value_var_name)); + value_var_name + )); let dup_key_error_key = match &key_type.conceptual_type { - ConceptualRustType::Primitive(Primitive::U8) | - ConceptualRustType::Primitive(Primitive::U16) | - ConceptualRustType::Primitive(Primitive::U32) | - ConceptualRustType::Primitive(Primitive::U64) => format!("Key::Uint({}.into())", key_var_name), - ConceptualRustType::Primitive(Primitive::Str) => format!("Key::Str({})", key_var_name), + ConceptualRustType::Primitive(Primitive::U8) + | ConceptualRustType::Primitive(Primitive::U16) + | ConceptualRustType::Primitive(Primitive::U32) + | ConceptualRustType::Primitive(Primitive::U64) => { + format!("Key::Uint({}.into())", key_var_name) + } + ConceptualRustType::Primitive(Primitive::Str) => { + format!("Key::Str({})", key_var_name) + } // TODO: make a generic one then store serialized CBOR? - _ => "Key::Str(String::from(\"some complicated/unsupported type\"))".to_owned(), + _ => "Key::Str(String::from(\"some complicated/unsupported type\"))" + .to_owned(), }; - dup_check.line(format!("return Err(DeserializeFailure::DuplicateKey({}).into());", dup_key_error_key)); + dup_check.line(format!( + "return Err(DeserializeFailure::DuplicateKey({}).into());", + dup_key_error_key + )); deser_loop.push_block(dup_check); if CLI_ARGS.preserve_encodings { if !key_encs.is_empty() { @@ -1706,71 +2209,118 @@ impl GenerationScope { "{}_key_encodings.insert({}{}, {});", config.var_name, key_var_name, - if key_type.encoding_var_is_copy() { "" } else { ".clone()" }, - tuple_str(key_encs.iter().map(|enc| enc.field_name.clone()).collect()))); + if key_type.encoding_var_is_copy() { + "" + } else { + ".clone()" + }, + tuple_str( + key_encs.iter().map(|enc| enc.field_name.clone()).collect() + ) + )); } if !value_encs.is_empty() { deser_loop.line(format!( "{}_value_encodings.insert({}{}, {});", config.var_name, key_var_name, - if key_type.encoding_var_is_copy() { "" } else { ".clone()" }, - tuple_str(value_encs.iter().map(|enc| enc.field_name.clone()).collect()))); + if key_type.encoding_var_is_copy() { + "" + } else { + ".clone()" + }, + tuple_str( + value_encs + .iter() + .map(|enc| enc.field_name.clone()) + .collect() + ) + )); } } deser_code.content.push_block(deser_loop); if CLI_ARGS.preserve_encodings { - config.final_exprs.push(format!("{}_encoding", config.var_name)); + config + .final_exprs + .push(format!("{}_encoding", config.var_name)); if !key_encs.is_empty() { - config.final_exprs.push(format!("{}_key_encodings", config.var_name)); + config + .final_exprs + .push(format!("{}_key_encodings", config.var_name)); } if !value_encs.is_empty() { - config.final_exprs.push(format!("{}_value_encodings", config.var_name)); + config + .final_exprs + .push(format!("{}_value_encodings", config.var_name)); } - deser_code.content.line(&format!("{}{}{}", before_after.before_str(false), final_expr(config.final_exprs, Some(table_var)), before_after.after_str(false))); + deser_code.content.line(&format!( + "{}{}{}", + before_after.before_str(false), + final_expr(config.final_exprs, Some(table_var)), + before_after.after_str(false) + )); } else { - deser_code.content.line(&format!("{}{}{}", before_after.before_str(false), table_var, before_after.after_str(false))); + deser_code.content.line(&format!( + "{}{}{}", + before_after.before_str(false), + table_var, + before_after.after_str(false) + )); } } deser_code.throws = true; - }, + } SerializingRustType::Root(ConceptualRustType::Alias(_ident, ty)) => { - self - .generate_deserialize(types, (&**ty).into(), before_after, config) + self.generate_deserialize(types, (&**ty).into(), before_after, config) .add_to_code(&mut deser_code); - }, + } SerializingRustType::EncodingOperation(CBOREncodingOperation::CBORBytes, child) => { if CLI_ARGS.preserve_encodings { - config.final_exprs.push(format!("StringEncoding::from({}_bytes_encoding)", config.var_name)); - deser_code.content.line(&format!("let ({}_bytes, {}_bytes_encoding) = raw.bytes_sz()?;", config.var_name, config.var_name)); + config.final_exprs.push(format!( + "StringEncoding::from({}_bytes_encoding)", + config.var_name + )); + deser_code.content.line(&format!( + "let ({}_bytes, {}_bytes_encoding) = raw.bytes_sz()?;", + config.var_name, config.var_name + )); } else { - deser_code.content.line(&format!("let {}_bytes = raw.bytes()?;", config.var_name)); + deser_code + .content + .line(&format!("let {}_bytes = raw.bytes()?;", config.var_name)); }; let name_overload = "inner_de"; - deser_code.content.line(&format!("let {} = &mut Deserializer::from(std::io::Cursor::new({}_bytes));", name_overload, config.var_name)); - self - .generate_deserialize( - types, - *child, - before_after, - config.overload_deserializer(name_overload)) - .add_to_code(&mut deser_code); + deser_code.content.line(&format!( + "let {} = &mut Deserializer::from(std::io::Cursor::new({}_bytes));", + name_overload, config.var_name + )); + self.generate_deserialize( + types, + *child, + before_after, + config.overload_deserializer(name_overload), + ) + .add_to_code(&mut deser_code); deser_code.throws = true; - }, + } SerializingRustType::EncodingOperation(CBOREncodingOperation::Tagged(tag), child) => { if config.optional_field { deser_code.content.line("read_len.read_elems(1)?;"); deser_code.read_len_used = true; } let mut tag_check = if CLI_ARGS.preserve_encodings { - let mut tag_check = Block::new(&format!("{}match {}.tag_sz()?", before_after.before, deserializer_name)); + let mut tag_check = Block::new(&format!( + "{}match {}.tag_sz()?", + before_after.before, deserializer_name + )); config.final_exprs.push("Some(tag_enc)".to_owned()); let some_deser_code = self .generate_deserialize( types, *child, DeserializeBeforeAfter::new("", "", before_after.expects_result), - config.optional_field(false)) + config.optional_field(false), + ) .mark_and_extract_content(&mut deser_code); if let Some(single_line) = some_deser_code.as_single_line() { tag_check.line(format!("({}, tag_enc) => {},", tag, single_line)); @@ -1782,14 +2332,18 @@ impl GenerationScope { } tag_check } else { - let mut tag_check = Block::new(&format!("{}match {}.tag()?", before_after.before, deserializer_name)); - + let mut tag_check = Block::new(&format!( + "{}match {}.tag()?", + before_after.before, deserializer_name + )); + let some_deser_code = self .generate_deserialize( types, *child, DeserializeBeforeAfter::new("", "", before_after.expects_result), - config.optional_field(false)) + config.optional_field(false), + ) .mark_and_extract_content(&mut deser_code); if let Some(single_line) = some_deser_code.as_single_line() { tag_check.line(format!("{} => {},", tag, single_line)); @@ -1809,7 +2363,7 @@ impl GenerationScope { tag_check.after(&before_after.after); deser_code.content.push_block(tag_check); deser_code.throws = true; - }, + } } deser_code } @@ -1823,15 +2377,25 @@ impl GenerationScope { ConceptualRustType::Fixed(_) => true, ConceptualRustType::Primitive(_) => true, ConceptualRustType::Rust(ident) => self.deserialize_generated(ident), - ConceptualRustType::Array(ty) => self.deserialize_generated_for_type(&ty.conceptual_type), - ConceptualRustType::Map(k, v) => self.deserialize_generated_for_type(&k.conceptual_type) && self.deserialize_generated_for_type(&v.conceptual_type), - ConceptualRustType::Optional(ty) => self.deserialize_generated_for_type(&ty.conceptual_type), + ConceptualRustType::Array(ty) => { + self.deserialize_generated_for_type(&ty.conceptual_type) + } + ConceptualRustType::Map(k, v) => { + self.deserialize_generated_for_type(&k.conceptual_type) + && self.deserialize_generated_for_type(&v.conceptual_type) + } + ConceptualRustType::Optional(ty) => { + self.deserialize_generated_for_type(&ty.conceptual_type) + } ConceptualRustType::Alias(_ident, ty) => self.deserialize_generated_for_type(ty), } } fn dont_generate_deserialize(&mut self, name: &RustIdent, reason: String) { - self.no_deser_reasons.entry(name.clone()).or_default().push(reason); + self.no_deser_reasons + .entry(name.clone()) + .or_default() + .push(reason); } pub fn print_structs_without_deserialize(&self) { @@ -1845,7 +2409,13 @@ impl GenerationScope { // TODO: repurpose this for type choices (not group choices) // TODO: make this its own function - there's no reason for this to be a method - fn generate_type_choices_from_variants(&mut self, types: &IntermediateTypes, name: &RustIdent, variants: &Vec, tag: Option) { + fn generate_type_choices_from_variants( + &mut self, + types: &IntermediateTypes, + name: &RustIdent, + variants: &Vec, + tag: Option, + ) { // Rust only generate_enum(self, types, &name, &variants, None, true, tag); if CLI_ARGS.wasm { @@ -1869,14 +2439,21 @@ impl GenerationScope { new_func.arg(&variant_arg, &variant.rust_type.for_wasm_param()); } if variant.rust_type.is_fixed_value() { - new_func.line(format!("Self(core::{}::new_{}())", name, variant.name_as_var())); + new_func.line(format!( + "Self(core::{}::new_{}())", + name, + variant.name_as_var() + )); } else { - let from_wasm_expr = variant.rust_type.from_wasm_boundary_clone(&variant_arg, can_fail); + let from_wasm_expr = variant + .rust_type + .from_wasm_boundary_clone(&variant_arg, can_fail); new_func.line(format!( "Self(core::{}::new_{}({}))", name, variant.name_as_var(), - ToWasmBoundaryOperations::format(from_wasm_expr.into_iter()))); + ToWasmBoundaryOperations::format(from_wasm_expr.into_iter()) + )); } wrapper.s_impl.push_fn(new_func); } @@ -1886,16 +2463,19 @@ impl GenerationScope { } // generate array type ie [Foo] generates Foos if not already created - fn generate_array_type(&mut self, types: &IntermediateTypes, element_type: RustType, array_type_ident: &RustIdent) { + fn generate_array_type( + &mut self, + types: &IntermediateTypes, + element_type: RustType, + array_type_ident: &RustIdent, + ) { if self.already_generated.insert(array_type_ident.clone()) { let inner_type = element_type.name_as_rust_array(true); let mut wrapper = create_base_wasm_struct(self, array_type_ident, false); wrapper.s.tuple_field(None, &inner_type); // other functions let mut new_func = codegen::Function::new("new"); - new_func - .vis("pub") - .ret("Self"); + new_func.vis("pub").ret("Self"); new_func.line("Self(Vec::new())"); wrapper.s_impl.push_fn(new_func); wrapper @@ -1920,7 +2500,14 @@ impl GenerationScope { .vis("pub") .arg_mut_self() .arg("elem", element_type.for_wasm_param()) - .line(format!("self.0.push({});", ToWasmBoundaryOperations::format(element_type.from_wasm_boundary_clone("elem", false).into_iter()))); + .line(format!( + "self.0.push({});", + ToWasmBoundaryOperations::format( + element_type + .from_wasm_boundary_clone("elem", false) + .into_iter() + ) + )); wrapper.add_conversion_methods(&inner_type); wrapper.push(self, types); } @@ -1945,7 +2532,8 @@ fn encoding_var_macros(used_in_key: bool) -> String { .iter() .map(|derive| format!("{}=\"ignore\"", derive)) .collect::>() - .join(", ")) + .join(", ") + ) } else { String::new() }; @@ -1955,21 +2543,43 @@ fn encoding_var_macros(used_in_key: bool) -> String { ret } -fn start_len(body: &mut dyn CodeBlock, rep: Representation, serializer_use: &str, encoding_var: &str, len_expr: &str) { +fn start_len( + body: &mut dyn CodeBlock, + rep: Representation, + serializer_use: &str, + encoding_var: &str, + len_expr: &str, +) { let rep_str = match rep { Representation::Array => "array", Representation::Map => "map", }; if CLI_ARGS.preserve_encodings { - body.line(&format!("{}.write_{}_sz({}.to_len_sz({}{}))?;", serializer_use, rep_str, encoding_var, len_expr, canonical_param())); + body.line(&format!( + "{}.write_{}_sz({}.to_len_sz({}{}))?;", + serializer_use, + rep_str, + encoding_var, + len_expr, + canonical_param() + )); } else { - body.line(&format!("{}.write_{}(cbor_event::Len::Len({}))?;", serializer_use, rep_str, len_expr)); + body.line(&format!( + "{}.write_{}(cbor_event::Len::Len({}))?;", + serializer_use, rep_str, len_expr + )); } } fn end_len(body: &mut dyn CodeBlock, serializer_use: &str, encoding_var: &str, is_end: bool) { if CLI_ARGS.preserve_encodings { - body.line(&format!("{}.end({}{}){}", encoding_var, serializer_use, canonical_param(), if is_end { "" } else { "?;" })); + body.line(&format!( + "{}.end({}{}){}", + encoding_var, + serializer_use, + canonical_param(), + if is_end { "" } else { "?;" } + )); } else { if is_end { body.line("Ok(serializer)"); @@ -1977,31 +2587,58 @@ fn end_len(body: &mut dyn CodeBlock, serializer_use: &str, encoding_var: &str, i } } -fn write_using_sz(body: &mut dyn CodeBlock, func: &str, serializer_use: &str, expr: &str, fit_sz_expr: &str, line_ender: &str, encoding_var: &str) { +fn write_using_sz( + body: &mut dyn CodeBlock, + func: &str, + serializer_use: &str, + expr: &str, + fit_sz_expr: &str, + line_ender: &str, + encoding_var: &str, +) { if CLI_ARGS.preserve_encodings { - body.line( - &format!( - "{}.{}_sz({}, fit_sz({}, {}{})){}", - serializer_use, func, expr, fit_sz_expr, encoding_var, canonical_param(), line_ender)); + body.line(&format!( + "{}.{}_sz({}, fit_sz({}, {}{})){}", + serializer_use, + func, + expr, + fit_sz_expr, + encoding_var, + canonical_param(), + line_ender + )); } else { - body.line(&format!("{}.{}({}){}", serializer_use, func, expr, line_ender)); + body.line(&format!( + "{}.{}({}){}", + serializer_use, func, expr, line_ender + )); } } -fn write_string_sz(body: &mut dyn CodeBlock, func: &str, serializer_use: &str, expr: &str, line_ender: &str, encoding_var: &str) { +fn write_string_sz( + body: &mut dyn CodeBlock, + func: &str, + serializer_use: &str, + expr: &str, + line_ender: &str, + encoding_var: &str, +) { if CLI_ARGS.preserve_encodings { - body.line( - &format!( - "{}.{}_sz(&{}, {}.to_str_len_sz({}.len() as u64{})){}", - serializer_use, - func, - expr, - encoding_var, - expr, - canonical_param(), - line_ender)); + body.line(&format!( + "{}.{}_sz(&{}, {}.to_str_len_sz({}.len() as u64{})){}", + serializer_use, + func, + expr, + encoding_var, + expr, + canonical_param(), + line_ender + )); } else { - body.line(&format!("{}.{}(&{}){}", serializer_use, func, expr, line_ender)); + body.line(&format!( + "{}.{}(&{}){}", + serializer_use, func, expr, line_ender + )); } } @@ -2036,7 +2673,10 @@ trait CodeBlock { fn push_block(&mut self, block: codegen::Block) -> &mut dyn CodeBlock; - fn push_all(&mut self, contents: BlocksOrLines) -> &mut dyn CodeBlock where Self: Sized { + fn push_all(&mut self, contents: BlocksOrLines) -> &mut dyn CodeBlock + where + Self: Sized, + { for content in contents.0 { match content { BlockOrLine::Line(line) => self.line(&line), @@ -2061,7 +2701,7 @@ impl CodeBlock for codegen::Block { fn line(&mut self, line: &str) -> &mut dyn CodeBlock { self.line(line) } - + fn push_block(&mut self, block: codegen::Block) -> &mut dyn CodeBlock { self.push_block(block) } @@ -2072,7 +2712,7 @@ impl CodeBlock for BlocksOrLines { self.0.push(BlockOrLine::Line(line.to_owned())); self } - + fn push_block(&mut self, block: codegen::Block) -> &mut dyn CodeBlock { self.0.push(BlockOrLine::Block(block)); self @@ -2095,7 +2735,10 @@ impl DataType for codegen::Enum { } } -fn create_base_rust_struct<'a>(types: &IntermediateTypes<'a>, ident: &RustIdent) -> (codegen::Struct, codegen::Impl) { +fn create_base_rust_struct<'a>( + types: &IntermediateTypes<'a>, + ident: &RustIdent, +) -> (codegen::Struct, codegen::Impl) { let name = &ident.to_string(); let mut s = codegen::Struct::new(name); add_struct_derives(&mut s, types.used_as_key(ident), false); @@ -2145,7 +2788,7 @@ impl<'a> WasmWrapper<'a> { .arg("native", native_name) .ret("Self") .line("Self(native)"); - self.from_wasm = Some(from_wasm); + self.from_wasm = Some(from_wasm); let mut from_native = codegen::Impl::new(native_name); from_native .impl_trait(format!("From<{}>", self.ident.to_string())) @@ -2153,7 +2796,7 @@ impl<'a> WasmWrapper<'a> { .arg("wasm", self.ident.to_string()) .ret("Self") .line("wasm.0"); - self.from_native = Some(from_native); + self.from_native = Some(from_native); let mut as_ref = codegen::Impl::new(self.ident.to_string()); as_ref .impl_trait(format!("AsRef<{}>", native_name)) @@ -2161,15 +2804,18 @@ impl<'a> WasmWrapper<'a> { .arg_ref_self() .ret(&format!("&{}", native_name)) .line("&self.0"); - self.as_ref = Some(as_ref); + self.as_ref = Some(as_ref); } } -fn create_base_wasm_struct<'a>(gen_scope: &GenerationScope, ident: &'a RustIdent, exists_in_rust: bool) -> WasmWrapper<'a> { +fn create_base_wasm_struct<'a>( + gen_scope: &GenerationScope, + ident: &'a RustIdent, + exists_in_rust: bool, +) -> WasmWrapper<'a> { let name = &ident.to_string(); let mut s = codegen::Struct::new(name); - s - .vis("pub") + s.vis("pub") .derive("Clone") .derive("Debug") .attr("wasm_bindgen"); @@ -2181,10 +2827,7 @@ fn create_base_wasm_struct<'a>(gen_scope: &GenerationScope, ident: &'a RustIdent if exists_in_rust { if CLI_ARGS.to_from_bytes_methods { let mut to_bytes = codegen::Function::new("to_cbor_bytes"); - to_bytes - .ret("Vec") - .arg_ref_self() - .vis("pub"); + to_bytes.ret("Vec").arg_ref_self().vis("pub"); if CLI_ARGS.preserve_encodings && CLI_ARGS.canonical_form { to_bytes.line("core::serialization::Serialize::to_cbor_bytes(&self.0)"); let mut to_canonical_bytes = codegen::Function::new("to_canonical_cbor_bytes"); @@ -2194,8 +2837,7 @@ fn create_base_wasm_struct<'a>(gen_scope: &GenerationScope, ident: &'a RustIdent .vis("pub") .line("Serialize::to_canonical_cbor_bytes(&self.0)"); } else { - to_bytes - .line("core::serialization::ToCBORBytes::to_cbor_bytes(&self.0)"); + to_bytes.line("core::serialization::ToCBORBytes::to_cbor_bytes(&self.0)"); } s_impl.push_fn(to_bytes); if gen_scope.deserialize_generated(ident) { @@ -2228,7 +2870,6 @@ fn create_base_wasm_struct<'a>(gen_scope: &GenerationScope, ident: &'a RustIdent .arg("json", "&str") .vis("pub") .line("serde_json::from_str(json).map(Self).map_err(|e| JsValue::from_str(&format!(\"from_json: {}\", e)))"); - } } WasmWrapper { @@ -2243,7 +2884,11 @@ fn create_base_wasm_struct<'a>(gen_scope: &GenerationScope, ident: &'a RustIdent /// default_structure will have it be a DIRECT wrapper with a tuple field of core::{ident} /// this will include generating to/from traits automatically -fn create_base_wasm_wrapper<'a>(gen_scope: &GenerationScope, ident: &'a RustIdent, default_structure: bool) -> WasmWrapper<'a> { +fn create_base_wasm_wrapper<'a>( + gen_scope: &GenerationScope, + ident: &'a RustIdent, + default_structure: bool, +) -> WasmWrapper<'a> { assert!(CLI_ARGS.wasm); let mut base = create_base_wasm_struct(gen_scope, ident, true); let name = &ident.to_string(); @@ -2258,7 +2903,13 @@ fn create_base_wasm_wrapper<'a>(gen_scope: &GenerationScope, ident: &'a RustIden // Alway creates directly just Serialize impl. Shortcut for create_serialize_impls when // we know we won't need the SerializeEmbeddedGroup impl. // See comments for create_serialize_impls for usage. -fn create_serialize_impl(ident: &RustIdent, rep: Option, tag: Option, definite_len: &str, use_this_encoding: Option<&str>) -> (codegen::Function, codegen::Impl) { +fn create_serialize_impl( + ident: &RustIdent, + rep: Option, + tag: Option, + definite_len: &str, + use_this_encoding: Option<&str>, +) -> (codegen::Function, codegen::Impl) { match create_serialize_impls(ident, rep, tag, definite_len, use_this_encoding, false) { (ser_func, ser_impl, None) => (ser_func, ser_impl), (_ser_func, _ser_impl, Some(_embedded_impl)) => unreachable!(), @@ -2275,7 +2926,14 @@ fn create_serialize_impl(ident: &RustIdent, rep: Option, tag: Op // In the second case (no embedded), only the array/map tag + length are written and the user will // want to write the rest of serialize() after that. // * `use_this_encoding` - If present, references a variable (must be bool and in this scope) to toggle definite vs indefinite (e.g. for PRESERVE_ENCODING) -fn create_serialize_impls(ident: &RustIdent, rep: Option, tag: Option, definite_len: &str, use_this_encoding: Option<&str>, generate_serialize_embedded: bool) -> (codegen::Function, codegen::Impl, Option) { +fn create_serialize_impls( + ident: &RustIdent, + rep: Option, + tag: Option, + definite_len: &str, + use_this_encoding: Option<&str>, + generate_serialize_embedded: bool, +) -> (codegen::Function, codegen::Impl, Option) { if generate_serialize_embedded { // This is not necessarily a problem but we should investigate this case to ensure we're not calling // (de)serialize_as_embedded without (de)serializing the tag @@ -2286,26 +2944,42 @@ fn create_serialize_impls(ident: &RustIdent, rep: Option, tag: O let mut ser_func = make_serialization_function("serialize"); if let Some(tag) = tag { let expr = format!("{}u64", tag); - write_using_sz(&mut ser_func, "write_tag", "serializer", &expr, &expr, "?;", "self.encodings.as_ref().map(|encs| encs.tag_encoding).unwrap_or_default()"); + write_using_sz( + &mut ser_func, + "write_tag", + "serializer", + &expr, + &expr, + "?;", + "self.encodings.as_ref().map(|encs| encs.tag_encoding).unwrap_or_default()", + ); } // TODO: do definite length encoding for optional fields too - if let Some (rep) = rep { + if let Some(rep) = rep { if let Some(definite) = use_this_encoding { start_len(&mut ser_func, rep, "serializer", definite, definite_len); } else { let len = cbor_event_len_n(definite_len); match rep { - Representation::Array => ser_func.line(format!("serializer.write_array({})?;", len)), + Representation::Array => { + ser_func.line(format!("serializer.write_array({})?;", len)) + } Representation::Map => ser_func.line(format!("serializer.write_map({})?;", len)), }; } if generate_serialize_embedded { - ser_func.line(format!("self.serialize_as_embedded_group(serializer{})", canonical_param())); + ser_func.line(format!( + "self.serialize_as_embedded_group(serializer{})", + canonical_param() + )); } } else { // not array or map, generate serialize directly if generate_serialize_embedded { - ser_func.line(format!("self.serialize_as_embedded_group(serializer{})", canonical_param())); + ser_func.line(format!( + "self.serialize_as_embedded_group(serializer{})", + canonical_param() + )); } } if generate_serialize_embedded { @@ -2321,47 +2995,62 @@ fn create_serialize_impls(ident: &RustIdent, rep: Option, tag: O fn add_deserialize_initial_len_check(deser_body: &mut dyn CodeBlock, len_info: RustStructCBORLen) { deser_body.line("let mut read_len = CBORReadLen::new(len);"); match len_info { - RustStructCBORLen::Dynamic => /*nothing*/(), + RustStructCBORLen::Dynamic => + /*nothing*/ + { + () + } // TODO: direct check here instead of involving read_len RustStructCBORLen::OptionalFields(mandatory) => { if mandatory != 0 { deser_body.line(&format!("read_len.read_elems({})?;", mandatory)); } - }, + } RustStructCBORLen::Fixed(fixed) => { if fixed != 0 { deser_body.line(&format!("read_len.read_elems({})?;", fixed)); } - }, + } } } -// Adds final Len check if not fixed + reads for the ending Special::Break for Indefinite arrays -fn add_deserialize_final_len_check(deser_body: &mut dyn CodeBlock, rep: Option, len_info: RustStructCBORLen) { +// Adds final Len check if not fixed + reads for the ending Special::Break for Indefinite arrays +fn add_deserialize_final_len_check( + deser_body: &mut dyn CodeBlock, + rep: Option, + len_info: RustStructCBORLen, +) { // We only check for Break for arrays since the implementation for maps uses len to decide // when to stop reading values, since otherwise with optional parameters it doesn't know. // We also can't do it from within deserialize_as_embedded_group() as that interferes with // plain groups nested inside other array groups let ending_check = match len_info { RustStructCBORLen::Fixed(_) => "()", // no need to check - checked at the start - RustStructCBORLen::OptionalFields(_) | - RustStructCBORLen::Dynamic => "read_len.finish()?", + RustStructCBORLen::OptionalFields(_) | RustStructCBORLen::Dynamic => "read_len.finish()?", }; match rep { Some(Representation::Array) => { let mut end_len_check = Block::new("match len"); end_len_check.line(format!("{} => {},", cbor_event_len_n("_"), ending_check)); - let mut indefinite_check = Block::new(&format!("{} => match raw.special()?", cbor_event_len_indef())); + let mut indefinite_check = Block::new(&format!( + "{} => match raw.special()?", + cbor_event_len_indef() + )); indefinite_check.line(format!("CBORSpecial::Break => {},", ending_check)); - indefinite_check.line("_ => return Err(DeserializeFailure::EndingBreakMissing.into()),"); + indefinite_check + .line("_ => return Err(DeserializeFailure::EndingBreakMissing.into()),"); indefinite_check.after(","); end_len_check.push_block(indefinite_check); deser_body.push_block(end_len_check); - }, + } Some(Representation::Map) => { deser_body.line(&format!("{};", ending_check)); - }, - None => /* this should just be for type choices */(), + } + None => + /* this should just be for type choices */ + { + () + } } } @@ -2385,7 +3074,15 @@ fn add_deserialize_final_len_check(deser_body: &mut dyn CodeBlock, rep: Option, tag: Option, len_info: RustStructCBORLen, generate_deserialize_embedded: bool, store_encoding: Option<&str>, deser_body: &mut dyn CodeBlock) -> (codegen::Impl, Option) { +fn create_deserialize_impls( + ident: &RustIdent, + rep: Option, + tag: Option, + len_info: RustStructCBORLen, + generate_deserialize_embedded: bool, + store_encoding: Option<&str>, + deser_body: &mut dyn CodeBlock, +) -> (codegen::Impl, Option) { let name = &ident.to_string(); let mut deser_impl = codegen::Impl::new(name); // TODO: add config param to decide if we want to use our deserialize @@ -2402,7 +3099,7 @@ fn create_deserialize_impls(ident: &RustIdent, rep: Option, tag: tag_check.line(&format!("return Err(DeserializeError::new(\"{}\", DeserializeFailure::TagMismatch{{ found: tag, expected: {} }}));", name, tag)); deser_body.push_block(tag_check); } - if let Some (rep) = rep { + if let Some(rep) = rep { match rep { Representation::Array => { if CLI_ARGS.preserve_encodings { @@ -2412,14 +3109,19 @@ fn create_deserialize_impls(ident: &RustIdent, rep: Option, tag: } if !generate_deserialize_embedded { if let Some(encoding_var_name) = store_encoding { - deser_body.line(&format!("let {}: LenEncoding = len.into();", encoding_var_name)); + deser_body.line(&format!( + "let {}: LenEncoding = len.into();", + encoding_var_name + )); } } add_deserialize_initial_len_check(deser_body, len_info); if generate_deserialize_embedded { - deser_body.line("let ret = Self::deserialize_as_embedded_group(raw, &mut read_len, len);"); + deser_body.line( + "let ret = Self::deserialize_as_embedded_group(raw, &mut read_len, len);", + ); } - }, + } Representation::Map => { if CLI_ARGS.preserve_encodings { deser_body.line("let len = raw.map_sz()?;"); @@ -2428,14 +3130,19 @@ fn create_deserialize_impls(ident: &RustIdent, rep: Option, tag: } if !generate_deserialize_embedded { if let Some(encoding_var_name) = store_encoding { - deser_body.line(&format!("let {}: LenEncoding = len.into();", encoding_var_name)); + deser_body.line(&format!( + "let {}: LenEncoding = len.into();", + encoding_var_name + )); } } add_deserialize_initial_len_check(deser_body, len_info); if generate_deserialize_embedded { - deser_body.line("let ret = Self::deserialize_as_embedded_group(raw, &mut read_len, len);"); + deser_body.line( + "let ret = Self::deserialize_as_embedded_group(raw, &mut read_len, len);", + ); } - }, + } }; } else { panic!("TODO: how should we handle this considering we are dealing with Len?"); @@ -2462,10 +3169,7 @@ fn push_rust_struct( ser_impl: codegen::Impl, ser_embedded_impl: Option, ) { - gen_scope - .rust(types, name) - .push_struct(s) - .push_impl(s_impl); + gen_scope.rust(types, name).push_struct(s).push_impl(s_impl); gen_scope.rust_serialize().push_impl(ser_impl); if let Some(s) = ser_embedded_impl { gen_scope.rust_serialize().push_impl(s); @@ -2476,18 +3180,21 @@ fn push_rust_struct( // without having to put error annotation inside of every single cbor_event call. fn make_err_annotate_block(annotation: &str, before: &str, after: &str) -> Block { let mut if_block = Block::new(&format!("{}(|| -> Result<_, DeserializeError>", before)); - if_block.after(&format!(")().map_err(|e| e.annotate(\"{}\")){}", annotation, after)); + if_block.after(&format!( + ")().map_err(|e| e.annotate(\"{}\")){}", + annotation, after + )); if_block } fn make_deser_loop(len_var: &str, len_expr: &str) -> Block { - Block::new( - &format!( - "while match {} {{ {} => {} < n, {} => true, }}", - len_var, - cbor_event_len_n("n"), - len_expr, - cbor_event_len_indef())) + Block::new(&format!( + "while match {} {{ {} => {} < n, {} => true, }}", + len_var, + cbor_event_len_n("n"), + len_expr, + cbor_event_len_indef() + )) } fn make_deser_loop_break_check() -> Block { @@ -2506,7 +3213,15 @@ pub fn table_type() -> &'static str { } } -fn codegen_table_type(gen_scope: &mut GenerationScope, types: &IntermediateTypes, name: &RustIdent, key_type: RustType, value_type: RustType, tag: Option, exists_in_rust: bool) { +fn codegen_table_type( + gen_scope: &mut GenerationScope, + types: &IntermediateTypes, + name: &RustIdent, + key_type: RustType, + value_type: RustType, + tag: Option, + exists_in_rust: bool, +) { assert!(CLI_ARGS.wasm); assert!(tag.is_none(), "TODO: why is this not used anymore? is it since it's only on the wasm side now so it shouldn't happen now?"); // this would interfere with loop code generation unless we @@ -2530,7 +3245,8 @@ fn codegen_table_type(gen_scope: &mut GenerationScope, types: &IntermediateTypes .line(format!("Self({}::new())", table_type())); wrapper.s_impl.push_fn(new_func); // len - wrapper.s_impl + wrapper + .s_impl .new_fn("len") .vis("pub") .ret("usize") @@ -2544,12 +3260,22 @@ fn codegen_table_type(gen_scope: &mut GenerationScope, types: &IntermediateTypes .arg("key", key_type.for_wasm_param()) .arg("value", value_type.for_wasm_param()) .ret(format!("Option<{}>", value_type.for_wasm_return())) - .line( - format!( - "self.0.insert({}, {}){}", - ToWasmBoundaryOperations::format(key_type.from_wasm_boundary_clone("key", false).into_iter()), - ToWasmBoundaryOperations::format(value_type.from_wasm_boundary_clone("value", false).into_iter()), - if value_type.directly_wasm_exposable() { "" } else { ".map(Into::into)" })); + .line(format!( + "self.0.insert({}, {}){}", + ToWasmBoundaryOperations::format( + key_type.from_wasm_boundary_clone("key", false).into_iter() + ), + ToWasmBoundaryOperations::format( + value_type + .from_wasm_boundary_clone("value", false) + .into_iter() + ), + if value_type.directly_wasm_exposable() { + "" + } else { + ".map(Into::into)" + } + )); // ^ TODO: support failable types everywhere or just force it to be only a detail in the wrapper? wrapper.s_impl.push_fn(insert_func); // get @@ -2570,19 +3296,28 @@ fn codegen_table_type(gen_scope: &mut GenerationScope, types: &IntermediateTypes getter.line(format!( "self.0.get({}){}", key_type.from_wasm_boundary_ref("key"), - if value_type.is_copy() { ".copied()" } else { get_ret_modifier })); + if value_type.is_copy() { + ".copied()" + } else { + get_ret_modifier + } + )); } else { getter.line(format!( "self.0.get(&{}.0){}", key_type.from_wasm_boundary_ref("key"), - if value_type.is_copy() { ".copied()" } else { get_ret_modifier })); + if value_type.is_copy() { + ".copied()" + } else { + get_ret_modifier + } + )); } wrapper.s_impl.push_fn(getter); // keys let keys_type = ConceptualRustType::Array(Box::new(key_type.clone())); let mut keys = codegen::Function::new("keys"); - keys - .arg_ref_self() + keys.arg_ref_self() .ret(keys_type.for_wasm_return()) .vis("pub"); if keys_type.directly_wasm_exposable() { @@ -2593,7 +3328,10 @@ fn codegen_table_type(gen_scope: &mut GenerationScope, types: &IntermediateTypes }; keys.line(format!("self.0{}.collect::>()", key_clone)); } else { - keys.line(format!("{}(self.0.iter().map(|(k, _v)| k.clone()).collect::>())", keys_type.for_wasm_return())); + keys.line(format!( + "{}(self.0.iter().map(|(k, _v)| k.clone()).collect::>())", + keys_type.for_wasm_return() + )); } wrapper.s_impl.push_fn(keys); wrapper.add_conversion_methods(&inner_type); @@ -2661,7 +3399,14 @@ fn encoding_fields_impl(name: &str, ty: SerializingRustType) -> Vec>().join(", ")) + format!( + "({})", + inner_encs + .iter() + .map(|key_enc| key_enc.type_name.clone()) + .collect::>() + .join(", ") + ) }; vec![ base, @@ -2673,16 +3418,14 @@ fn encoding_fields_impl(name: &str, ty: SerializingRustType) -> Vec { - let mut encs = vec![ - EncodingField { - field_name: format!("{}_encoding", name), - type_name: "LenEncoding".to_owned(), - default_expr: "LenEncoding::default()", - inner: Vec::new(), - } - ]; + let mut encs = vec![EncodingField { + field_name: format!("{}_encoding", name), + type_name: "LenEncoding".to_owned(), + default_expr: "LenEncoding::default()", + inner: Vec::new(), + }]; let key_encs = encoding_fields_impl(&format!("{}_key", name), (&**k).into()); let val_encs = encoding_fields_impl(&format!("{}_value", name), (&**v).into()); @@ -2690,11 +3433,22 @@ fn encoding_fields_impl(name: &str, ty: SerializingRustType) -> Vec>().join(", ")) + format!( + "({})", + key_encs + .iter() + .map(|key_enc| key_enc.type_name.clone()) + .collect::>() + .join(", ") + ) }; encs.push(EncodingField { field_name: format!("{}_key_encodings", name), - type_name: format!("BTreeMap<{}, {}>", k.for_rust_member(false), type_name_value), + type_name: format!( + "BTreeMap<{}, {}>", + k.for_rust_member(false), + type_name_value + ), default_expr: "BTreeMap::new()", inner: key_encs, }); @@ -2704,68 +3458,99 @@ fn encoding_fields_impl(name: &str, ty: SerializingRustType) -> Vec>().join(", ")) + format!( + "({})", + val_encs + .iter() + .map(|val_enc| val_enc.type_name.clone()) + .collect::>() + .join(", ") + ) }; encs.push(EncodingField { field_name: format!("{}_value_encodings", name), - type_name: format!("BTreeMap<{}, {}>", k.for_rust_member(false), type_name_value), + type_name: format!( + "BTreeMap<{}, {}>", + k.for_rust_member(false), + type_name_value + ), default_expr: "BTreeMap::new()", inner: val_encs, }); } encs - }, + } SerializingRustType::Root(ConceptualRustType::Primitive(p)) => match p { - Primitive::Bytes | - Primitive::Str => vec![ - EncodingField { - field_name: format!("{}_encoding", name), - type_name: "StringEncoding".to_owned(), - default_expr: "StringEncoding::default()", - inner: Vec::new(), - } - ], - Primitive::I8 | - Primitive::I16 | - Primitive::I32 | - Primitive::I64 | - Primitive::N64 | - Primitive::U8 | - Primitive::U16 | - Primitive::U32 | - Primitive::U64 | - Primitive::F32 | - Primitive::F64 => vec![ - EncodingField { - field_name: format!("{}_encoding", name), - type_name: "Option".to_owned(), - default_expr: "None", - inner: Vec::new(), - } - ], - Primitive::Bool => /* bool only has 1 encoding */vec![], + Primitive::Bytes | Primitive::Str => vec![EncodingField { + field_name: format!("{}_encoding", name), + type_name: "StringEncoding".to_owned(), + default_expr: "StringEncoding::default()", + inner: Vec::new(), + }], + Primitive::I8 + | Primitive::I16 + | Primitive::I32 + | Primitive::I64 + | Primitive::N64 + | Primitive::U8 + | Primitive::U16 + | Primitive::U32 + | Primitive::U64 + | Primitive::F32 + | Primitive::F64 => vec![EncodingField { + field_name: format!("{}_encoding", name), + type_name: "Option".to_owned(), + default_expr: "None", + inner: Vec::new(), + }], + Primitive::Bool => + /* bool only has 1 encoding */ + { + vec![] + } }, SerializingRustType::Root(ConceptualRustType::Fixed(f)) => match f { - FixedValue::Bool(_) | - FixedValue::Null => vec![], - FixedValue::Nint(_) => encoding_fields_impl(name, (&ConceptualRustType::Primitive(Primitive::I64)).into()), - FixedValue::Uint(_) => encoding_fields_impl(name, (&ConceptualRustType::Primitive(Primitive::U64)).into()), - FixedValue::Float(_) => encoding_fields_impl(name, (&ConceptualRustType::Primitive(Primitive::F64)).into()), - FixedValue::Text(_) => encoding_fields_impl(name, (&ConceptualRustType::Primitive(Primitive::Str)).into()), + FixedValue::Bool(_) | FixedValue::Null => vec![], + FixedValue::Nint(_) => encoding_fields_impl( + name, + (&ConceptualRustType::Primitive(Primitive::I64)).into(), + ), + FixedValue::Uint(_) => encoding_fields_impl( + name, + (&ConceptualRustType::Primitive(Primitive::U64)).into(), + ), + FixedValue::Float(_) => encoding_fields_impl( + name, + (&ConceptualRustType::Primitive(Primitive::F64)).into(), + ), + FixedValue::Text(_) => encoding_fields_impl( + name, + (&ConceptualRustType::Primitive(Primitive::Str)).into(), + ), }, - SerializingRustType::Root(ConceptualRustType::Alias(_, _)) => panic!("resolve types before calling this"), - SerializingRustType::Root(ConceptualRustType::Optional(ty)) => encoding_fields(name, ty, false), + SerializingRustType::Root(ConceptualRustType::Alias(_, _)) => { + panic!("resolve types before calling this") + } + SerializingRustType::Root(ConceptualRustType::Optional(ty)) => { + encoding_fields(name, ty, false) + } SerializingRustType::Root(ConceptualRustType::Rust(_)) => vec![], SerializingRustType::EncodingOperation(CBOREncodingOperation::Tagged(tag), child) => { - let mut encs = encoding_fields_impl(&format!("{}_tag", name), (&ConceptualRustType::Fixed(FixedValue::Uint(*tag))).into()); + let mut encs = encoding_fields_impl( + &format!("{}_tag", name), + (&ConceptualRustType::Fixed(FixedValue::Uint(*tag))).into(), + ); encs.append(&mut encoding_fields_impl(name, *child)); encs - }, + } SerializingRustType::EncodingOperation(CBOREncodingOperation::CBORBytes, child) => { - let mut encs = encoding_fields_impl(&format!("{}_bytes", name), (&ConceptualRustType::Primitive(Primitive::Bytes)).into()); + let mut encs = encoding_fields_impl( + &format!("{}_bytes", name), + (&ConceptualRustType::Primitive(Primitive::Bytes)).into(), + ); encs.append(&mut encoding_fields_impl(name, *child)); encs - }, + } } } @@ -2796,14 +3581,18 @@ fn tuple_str(strs: Vec) -> String { } } -fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, name: &RustIdent, tag: Option, record: &RustRecord) { +fn codegen_struct( + gen_scope: &mut GenerationScope, + types: &IntermediateTypes, + name: &RustIdent, + tag: Option, + record: &RustRecord, +) { // wasm wrapper if CLI_ARGS.wasm { let mut wrapper = create_base_wasm_wrapper(gen_scope, name, true); let mut wasm_new = codegen::Function::new("new"); - wasm_new - .ret("Self") - .vis("pub"); + wasm_new.ret("Self").vis("pub"); let mut wasm_new_args = Vec::new(); for field in &record.fields { // Fixed values don't need constructors or getters or fields in the rust code @@ -2819,35 +3608,55 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na setter.line(format!( "self.0.{} = {}", field.name, - ToWasmBoundaryOperations::format(field.rust_type.from_wasm_boundary_clone(&field.name, false).into_iter()))); + ToWasmBoundaryOperations::format( + field + .rust_type + .from_wasm_boundary_clone(&field.name, false) + .into_iter() + ) + )); } else { setter.line(format!( "self.0.{} = Some({})", field.name, - ToWasmBoundaryOperations::format(field.rust_type.from_wasm_boundary_clone(&field.name, false).into_iter()))); + ToWasmBoundaryOperations::format( + field + .rust_type + .from_wasm_boundary_clone(&field.name, false) + .into_iter() + ) + )); } // ^ TODO: check types.can_new_fail(&field.name) wrapper.s_impl.push_fn(setter); // getter let mut getter = codegen::Function::new(&field.name); - getter - .arg_ref_self() - .vis("pub"); + getter.arg_ref_self().vis("pub"); if field.rust_type.default.is_some() { - getter - .ret(field.rust_type.for_wasm_return()) - .line(field.rust_type.to_wasm_boundary(&format!("self.0.{}", field.name), false)); + getter.ret(field.rust_type.for_wasm_return()).line( + field + .rust_type + .to_wasm_boundary(&format!("self.0.{}", field.name), false), + ); } else { getter .ret(format!("Option<{}>", field.rust_type.for_wasm_return())) - .line(field.rust_type.to_wasm_boundary_optional(&format!("self.0.{}", field.name), false)); + .line(field.rust_type.to_wasm_boundary_optional( + &format!("self.0.{}", field.name), + false, + )); } wrapper.s_impl.push_fn(getter); } else { // new wasm_new.arg(&field.name, field.rust_type.for_wasm_param()); - wasm_new_args.push(ToWasmBoundaryOperations::format(field.rust_type.from_wasm_boundary_clone(&field.name, false).into_iter())); + wasm_new_args.push(ToWasmBoundaryOperations::format( + field + .rust_type + .from_wasm_boundary_clone(&field.name, false) + .into_iter(), + )); // ^ TODO: check types.can_new_fail(&field.name) // do we want setters here later for mandatory types covered by new? // getter @@ -2856,47 +3665,73 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na .arg_ref_self() .ret(field.rust_type.for_wasm_return()) .vis("pub") - .line(field.rust_type.to_wasm_boundary(&format!("self.0.{}", field.name), false)); + .line( + field + .rust_type + .to_wasm_boundary(&format!("self.0.{}", field.name), false), + ); wrapper.s_impl.push_fn(getter); } } } - wasm_new.line(format!("Self(core::{}::new({}))", name, wasm_new_args.join(", "))); + wasm_new.line(format!( + "Self(core::{}::new({}))", + name, + wasm_new_args.join(", ") + )); wrapper.s_impl.push_fn(wasm_new); wrapper.push(gen_scope, types); } - + // Rust-only for the rest of this function // Struct (fields) + constructor let (mut native_struct, mut native_impl) = create_base_rust_struct(types, name); native_struct.vis("pub"); let mut native_new = codegen::Function::new("new"); - native_new - .ret("Self") - .vis("pub"); + native_new.ret("Self").vis("pub"); let mut native_new_block = Block::new("Self"); // for clippy we generate a Default impl if new has no args let mut new_arg_count = 0; for field in &record.fields { if !gen_scope.deserialize_generated_for_type(&field.rust_type.conceptual_type) { - gen_scope.dont_generate_deserialize(name, format!("field {}: {} couldn't generate serialize", field.name, field.rust_type.for_rust_member(false))); + gen_scope.dont_generate_deserialize( + name, + format!( + "field {}: {} couldn't generate serialize", + field.name, + field.rust_type.for_rust_member(false) + ), + ); } // Fixed values only exist in (de)serialization code (outside of preserve-encodings=true) if !field.rust_type.is_fixed_value() { if let Some(default_value) = &field.rust_type.default { // field - native_struct.field(&format!("pub {}", field.name), field.rust_type.for_rust_member(false)); + native_struct.field( + &format!("pub {}", field.name), + field.rust_type.for_rust_member(false), + ); // new - native_new_block.line(format!("{}: {},", field.name, default_value.to_primitive_str_assign())); + native_new_block.line(format!( + "{}: {},", + field.name, + default_value.to_primitive_str_assign() + )); } else if field.optional { // field - native_struct.field(&format!("pub {}", field.name), format!("Option<{}>", field.rust_type.for_rust_member(false))); + native_struct.field( + &format!("pub {}", field.name), + format!("Option<{}>", field.rust_type.for_rust_member(false)), + ); // new native_new_block.line(format!("{}: None,", field.name)); } else { // field - native_struct.field(&format!("pub {}", field.name), field.rust_type.for_rust_member(false)); + native_struct.field( + &format!("pub {}", field.name), + field.rust_type.for_rust_member(false), + ); // new native_new.arg(&field.name, field.rust_type.for_rust_move()); new_arg_count += 1; @@ -2906,7 +3741,13 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na } let len_encoding_var = if CLI_ARGS.preserve_encodings { let encoding_name = RustIdent::new(CDDLIdent::new(format!("{}Encoding", name))); - native_struct.field(&format!("{}pub encodings", encoding_var_macros(types.used_as_key(name))), format!("Option<{}>", encoding_name)); + native_struct.field( + &format!( + "{}pub encodings", + encoding_var_macros(types.used_as_key(name)) + ), + format!("Option<{}>", encoding_name), + ); native_new_block.line("encodings: None,"); let mut encoding_struct = make_encoding_struct(&encoding_name.to_string()); @@ -2919,8 +3760,15 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na } for field in &record.fields { // even fixed values still need to keep track of their encodings - for field_enc in encoding_fields(&field.name, &field.rust_type.clone().resolve_aliases(), true) { - encoding_struct.field(&format!("pub {}", field_enc.field_name), field_enc.type_name); + for field_enc in encoding_fields( + &field.name, + &field.rust_type.clone().resolve_aliases(), + true, + ) { + encoding_struct.field( + &format!("pub {}", field_enc.field_name), + field_enc.type_name, + ); } if record.rep == Representation::Map { let key_enc = key_encoding_field(&field.name, field.key.as_ref().unwrap()); @@ -2938,19 +3786,26 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na native_impl.push_fn(native_new); // Serialization (via rust traits) - includes Deserialization too - let (ser_func, mut ser_impl, mut ser_embedded_impl) = - create_serialize_impls( - name, - Some(record.rep), - tag, - &record.definite_info(types), - len_encoding_var.map(|var| format!("self.encodings.as_ref().map(|encs| encs.{}).unwrap_or_default()", var)).as_deref(), - types.is_plain_group(name)); + let (ser_func, mut ser_impl, mut ser_embedded_impl) = create_serialize_impls( + name, + Some(record.rep), + tag, + &record.definite_info(types), + len_encoding_var + .map(|var| { + format!( + "self.encodings.as_ref().map(|encs| encs.{}).unwrap_or_default()", + var + ) + }) + .as_deref(), + types.is_plain_group(name), + ); let mut ser_func = match ser_embedded_impl { Some(_) => { ser_impl.push_fn(ser_func); make_serialization_function("serialize_as_embedded_group") - }, + } None => ser_func, }; let mut deser_code = DeserializationCode::default(); @@ -2960,29 +3815,57 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na let mut deser_ret = Block::new(&format!("Ok({}", name)); for field in record.fields.iter() { if field.optional { - let (optional_field_check, field_expr, expr_is_ref) = if let Some(default_value) = &field.rust_type.default { - (if CLI_ARGS.preserve_encodings { - format!("if self.{} != {} || self.encodings.map(|encs| encs.{}_default_present).unwrap_or(false)", field.name, default_value.to_primitive_str_compare(), field.name) - } else { - format!("if self.{} != {}", field.name, default_value.to_primitive_str_compare()) - }, format!("self.{}", field.name), false) + let (optional_field_check, field_expr, expr_is_ref) = if let Some( + default_value, + ) = + &field.rust_type.default + { + ( + if CLI_ARGS.preserve_encodings { + format!("if self.{} != {} || self.encodings.map(|encs| encs.{}_default_present).unwrap_or(false)", field.name, default_value.to_primitive_str_compare(), field.name) + } else { + format!( + "if self.{} != {}", + field.name, + default_value.to_primitive_str_compare() + ) + }, + format!("self.{}", field.name), + false, + ) } else { - (format!("if let Some(field) = &self.{}", field.name), "field".to_owned(), true) + ( + format!("if let Some(field) = &self.{}", field.name), + "field".to_owned(), + true, + ) }; let mut optional_array_ser_block = Block::new(&optional_field_check); gen_scope.generate_serialize( types, (&field.rust_type).into(), &mut optional_array_ser_block, - SerializeConfig::new(&field_expr, &field.name).expr_is_ref(expr_is_ref).encoding_var_in_option_struct("self.encodings")); + SerializeConfig::new(&field_expr, &field.name) + .expr_is_ref(expr_is_ref) + .encoding_var_in_option_struct("self.encodings"), + ); ser_func.push_block(optional_array_ser_block); - gen_scope.dont_generate_deserialize(name, format!("Array with optional field {}: {}", field.name, field.rust_type.for_rust_member(false))); + gen_scope.dont_generate_deserialize( + name, + format!( + "Array with optional field {}: {}", + field.name, + field.rust_type.for_rust_member(false) + ), + ); } else { gen_scope.generate_serialize( types, (&field.rust_type).into(), &mut ser_func, - SerializeConfig::new(format!("self.{}", field.name), &field.name).encoding_var_in_option_struct("self.encodings")); + SerializeConfig::new(format!("self.{}", field.name), &field.name) + .encoding_var_in_option_struct("self.encodings"), + ); if CLI_ARGS.preserve_encodings { let var_names_str = encoding_var_names_str(&field.name, &field.rust_type); if CLI_ARGS.annotate_fields { @@ -2991,7 +3874,8 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na types, (&field.rust_type).into(), DeserializeBeforeAfter::new("", "", true), - DeserializeConfig::new(&field.name).in_embedded(in_embedded)) + DeserializeConfig::new(&field.name).in_embedded(in_embedded), + ) .annotate(&field.name, &format!("let {} = ", var_names_str), "?;") .add_to_code(&mut deser_code); } else { @@ -2999,20 +3883,25 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na .generate_deserialize( types, (&field.rust_type).into(), - DeserializeBeforeAfter::new(&format!("let {} = ", var_names_str), ";", false), - DeserializeConfig::new(&field.name).in_embedded(in_embedded)) + DeserializeBeforeAfter::new( + &format!("let {} = ", var_names_str), + ";", + false, + ), + DeserializeConfig::new(&field.name).in_embedded(in_embedded), + ) .add_to_code(&mut deser_code); } } else { if field.rust_type.is_fixed_value() { // don't set anything, only verify data if CLI_ARGS.annotate_fields { - let mut err_deser = gen_scope - .generate_deserialize( - types, - (&field.rust_type).into(), - DeserializeBeforeAfter::new("", "", true), - DeserializeConfig::new(&field.name).in_embedded(in_embedded)); + let mut err_deser = gen_scope.generate_deserialize( + types, + (&field.rust_type).into(), + DeserializeBeforeAfter::new("", "", true), + DeserializeConfig::new(&field.name).in_embedded(in_embedded), + ); // this block needs to evaluate to a Result even though it has no value err_deser.content.line("Ok(())"); err_deser @@ -3024,7 +3913,9 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na types, (&field.rust_type).into(), DeserializeBeforeAfter::new("", "", false), - DeserializeConfig::new(&field.name).in_embedded(in_embedded)) + DeserializeConfig::new(&field.name) + .in_embedded(in_embedded), + ) .add_to_code(&mut deser_code); } } else { @@ -3034,7 +3925,9 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na types, (&field.rust_type).into(), DeserializeBeforeAfter::new("", "", true), - DeserializeConfig::new(&field.name).in_embedded(in_embedded)) + DeserializeConfig::new(&field.name) + .in_embedded(in_embedded), + ) .annotate(&field.name, &format!("let {} = ", field.name), "?;") .add_to_code(&mut deser_code); } else { @@ -3042,8 +3935,14 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na .generate_deserialize( types, (&field.rust_type).into(), - DeserializeBeforeAfter::new(&format!("let {} = ", field.name), ";", false), - DeserializeConfig::new(&field.name).in_embedded(in_embedded)) + DeserializeBeforeAfter::new( + &format!("let {} = ", field.name), + ";", + false, + ), + DeserializeConfig::new(&field.name) + .in_embedded(in_embedded), + ) .add_to_code(&mut deser_code); } } @@ -3054,7 +3953,8 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na } } if CLI_ARGS.preserve_encodings { - let mut encoding_ctor = codegen::Block::new(&format!("encodings: Some({}Encoding", name)); + let mut encoding_ctor = + codegen::Block::new(&format!("encodings: Some({}Encoding", name)); encoding_ctor.line("len_encoding,"); if tag.is_some() { encoding_ctor.line("tag_encoding: Some(tag_encoding),"); @@ -3062,7 +3962,11 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na for field in record.fields.iter() { // we don't support deserialization for optional fields so don't even bother if !field.optional { - for field_enc in encoding_fields(&field.name, &field.rust_type.clone().resolve_aliases(), true) { + for field_enc in encoding_fields( + &field.name, + &field.rust_type.clone().resolve_aliases(), + true, + ) { encoding_ctor.line(format!("{},", field_enc.field_name)); } } @@ -3074,14 +3978,16 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na // in other groups otherwise deser_ret.after(")"); deser_ret - }, + } Representation::Map => { let mut uint_field_deserializers = Vec::new(); let mut text_field_deserializers = Vec::new(); // (field_index, field, content) -- this is ordered by canonical order let mut ser_content: Vec<(usize, &RustField, BlocksOrLines)> = Vec::new(); if CLI_ARGS.preserve_encodings { - deser_code.content.line("let mut orig_deser_order = Vec::new();"); + deser_code + .content + .line("let mut orig_deser_order = Vec::new();"); } // we default to canonical ordering here as the default ordering as that should be the most useful // keep in mind this is always overwritten if you have CLI_ARGS.preserve_encodings enabled AND there was @@ -3094,38 +4000,65 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na // or just for deserialization then constructing at the end with locals like a, b, bar_c, bar_d. if let ConceptualRustType::Rust(ident) = &field.rust_type.conceptual_type { if types.is_plain_group(&ident) { - gen_scope.dont_generate_deserialize(name, format!("Map with plain group field {}: {}", field.name, field.rust_type.for_rust_member(false))); + gen_scope.dont_generate_deserialize( + name, + format!( + "Map with plain group field {}: {}", + field.name, + field.rust_type.for_rust_member(false) + ), + ); } } // declare variables for deser loop if CLI_ARGS.preserve_encodings { - for field_enc in encoding_fields(&field.name, &field.rust_type.clone().resolve_aliases(), true) { - deser_code.content.line(&format!("let mut {} = {};", field_enc.field_name, field_enc.default_expr)); + for field_enc in encoding_fields( + &field.name, + &field.rust_type.clone().resolve_aliases(), + true, + ) { + deser_code.content.line(&format!( + "let mut {} = {};", + field_enc.field_name, field_enc.default_expr + )); } let key_enc = key_encoding_field(&field.name, &field.key.as_ref().unwrap()); - deser_code.content.line(&format!("let mut {} = {};", key_enc.field_name, key_enc.default_expr)); + deser_code.content.line(&format!( + "let mut {} = {};", + key_enc.field_name, key_enc.default_expr + )); } if field.rust_type.is_fixed_value() { - deser_code.content.line(&format!("let mut {}_present = false;", field.name)); + deser_code + .content + .line(&format!("let mut {}_present = false;", field.name)); } else { - deser_code.content.line(&format!("let mut {} = None;", field.name)); + deser_code + .content + .line(&format!("let mut {} = None;", field.name)); } - let (data_name, expr_is_ref) = if field.optional && field.rust_type.default.is_none() { - (String::from("field"), true) - } else { - (format!("self.{}", field.name), false) - }; + let (data_name, expr_is_ref) = + if field.optional && field.rust_type.default.is_none() { + (String::from("field"), true) + } else { + (format!("self.{}", field.name), false) + }; let key = field.key.clone().unwrap(); // deserialize key + value let mut deser_block = match &key { - FixedValue::Uint(x) => if CLI_ARGS.preserve_encodings { - Block::new(&format!("({}, key_enc) => ", x)) - } else { - Block::new(&format!("{} => ", x)) - }, + FixedValue::Uint(x) => { + if CLI_ARGS.preserve_encodings { + Block::new(&format!("({}, key_enc) => ", x)) + } else { + Block::new(&format!("{} => ", x)) + } + } FixedValue::Text(x) => Block::new(&format!("\"{}\" => ", x)), - _ => panic!("unsupported map key type for {}.{}: {:?}", name, field.name, key), + _ => panic!( + "unsupported map key type for {}.{}: {:?}", + name, field.name, key + ), }; deser_block.after(","); let mut deser_block_code = DeserializationCode::default(); @@ -3140,7 +4073,10 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na } else { Block::new(&format!("if {}.is_some()", field.name)) }; - dup_check.line(&format!("return Err(DeserializeFailure::DuplicateKey({}).into());", key_in_rust)); + dup_check.line(&format!( + "return Err(DeserializeFailure::DuplicateKey({}).into());", + key_in_rust + )); deser_block_code.content.push_block(dup_check); let temp_var_prefix = format!("tmp_{}", field.name); @@ -3156,7 +4092,10 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na types, (&field.rust_type).into(), DeserializeBeforeAfter::new("", "", true), - DeserializeConfig::new(&field.name).in_embedded(in_embedded).optional_field(field.optional)) + DeserializeConfig::new(&field.name) + .in_embedded(in_embedded) + .optional_field(field.optional), + ) .annotate(&field.name, &before, after) .add_to_code(&mut deser_block_code); } else { @@ -3170,7 +4109,10 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na types, (&field.rust_type).into(), DeserializeBeforeAfter::new(&before, after, false), - DeserializeConfig::new(&field.name).in_embedded(in_embedded).optional_field(field.optional)) + DeserializeConfig::new(&field.name) + .in_embedded(in_embedded) + .optional_field(field.optional), + ) .add_to_code(&mut deser_block_code); } // Due to destructuring assignemnt (RFC 372 / 71156) being unstable we're forced to use temporaries then reassign after @@ -3181,26 +4123,42 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na // but I don't think anyone (or many) would care about this as it's incredibly niche // (annotate_fields=false would be for minimizing code size but then preserve_encodings=true generates way more code) if field.rust_type.is_fixed_value() { - deser_block_code.content.line(&format!("{}_present = true;", field.name)); + deser_block_code + .content + .line(&format!("{}_present = true;", field.name)); } else { - deser_block_code.content.line(&format!("{} = Some(tmp_{});", field.name, field.name)); + deser_block_code + .content + .line(&format!("{} = Some(tmp_{});", field.name, field.name)); } - for enc_field in encoding_fields(&field.name, &field.rust_type.clone().resolve_aliases(), false) { - deser_block_code.content.line(&format!("{} = tmp_{};", enc_field.field_name, enc_field.field_name)); + for enc_field in encoding_fields( + &field.name, + &field.rust_type.clone().resolve_aliases(), + false, + ) { + deser_block_code.content.line(&format!( + "{} = tmp_{};", + enc_field.field_name, enc_field.field_name + )); } } else { if field.rust_type.is_fixed_value() { let mut dup_check = Block::new(&format!("if {}_present", field.name)); - dup_check.line(&format!("return Err(DeserializeFailure::DuplicateKey({}).into());", key_in_rust)); + dup_check.line(&format!( + "return Err(DeserializeFailure::DuplicateKey({}).into());", + key_in_rust + )); deser_block_code.content.push_block(dup_check); // only does verification and sets the field_present bool to do error checking later if CLI_ARGS.annotate_fields { - let mut err_deser = gen_scope - .generate_deserialize( - types, - (&field.rust_type).into(), - DeserializeBeforeAfter::new("", "", false), - DeserializeConfig::new(&field.name).in_embedded(in_embedded).optional_field(field.optional)); + let mut err_deser = gen_scope.generate_deserialize( + types, + (&field.rust_type).into(), + DeserializeBeforeAfter::new("", "", false), + DeserializeConfig::new(&field.name) + .in_embedded(in_embedded) + .optional_field(field.optional), + ); err_deser.content.line("Ok(true)"); err_deser .annotate(&field.name, &format!("{}_present = ", field.name), "?;") @@ -3211,13 +4169,21 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na types, (&field.rust_type).into(), DeserializeBeforeAfter::new("", "", false), - DeserializeConfig::new(&field.name).in_embedded(in_embedded).optional_field(field.optional)) + DeserializeConfig::new(&field.name) + .in_embedded(in_embedded) + .optional_field(field.optional), + ) .add_to_code(&mut deser_block_code); - deser_block_code.content.line(&format!("{}_present = true;", field.name)); + deser_block_code + .content + .line(&format!("{}_present = true;", field.name)); } } else { let mut dup_check = Block::new(&format!("if {}.is_some()", field.name)); - dup_check.line(&format!("return Err(DeserializeFailure::DuplicateKey({}).into());", key_in_rust)); + dup_check.line(&format!( + "return Err(DeserializeFailure::DuplicateKey({}).into());", + key_in_rust + )); deser_block_code.content.push_block(dup_check); if CLI_ARGS.annotate_fields { gen_scope @@ -3225,7 +4191,10 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na types, (&field.rust_type).into(), DeserializeBeforeAfter::new("", "", true), - DeserializeConfig::new(&field.name).in_embedded(in_embedded).optional_field(field.optional)) + DeserializeConfig::new(&field.name) + .in_embedded(in_embedded) + .optional_field(field.optional), + ) .annotate(&field.name, &format!("{} = Some(", field.name), "?);") .add_to_code(&mut deser_block_code); } else { @@ -3233,8 +4202,15 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na .generate_deserialize( types, (&field.rust_type).into(), - DeserializeBeforeAfter::new(&format!("{} = Some(", field.name), ");", false), - DeserializeConfig::new(&field.name).in_embedded(in_embedded).optional_field(field.optional)) + DeserializeBeforeAfter::new( + &format!("{} = Some(", field.name), + ");", + false, + ), + DeserializeConfig::new(&field.name) + .in_embedded(in_embedded) + .optional_field(field.optional), + ) .add_to_code(&mut deser_block_code); } } @@ -3257,20 +4233,39 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na let serialize_config = SerializeConfig::new(&data_name, &field.name) .expr_is_ref(expr_is_ref) .encoding_var_in_option_struct("self.encodings"); - let key_encoding_var = serialize_config.encoding_var(Some("key"), key.encoding_var_is_copy()); - + let key_encoding_var = + serialize_config.encoding_var(Some("key"), key.encoding_var_is_copy()); + deser_block.push_all(deser_block_code.mark_and_extract_content(&mut deser_code)); match &key { FixedValue::Uint(x) => { let expr = format!("{}u64", x); - write_using_sz(&mut map_ser_content, "write_unsigned_integer", "serializer", &expr, &expr, "?;", &key_encoding_var); + write_using_sz( + &mut map_ser_content, + "write_unsigned_integer", + "serializer", + &expr, + &expr, + "?;", + &key_encoding_var, + ); uint_field_deserializers.push(deser_block); - }, + } FixedValue::Text(s) => { - write_string_sz(&mut map_ser_content, "write_text", "serializer", &format!("\"{}\"", s), "?;", &key_encoding_var); + write_string_sz( + &mut map_ser_content, + "write_text", + "serializer", + &format!("\"{}\"", s), + "?;", + &key_encoding_var, + ); text_field_deserializers.push(deser_block); - }, - _ => panic!("unsupported map key type for {}.{}: {:?}", name, field.name, key), + } + _ => panic!( + "unsupported map key type for {}.{}: {:?}", + name, field.name, key + ), }; // serialize value @@ -3278,7 +4273,8 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na types, (&field.rust_type).into(), &mut map_ser_content, - serialize_config); + serialize_config, + ); ser_content.push((field_index, field, map_ser_content)); } if CLI_ARGS.preserve_encodings { @@ -3308,27 +4304,34 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na // ser_loop_match.line(format!("{} => {},")); //} else { //} - let mut field_ser_block = if field.optional && field.rust_type.default.is_none() { - Block::new(&format!("{} => if let Some(field) = &self.{}", field_index, field.name)) + let mut field_ser_block = if field.optional && field.rust_type.default.is_none() + { + Block::new(&format!( + "{} => if let Some(field) = &self.{}", + field_index, field.name + )) } else { Block::new(&format!("{} =>", field_index)) }; field_ser_block.push_all(content); ser_loop_match.push_block(field_ser_block); } - ser_loop_match - .line("_ => unreachable!()") - .after(";"); + ser_loop_match.line("_ => unreachable!()").after(";"); ser_loop.push_block(ser_loop_match); ser_func.push_block(ser_loop); } else { for (_field_index, field, content) in ser_content.into_iter() { if field.optional { - let optional_ser_field_check = if let Some(default_value) = &field.rust_type.default { - format!("if self.{} != {}", field.name, default_value.to_primitive_str_compare()) - } else { - format!("if let Some(field) = &self.{}", field.name) - }; + let optional_ser_field_check = + if let Some(default_value) = &field.rust_type.default { + format!( + "if self.{} != {}", + field.name, + default_value.to_primitive_str_compare() + ) + } else { + format!("if let Some(field) = &self.{}", field.name) + }; let mut optional_ser_field = Block::new(&optional_ser_field_check); optional_ser_field.push_all(content); ser_func.push_block(optional_ser_field); @@ -3344,7 +4347,7 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na if uint_field_deserializers.is_empty() { type_match.line("CBORType::UnsignedInteger => return Err(DeserializeFailure::UnknownKey(Key::Uint(raw.unsigned_integer()?)).into()),"); } else { - let mut uint_match = if CLI_ARGS.preserve_encodings { + let mut uint_match = if CLI_ARGS.preserve_encodings { Block::new("CBORType::UnsignedInteger => match raw.unsigned_integer_sz()?") } else { Block::new("CBORType::UnsignedInteger => match raw.unsigned_integer()?") @@ -3388,9 +4391,15 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na } } let mut special_match = Block::new("CBORType::Special => match len"); - special_match.line(format!("{} => return Err(DeserializeFailure::BreakInDefiniteLen.into()),", cbor_event_len_n("_"))); + special_match.line(format!( + "{} => return Err(DeserializeFailure::BreakInDefiniteLen.into()),", + cbor_event_len_n("_") + )); // TODO: this will need to change if we support Special values as keys (e.g. true / false) - let mut break_check = Block::new(&format!("{} => match raw.special()?", cbor_event_len_indef())); + let mut break_check = Block::new(&format!( + "{} => match raw.special()?", + cbor_event_len_indef() + )); break_check.line("CBORSpecial::Break => break,"); break_check.line("_ => return Err(DeserializeFailure::EndingBreakMissing.into()),"); break_check.after(","); @@ -3412,11 +4421,16 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na _ => unimplemented!(), }; if field.rust_type.is_fixed_value() { - let mut mandatory_field_check = Block::new(&format!("if !{}_present", field.name)); - mandatory_field_check.line(format!("return Err(DeserializeFailure::MandatoryFieldMissing({}).into());", key)); + let mut mandatory_field_check = + Block::new(&format!("if !{}_present", field.name)); + mandatory_field_check.line(format!( + "return Err(DeserializeFailure::MandatoryFieldMissing({}).into());", + key + )); deser_code.content.push_block(mandatory_field_check); } else { - let mut mandatory_field_check = Block::new(&format!("let {} = match {}", field.name, field.name)); + let mut mandatory_field_check = + Block::new(&format!("let {} = match {}", field.name, field.name)); mandatory_field_check.line("Some(x) => x,"); mandatory_field_check.line(format!("None => return Err(DeserializeFailure::MandatoryFieldMissing({}).into()),", key)); @@ -3425,8 +4439,13 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na } } else if let Some(default_value) = &field.rust_type.default { if CLI_ARGS.preserve_encodings { - let mut default_present_check = Block::new(&format!("if {} == Some({})", field.name, default_value.to_primitive_str_assign())); - default_present_check.line(format!("{}_default_present = true;", field.name)); + let mut default_present_check = Block::new(&format!( + "if {} == Some({})", + field.name, + default_value.to_primitive_str_assign() + )); + default_present_check + .line(format!("{}_default_present = true;", field.name)); deser_code.content.push_block(default_present_check); } match default_value { @@ -3436,18 +4455,20 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na "let {} = {}.unwrap_or_else(|| {});", field.name, field.name, - default_value.to_primitive_str_assign())); - }, - FixedValue::Bool(_) | - FixedValue::Nint(_) | - FixedValue::Null | - FixedValue::Float(_) | - FixedValue::Uint(_) => { + default_value.to_primitive_str_assign() + )); + } + FixedValue::Bool(_) + | FixedValue::Nint(_) + | FixedValue::Null + | FixedValue::Float(_) + | FixedValue::Uint(_) => { deser_code.content.line(&format!( "let {} = {}.unwrap_or({});", field.name, field.name, - default_value.to_primitive_str_assign())); + default_value.to_primitive_str_assign() + )); } } } @@ -3456,7 +4477,8 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na } } if CLI_ARGS.preserve_encodings { - let mut encoding_ctor = codegen::Block::new(&format!("encodings: Some({}Encoding", name)); + let mut encoding_ctor = + codegen::Block::new(&format!("encodings: Some({}Encoding", name)); if tag.is_some() { encoding_ctor.line("tag_encoding: Some(tag_encoding),"); } @@ -3466,7 +4488,11 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na for field in record.fields.iter() { let key_enc = key_encoding_field(&field.name, field.key.as_ref().unwrap()); encoding_ctor.line(format!("{},", key_enc.field_name)); - for field_enc in encoding_fields(&field.name, &field.rust_type.clone().resolve_aliases(), true) { + for field_enc in encoding_fields( + &field.name, + &field.rust_type.clone().resolve_aliases(), + true, + ) { encoding_ctor.line(format!("{},", field_enc.field_name)); } } @@ -3475,30 +4501,41 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na } ctor_block.after(")"); ctor_block - }, + } }; - let len_enc_var = len_encoding_var.map(|var| format!("self.encodings.as_ref().map(|encs| encs.{}).unwrap_or_default()", var)).unwrap_or_default(); + let len_enc_var = len_encoding_var + .map(|var| { + format!( + "self.encodings.as_ref().map(|encs| encs.{}).unwrap_or_default()", + var + ) + }) + .unwrap_or_default(); end_len(&mut ser_func, "serializer", &len_enc_var, true); match &mut ser_embedded_impl { Some(ser_embedded_impl) => ser_embedded_impl.push_fn(ser_func), None => ser_impl.push_fn(ser_func), }; let mut deser_scaffolding = BlocksOrLines::default(); - let (mut deser_impl, mut deser_embedded_impl) = - create_deserialize_impls( - name, - Some(record.rep), - tag, - record.cbor_len_info(types), - types.is_plain_group(name), - len_encoding_var, - &mut deser_scaffolding); + let (mut deser_impl, mut deser_embedded_impl) = create_deserialize_impls( + name, + Some(record.rep), + tag, + record.cbor_len_info(types), + types.is_plain_group(name), + len_encoding_var, + &mut deser_scaffolding, + ); if deser_embedded_impl.is_none() { // ending checks are included with embedded serialization setup // since we are populating deserialize_as_embedded_group() and deserialize() // is already complete // but these checks must be done manually here *after* we populate deserialize() - add_deserialize_final_len_check(&mut deser_code.content, Some(record.rep), record.cbor_len_info(types)); + add_deserialize_final_len_check( + &mut deser_code.content, + Some(record.rep), + record.cbor_len_info(types), + ); } deser_code.content.push_block(ctor_block); @@ -3535,7 +4572,15 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na deser_f.push_all(deser_code.content); deser_impl.push_fn(deser_f); } - push_rust_struct(gen_scope, types, name, native_struct, native_impl, ser_impl, ser_embedded_impl); + push_rust_struct( + gen_scope, + types, + name, + native_struct, + native_impl, + ser_impl, + ser_embedded_impl, + ); // for clippy we generate a Default when new takes no args. // We keep new() for consistency with other types. if new_arg_count == 0 { @@ -3545,9 +4590,7 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na .new_fn("default") .ret("Self") .line("Self::new()"); - gen_scope - .rust(types, name) - .push_impl(default_impl); + gen_scope.rust(types, name).push_impl(default_impl); } // TODO: generic deserialize (might need backtracking) if gen_scope.deserialize_generated(name) { @@ -3558,7 +4601,14 @@ fn codegen_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, na } } -fn codegen_group_choices(gen_scope: &mut GenerationScope, types: &IntermediateTypes, name: &RustIdent, variants: &Vec, rep: Representation, tag: Option) { +fn codegen_group_choices( + gen_scope: &mut GenerationScope, + types: &IntermediateTypes, + name: &RustIdent, + variants: &Vec, + rep: Representation, + tag: Option, +) { // rust inner enum generate_enum(gen_scope, types, name, &variants, Some(rep), false, tag); @@ -3569,29 +4619,38 @@ fn codegen_group_choices(gen_scope: &mut GenerationScope, types: &IntermediateTy for variant in variants.iter() { // TODO: verify if variant.serialize_as_embedded_group impacts ctor generation let mut new_func = codegen::Function::new(&format!("new_{}", variant.name_as_var())); - new_func - .ret("Self") - .vis("pub"); + new_func.ret("Self").vis("pub"); let mut output_comma = false; // We only want to generate Variant::new() calls when we created a special struct // for the variant, which happens in the general case for multi-field group choices let fields = match &variant.rust_type.conceptual_type { // we need to check for sanity here, as if we're referring to the ident // it should at this stage be registered - ConceptualRustType::Rust(ident) => match types.rust_struct(ident).unwrap().variant() { - RustStructType::Record(record) => Some(&record.fields), - _ => None, - }, - ConceptualRustType::Alias(_, _) => unimplemented!("TODO: do we need to handle aliases here?"), + ConceptualRustType::Rust(ident) => { + match types.rust_struct(ident).unwrap().variant() { + RustStructType::Record(record) => Some(&record.fields), + _ => None, + } + } + ConceptualRustType::Alias(_, _) => { + unimplemented!("TODO: do we need to handle aliases here?") + } _ => None, }; match fields { Some(fields) => { - let ctor_fields: Vec<&RustField> = fields.iter().filter(|f| !f.optional && !f.rust_type.is_fixed_value()).collect(); + let ctor_fields: Vec<&RustField> = fields + .iter() + .filter(|f| !f.optional && !f.rust_type.is_fixed_value()) + .collect(); match ctor_fields.len() { 0 => { - new_func.line(format!("Self(core::{}::new_{}())", name, variant.name_as_var())); - }, + new_func.line(format!( + "Self(core::{}::new_{}())", + name, + variant.name_as_var() + )); + } // TODO: verify. I think this was here so that 1-field things would be directly stored // 1 => { // let field = ctor_fields.first().unwrap(); @@ -3603,7 +4662,8 @@ fn codegen_group_choices(gen_scope: &mut GenerationScope, types: &IntermediateTy // multi-field struct, so for convenience we let you pass the parameters directly here // instead of having to separately construct the variant to pass in _ => { - let mut ctor = format!("Self(core::{}::new_{}(", name, variant.name_as_var()); + let mut ctor = + format!("Self(core::{}::new_{}(", name, variant.name_as_var()); for field in ctor_fields { if output_comma { ctor.push_str(", "); @@ -3611,26 +4671,45 @@ fn codegen_group_choices(gen_scope: &mut GenerationScope, types: &IntermediateTy output_comma = true; } new_func.arg(&field.name, field.rust_type.for_wasm_param()); - ctor.push_str(&ToWasmBoundaryOperations::format(field.rust_type.from_wasm_boundary_clone(&field.name, false).into_iter())); + ctor.push_str(&ToWasmBoundaryOperations::format( + field + .rust_type + .from_wasm_boundary_clone(&field.name, false) + .into_iter(), + )); // ^ TODO: check types.can_new_fail(&field.name) } ctor.push_str("))"); new_func.line(ctor); - }, + } } - }, + } None => { // just directly pass in the variant's type if variant.rust_type.is_fixed_value() { - new_func.line(format!("Self(core::{}::new_{}())", name, variant.name_as_var())); + new_func.line(format!( + "Self(core::{}::new_{}())", + name, + variant.name_as_var() + )); } else { let field_name = variant.name.to_string(); new_func .arg(&field_name, variant.rust_type.for_wasm_param()) - .line(format!("Self(core::{}::new_{}({}))", name, variant.name_as_var(), ToWasmBoundaryOperations::format(variant.rust_type.from_wasm_boundary_clone(&field_name, false).into_iter()))); + .line(format!( + "Self(core::{}::new_{}({}))", + name, + variant.name_as_var(), + ToWasmBoundaryOperations::format( + variant + .rust_type + .from_wasm_boundary_clone(&field_name, false) + .into_iter() + ) + )); // ^ TODO: check types.can_new_fail(&field.name) } - }, + } } wrapper.s_impl.push_fn(new_func); } @@ -3640,19 +4719,28 @@ fn codegen_group_choices(gen_scope: &mut GenerationScope, types: &IntermediateTy } } -fn add_wasm_enum_getters(s_impl: &mut codegen::Impl, name: &RustIdent, variants: &Vec, rep: Option) { +fn add_wasm_enum_getters( + s_impl: &mut codegen::Impl, + name: &RustIdent, + variants: &Vec, + rep: Option, +) { assert!(CLI_ARGS.wasm); // kind() getter let kind_name = format!("{}Kind", name); let mut get_kind = codegen::Function::new("kind"); - get_kind - .arg_ref_self() - .vis("pub") - .ret(&kind_name); + get_kind.arg_ref_self().vis("pub").ret(&kind_name); let mut get_kind_match = codegen::Block::new("match &self.0"); for variant in variants.iter() { let enum_gen_info = EnumVariantInRust::new(&variant, rep); - get_kind_match.line(format!("core::{}::{}{} => {}::{},", name, variant.name, enum_gen_info.capture_ignore_all(), kind_name, variant.name)); + get_kind_match.line(format!( + "core::{}::{}{} => {}::{},", + name, + variant.name, + enum_gen_info.capture_ignore_all(), + kind_name, + variant.name + )); } get_kind.push_block(get_kind_match); s_impl.push_fn(get_kind); @@ -3672,7 +4760,10 @@ fn add_wasm_enum_getters(s_impl: &mut codegen::Impl, name: &RustIdent, variants: name, variant.name, enum_gen_info.capture_ignore_encodings(), - variant.rust_type.to_wasm_boundary(&enum_gen_info.names[0], true))); + variant + .rust_type + .to_wasm_boundary(&enum_gen_info.names[0], true) + )); variant_match.line("_ => None,"); as_variant.push_block(variant_match); s_impl.push_fn(as_variant); @@ -3752,20 +4843,24 @@ impl EnumVariantInRust { } fn names_with_macros(&self, used_in_key: bool) -> Vec { - self.names.iter().enumerate().map(|(i, name)| { - if i < self.names.len() - self.enc_fields.len() { - // not an encoding variable: - name.clone() - } else { - // encoding variable: - // the codeen crate doesn't support proc macros on fields but we just inline - // these with a newline in the field names for declaring as workaround. - // Indentation is never an issue as we're always 2 levels deep for field declarations - format!("{}{}", encoding_var_macros(used_in_key), name) - } - }).collect() + self.names + .iter() + .enumerate() + .map(|(i, name)| { + if i < self.names.len() - self.enc_fields.len() { + // not an encoding variable: + name.clone() + } else { + // encoding variable: + // the codeen crate doesn't support proc macros on fields but we just inline + // these with a newline in the field names for declaring as workaround. + // Indentation is never an issue as we're always 2 levels deep for field declarations + format!("{}{}", encoding_var_macros(used_in_key), name) + } + }) + .collect() } - + fn capture_all(&self) -> String { match self.names.len() { 0 => "".to_owned(), @@ -3786,24 +4881,38 @@ impl EnumVariantInRust { match self.names.len() { 0 => "".to_owned(), 1 if self.enc_fields.is_empty() => format!("({})", self.names[0]), - _ => if self.enc_fields.len() == self.names.len() { - "{ .. }".to_owned() - } else { - format!("{{ {}, .. }}", self.names[0]) - }, + _ => { + if self.enc_fields.len() == self.names.len() { + "{ .. }".to_owned() + } else { + format!("{{ {}, .. }}", self.names[0]) + } + } } } /// if init_fields exists, use these for values, otherwise assumes variables exist with same names - fn generate_constructor(&self, body: &mut dyn CodeBlock, before: &str, after: &str, init_fields: Option<&Vec>) { + fn generate_constructor( + &self, + body: &mut dyn CodeBlock, + before: &str, + after: &str, + init_fields: Option<&Vec>, + ) { let init_fields = init_fields.unwrap_or_else(|| self.names.as_ref()); match init_fields.len() { 0 => { body.line(&format!("{}Self::{}{}", before, self.name, after)); - }, + } 1 if self.enc_fields.is_empty() => { - body.line(&format!("{}Self::{}({}){}", before, self.name, init_fields.join(", "), after)); - }, + body.line(&format!( + "{}Self::{}({}){}", + before, + self.name, + init_fields.join(", "), + after + )); + } _ => { let mut ctor = Block::new(&format!("{}Self::{}", before, self.name)); for (name, expr) in self.names.iter().zip(init_fields.iter()) { @@ -3815,7 +4924,7 @@ impl EnumVariantInRust { } ctor.after(after); body.push_block(ctor); - }, + } }; } } @@ -3823,7 +4932,15 @@ impl EnumVariantInRust { // if generate_deserialize_directly, don't generate deserialize_as_embedded_group() and just inline it within deserialize() // This is useful for type choicecs which don't have any enclosing array/map tags, and thus don't benefit from exposing a // deserialize_as_embedded_group as the behavior would be identical. -fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, name: &RustIdent, variants: &Vec, rep: Option, generate_deserialize_directly: bool, tag: Option) { +fn generate_enum( + gen_scope: &mut GenerationScope, + types: &IntermediateTypes, + name: &RustIdent, + variants: &Vec, + rep: Option, + generate_deserialize_directly: bool, + tag: Option, +) { if CLI_ARGS.wasm { // also create a wasm-exposed enum just to distinguish the type let mut kind = codegen::Enum::new(&format!("{}Kind", name)); @@ -3832,9 +4949,7 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam kind.new_variant(&variant.name.to_string()); } kind.attr("wasm_bindgen"); - gen_scope - .wasm(types, name) - .push_enum(kind); + gen_scope.wasm(types, name).push_enum(kind); } // rust enum containing the data @@ -3872,12 +4987,24 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam deser_impl } else { // this handles the tag check too - let outer_encoding_var = if CLI_ARGS.preserve_encodings && variants.iter().any(|variant| !variant.serialize_as_embedded_group) { + let outer_encoding_var = if CLI_ARGS.preserve_encodings + && variants + .iter() + .any(|variant| !variant.serialize_as_embedded_group) + { Some("outer_len_encoding") } else { None }; - let (deser_impl, _deser_embedded_impl) = create_deserialize_impls(name, rep, tag, len_info.clone(), false, outer_encoding_var, deser_body); + let (deser_impl, _deser_embedded_impl) = create_deserialize_impls( + name, + rep, + tag, + len_info.clone(), + false, + outer_encoding_var, + deser_body, + ); deser_impl }; deser_body.line("let initial_position = raw.as_mut_ref().seek(SeekFrom::Current(0)).unwrap();"); @@ -3886,23 +5013,24 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam let variant_var_name = variant.name_as_var(); let mut v = codegen::Variant::new(&variant.name.to_string()); match enum_gen_info.names.len() { - 0 => { - }, + 0 => {} 1 if enum_gen_info.enc_fields.is_empty() => { v.tuple(&enum_gen_info.types[0]); - }, + } _ => { - for (name_with_macros, type_str) in enum_gen_info.names_with_macros(types.used_as_key(name)).into_iter().zip(enum_gen_info.types.iter()) { + for (name_with_macros, type_str) in enum_gen_info + .names_with_macros(types.used_as_key(name)) + .into_iter() + .zip(enum_gen_info.types.iter()) + { v.named(&name_with_macros, type_str); } - }, + } } e.push_variant(v); // new (particularly useful if we have encoding variables) let mut new_func = codegen::Function::new(&format!("new_{}", variant_var_name)); - new_func - .ret("Self") - .vis("pub"); + new_func.ret("Self").vis("pub"); let mut output_comma = false; // We only want to generate Variant::new() calls when we created a special struct // for the variant, which happens in the general case for multi-field group choices @@ -3910,17 +5038,23 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam // we need to check for sanity here, as if we're referring to the ident // it should at this stage be registered ConceptualRustType::Rust(ident) => { - - match types.rust_struct(ident).expect(&format!("{} refers to undefined ident: {}", name, ident)).variant() { + match types + .rust_struct(ident) + .expect(&format!("{} refers to undefined ident: {}", name, ident)) + .variant() + { RustStructType::Record(record) => Some(&record.fields), _ => None, } - }, + } _ => None, }; let mut init_fields = match rep.and(fields) { Some(fields) => { - let ctor_fields: Vec<&RustField> = fields.iter().filter(|f| !f.optional && !f.rust_type.is_fixed_value()).collect(); + let ctor_fields: Vec<&RustField> = fields + .iter() + .filter(|f| !f.optional && !f.rust_type.is_fixed_value()) + .collect(); let mut ctor = format!("{}::new(", variant.name); for field in ctor_fields { if output_comma { @@ -3934,7 +5068,7 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam } ctor.push_str(")"); vec![ctor] - }, + } None => { if variant.rust_type.is_fixed_value() { vec![] @@ -3945,7 +5079,7 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam vec![field_name] // ^ TODO: check types.can_new_fail(&field.name)? } - }, + } }; for enc_field in enum_gen_info.enc_fields.iter() { init_fields.push(enc_field.default_expr.to_owned()); @@ -3964,22 +5098,36 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam variant.name, variant_var_name, variant_var_name, - canonical_param())); + canonical_param() + )); } else { - let mut case_block = Block::new(&format!("{}::{}{} =>", name, variant.name, enum_gen_info.capture_all())); + let mut case_block = Block::new(&format!( + "{}::{}{} =>", + name, + variant.name, + enum_gen_info.capture_all() + )); if CLI_ARGS.preserve_encodings { if let Some(r) = rep { // group choice - let n = variant.rust_type.expanded_field_count(types) - .expect("preserve-encodings=true not supported with varying-size group choice"); - start_len(&mut case_block, r, "serializer", "outer_len_encoding", &n.to_string()); + let n = variant.rust_type.expanded_field_count(types).expect( + "preserve-encodings=true not supported with varying-size group choice", + ); + start_len( + &mut case_block, + r, + "serializer", + "outer_len_encoding", + &n.to_string(), + ); gen_scope.generate_serialize( types, (&variant.rust_type).into(), &mut case_block, SerializeConfig::new(&variant_var_name, &variant_var_name) .expr_is_ref(true) - .encoding_var_is_ref(true)); + .encoding_var_is_ref(true), + ); end_len(&mut case_block, "serializer", "outer_len_encoding", false); case_block.line("Ok(serializer)"); } else { @@ -3991,22 +5139,24 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam SerializeConfig::new(&variant_var_name, &variant_var_name) .expr_is_ref(true) .is_end(true) - .encoding_var_is_ref(true)); + .encoding_var_is_ref(true), + ); } } else { let write_break = match rep { Some(r) => { - let (len_str, indefinite) = match variant.rust_type.expanded_field_count(types) { - Some(n) => (cbor_event_len_n(&n.to_string()), false), - None => (String::from(cbor_event_len_indef()), true), - }; + let (len_str, indefinite) = + match variant.rust_type.expanded_field_count(types) { + Some(n) => (cbor_event_len_n(&n.to_string()), false), + None => (String::from(cbor_event_len_indef()), true), + }; let func_str = match r { Representation::Array => "write_array", Representation::Map => "write_map", }; case_block.line(format!("serializer.{}({})?;", func_str, len_str)); indefinite - }, + } None => false, }; // TODO: only generate a block if the serialize is more than 1 line @@ -4018,7 +5168,8 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam &mut case_block, SerializeConfig::new(&variant_var_name, &variant_var_name) .expr_is_ref(true) - .is_end(!write_break)); + .is_end(!write_break), + ); if write_break { case_block.line("serializer.write_special(CBORSpecial::Break)"); } @@ -4030,31 +5181,35 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam // TODO: don't backtrack if variants begin with non-overlapping cbor types // TODO: how to detect when a greedy match won't work? (ie choice with choices in a choice possibly) let variant_deser_code = if enum_gen_info.types.is_empty() { - let mut code = gen_scope - .generate_deserialize( - types, - (&variant.rust_type).into(), - DeserializeBeforeAfter::new("", "", false), - DeserializeConfig::new(&variant.name_as_var())); + let mut code = gen_scope.generate_deserialize( + types, + (&variant.rust_type).into(), + DeserializeBeforeAfter::new("", "", false), + DeserializeConfig::new(&variant.name_as_var()), + ); code.content.line("Ok(())"); code } else { - gen_scope - .generate_deserialize( - types, - (&variant.rust_type).into(), - DeserializeBeforeAfter::new("", "", true), - DeserializeConfig::new(&variant.name_as_var())) + gen_scope.generate_deserialize( + types, + (&variant.rust_type).into(), + DeserializeBeforeAfter::new("", "", true), + DeserializeConfig::new(&variant.name_as_var()), + ) }; let mut return_if_deserialized = match variant_deser_code.content.as_single_line() { Some(single_line) if !variant_deser_code.throws => { // to get around type annotations being needed for error types (e.g. auto conversions with ?) we make a variable // to do better than this we'd need to make DeserializationCode keep track of error types too. - deser_body.line(&format!("let deser_variant: Result<_, DeserializeError> = {};", single_line)); + deser_body.line(&format!( + "let deser_variant: Result<_, DeserializeError> = {};", + single_line + )); Block::new("match deser_variant") - }, + } _ => { - let mut variant_deser = Block::new("match (|raw: &mut Deserializer<_>| -> Result<_, DeserializeError>"); + let mut variant_deser = + Block::new("match (|raw: &mut Deserializer<_>| -> Result<_, DeserializeError>"); variant_deser.after(")(raw)"); variant_deser.push_all(variant_deser_code.content); deser_body.push_block(variant_deser); @@ -4064,7 +5219,8 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam }; let names_without_outer = enum_gen_info.names_without_outer(); if names_without_outer.is_empty() { - return_if_deserialized.line(format!("Ok(()) => return Ok({}::{}),", name, variant.name)); + return_if_deserialized + .line(format!("Ok(()) => return Ok({}::{}),", name, variant.name)); } else { enum_gen_info.generate_constructor( &mut return_if_deserialized, @@ -4074,9 +5230,11 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam format!("Ok({}) => return Ok(", names_without_outer.join(", ")) }, "),", - None); + None, + ); } - return_if_deserialized.line("Err(_) => raw.as_mut_ref().seek(SeekFrom::Start(initial_position)).unwrap(),"); + return_if_deserialized + .line("Err(_) => raw.as_mut_ref().seek(SeekFrom::Start(initial_position)).unwrap(),"); return_if_deserialized.after(";"); deser_body.push_block(return_if_deserialized); } @@ -4090,17 +5248,17 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam // that gets complicated for optional fields inside those plain groups so we'll // just avoid this check instead for this one case. add_deserialize_final_len_check(deser_body, rep, RustStructCBORLen::Fixed(0)); - deser_body.line(&format!("Err(DeserializeError::new(\"{}\", DeserializeFailure::NoVariantMatched))", name)); + deser_body.line(&format!( + "Err(DeserializeError::new(\"{}\", DeserializeFailure::NoVariantMatched))", + name + )); if CLI_ARGS.annotate_fields { deser_func.push_block(error_annotator); } deser_impl.push_fn(deser_func); // TODO: should we stick this in another scope somewhere or not? it's not exposed to wasm // however, clients expanding upon the generated lib might find it of use to change. - gen_scope - .rust(types, name) - .push_enum(e) - .push_impl(e_impl); + gen_scope.rust(types, name).push_enum(e).push_impl(e_impl); gen_scope .rust_serialize() .push_impl(ser_impl) @@ -4109,8 +5267,7 @@ fn generate_enum(gen_scope: &mut GenerationScope, types: &IntermediateTypes, nam fn make_serialization_function(name: &str) -> codegen::Function { let mut f = codegen::Function::new(name); - f - .generic("'se, W: Write") + f.generic("'se, W: Write") .ret("cbor_event::Result<&'se mut Serializer>") .arg_ref_self() .arg("serializer", "&'se mut Serializer"); @@ -4132,8 +5289,7 @@ fn make_serialization_impl(name: &str) -> codegen::Impl { fn make_deserialization_function(name: &str) -> codegen::Function { let mut f = codegen::Function::new(name); - f - .generic("R: BufRead + Seek") + f.generic("R: BufRead + Seek") .ret("Result") .arg("raw", "&mut Deserializer"); f @@ -4151,7 +5307,10 @@ fn make_encoding_struct(encoding_name: &str) -> codegen::Struct { fn generate_tag_check(deser_func: &mut dyn CodeBlock, ident: &RustIdent, tag: Option) { if let Some(tag) = tag { - deser_func.line(&format!("let tag = raw.tag().map_err(|e| DeserializeError::from(e).annotate(\"{}\"))?;", ident)); + deser_func.line(&format!( + "let tag = raw.tag().map_err(|e| DeserializeError::from(e).annotate(\"{}\"))?;", + ident + )); let mut tag_check = Block::new(&format!("if tag != {}", tag)); tag_check.line(&format!("return Err(DeserializeError::new(\"{}\", DeserializeFailure::TagMismatch{{ found: tag, expected: {} }}));", ident, tag)); deser_func.push_block(tag_check); @@ -4159,7 +5318,13 @@ fn generate_tag_check(deser_func: &mut dyn CodeBlock, ident: &RustIdent, tag: Op } // This is used mostly for when thing are tagged have specific ranges. -fn generate_wrapper_struct(gen_scope: &mut GenerationScope, types: &IntermediateTypes, type_name: &RustIdent, field_type: &RustType, min_max: Option<(Option, Option)>) { +fn generate_wrapper_struct( + gen_scope: &mut GenerationScope, + types: &IntermediateTypes, + type_name: &RustIdent, + field_type: &RustType, + min_max: Option<(Option, Option)>, +) { if min_max.is_some() { assert!(types.can_new_fail(type_name)); } @@ -4169,7 +5334,7 @@ fn generate_wrapper_struct(gen_scope: &mut GenerationScope, types: &Intermediate wasm_new .arg("inner", field_type.for_wasm_param()) .vis("pub"); - + if types.can_new_fail(type_name) { // you can't use Self in a parameter in wasm_bindgen for some reason wasm_new @@ -4179,13 +5344,13 @@ fn generate_wrapper_struct(gen_scope: &mut GenerationScope, types: &Intermediate } else { let mut ops = field_type.from_wasm_boundary_clone("inner", false); ops.push(ToWasmBoundaryOperations::Into); - wasm_new - .ret("Self") - .line(format!("Self({})", ToWasmBoundaryOperations::format(ops.into_iter()))); + wasm_new.ret("Self").line(format!( + "Self({})", + ToWasmBoundaryOperations::format(ops.into_iter()) + )); } let mut get = codegen::Function::new("get"); - get - .vis("pub") + get.vis("pub") .arg_ref_self() .ret(field_type.for_wasm_return()) .line(field_type.to_wasm_boundary("self.0.get()", false)); @@ -4201,12 +5366,21 @@ fn generate_wrapper_struct(gen_scope: &mut GenerationScope, types: &Intermediate let enc_fields = if CLI_ARGS.preserve_encodings { s.field("pub inner", field_type.for_rust_member(false)); let enc_fields = encoding_fields("inner", &field_type.clone().resolve_aliases(), true); - + if !enc_fields.is_empty() { - s.field(&format!("{}pub encodings", encoding_var_macros(types.used_as_key(type_name))), format!("Option<{}>", encoding_name)); + s.field( + &format!( + "{}pub encodings", + encoding_var_macros(types.used_as_key(type_name)) + ), + format!("Option<{}>", encoding_name), + ); let mut encoding_struct = make_encoding_struct(&encoding_name.to_string()); for field_enc in &enc_fields { - encoding_struct.field(&format!("pub {}", field_enc.field_name), &field_enc.type_name); + encoding_struct.field( + &format!("pub {}", field_enc.field_name), + &field_enc.type_name, + ); } gen_scope.cbor_encodings().push_struct(encoding_struct); } @@ -4225,16 +5399,12 @@ fn generate_wrapper_struct(gen_scope: &mut GenerationScope, types: &Intermediate ("0", "self.0") }; let mut get = codegen::Function::new("get"); - get - .vis("pub") - .arg_ref_self(); + get.vis("pub").arg_ref_self(); if field_type.is_copy() { - get - .ret(field_type.for_rust_member(false)) + get.ret(field_type.for_rust_member(false)) .line(field_type.clone_if_not_copy(self_var)); } else { - get - .ret(format!("&{}", field_type.for_rust_member(false))) + get.ret(format!("&{}", field_type.for_rust_member(false))) .line(format!("&{}", self_var)); } s_impl.push_fn(get); @@ -4244,7 +5414,10 @@ fn generate_wrapper_struct(gen_scope: &mut GenerationScope, types: &Intermediate types, field_type.into(), &mut ser_func, - SerializeConfig::new(self_var, "inner").is_end(true).encoding_var_in_option_struct("self.encodings")); + SerializeConfig::new(self_var, "inner") + .is_end(true) + .encoding_var_in_option_struct("self.encodings"), + ); ser_impl.push_fn(ser_func); let mut deser_func = make_deserialization_function("deserialize"); let mut deser_impl = codegen::Impl::new(&type_name.to_string()); @@ -4255,9 +5428,7 @@ fn generate_wrapper_struct(gen_scope: &mut GenerationScope, types: &Intermediate } } let mut new_func = codegen::Function::new("new"); - new_func - .arg("inner", field_type.for_rust_move()) - .vis("pub"); + new_func.arg("inner", field_type.for_rust_move()).vis("pub"); let var_names_str = if CLI_ARGS.preserve_encodings { encoding_var_names_str("inner", &field_type) } else { @@ -4274,28 +5445,31 @@ fn generate_wrapper_struct(gen_scope: &mut GenerationScope, types: &Intermediate types, field_type.into(), DeserializeBeforeAfter::new(&before, after, false), - DeserializeConfig::new("inner")) + DeserializeConfig::new("inner"), + ) .add_to(&mut deser_func); - - let against = if field_type.encodings.contains(&CBOREncodingOperation::CBORBytes) { + + let against = if field_type + .encodings + .contains(&CBOREncodingOperation::CBORBytes) + { "inner.len()" } else { match &field_type.conceptual_type { ConceptualRustType::Primitive(p) => match p { - Primitive::Bytes | - Primitive::Str => "inner.len()", - Primitive::Bool | - Primitive::F32 | - Primitive::F64 | - Primitive::U8 | - Primitive::U16 | - Primitive::U32 | - Primitive::U64 | - Primitive::I8 | - Primitive::I16 | - Primitive::I32 | - Primitive::I64 | - Primitive::N64 => "inner", + Primitive::Bytes | Primitive::Str => "inner.len()", + Primitive::Bool + | Primitive::F32 + | Primitive::F64 + | Primitive::U8 + | Primitive::U16 + | Primitive::U32 + | Primitive::U64 + | Primitive::I8 + | Primitive::I16 + | Primitive::I32 + | Primitive::I64 + | Primitive::N64 => "inner", }, _ => unimplemented!(), } @@ -4353,7 +5527,8 @@ fn generate_wrapper_struct(gen_scope: &mut GenerationScope, types: &Intermediate let mut deser_ctor = codegen::Block::new("Ok(Self"); deser_ctor.line("inner,"); if !enc_fields.is_empty() { - let mut encoding_ctor = codegen::Block::new(&format!("encodings: Some({}", encoding_name)); + let mut encoding_ctor = + codegen::Block::new(&format!("encodings: Some({}", encoding_name)); for field_enc in enc_fields { encoding_ctor.line(format!("{},", field_enc.field_name)); } @@ -4381,7 +5556,15 @@ fn generate_wrapper_struct(gen_scope: &mut GenerationScope, types: &Intermediate .new_fn("try_from") .arg("inner", field_type.for_rust_member(false)) .ret("Result") - .line(format!("{}::new({})", type_name, ToWasmBoundaryOperations::format(field_type.from_wasm_boundary_clone("inner", false).into_iter()))); + .line(format!( + "{}::new({})", + type_name, + ToWasmBoundaryOperations::format( + field_type + .from_wasm_boundary_clone("inner", false) + .into_iter() + ) + )); try_from } else { // let field_type_tagged = if let Some(t) = tag { @@ -4402,13 +5585,15 @@ fn generate_wrapper_struct(gen_scope: &mut GenerationScope, types: &Intermediate types, field_type.into(), DeserializeBeforeAfter::new(&before, after, false), - DeserializeConfig::new("inner")) + DeserializeConfig::new("inner"), + ) .add_to(&mut deser_func); let mut deser_ctor = codegen::Block::new("Ok(Self"); deser_ctor.line("inner,"); if !enc_fields.is_empty() { - let mut encoding_ctor = codegen::Block::new(&format!("encodings: Some({}", encoding_name)); + let mut encoding_ctor = + codegen::Block::new(&format!("encodings: Some({}", encoding_name)); for field_enc in enc_fields { encoding_ctor.line(format!("{},", field_enc.field_name)); } @@ -4430,18 +5615,26 @@ fn generate_wrapper_struct(gen_scope: &mut GenerationScope, types: &Intermediate types, field_type.into(), DeserializeBeforeAfter::new("Ok(Self(", "))", false), - DeserializeConfig::new("inner")) + DeserializeConfig::new("inner"), + ) .add_to(&mut deser_func); new_func.line("Self(inner)"); } - + let mut from = codegen::Impl::new(&type_name.to_string()); - from - .impl_trait(format!("From<{}>", field_type.for_rust_member(false))) + from.impl_trait(format!("From<{}>", field_type.for_rust_member(false))) .new_fn("from") .arg("inner", field_type.for_rust_member(false)) .ret("Self") - .line(format!("{}::new({})", type_name, ToWasmBoundaryOperations::format(field_type.from_wasm_boundary_clone("inner", false).into_iter()))); + .line(format!( + "{}::new({})", + type_name, + ToWasmBoundaryOperations::format( + field_type + .from_wasm_boundary_clone("inner", false) + .into_iter() + ) + )); from }; deser_impl.push_fn(deser_func); @@ -4484,9 +5677,7 @@ fn key_derives(for_ignore: bool) -> &'static [&'static str] { } fn add_struct_derives(data_type: &mut T, used_in_key: bool, is_enum: bool) { - data_type - .derive("Clone") - .derive("Debug"); + data_type.derive("Clone").derive("Debug"); if CLI_ARGS.json_serde_derives { data_type .derive("serde::Deserialize") @@ -4499,11 +5690,19 @@ fn add_struct_derives(data_type: &mut T, used_in_key: bool, is_enum if CLI_ARGS.preserve_encodings { // there's no way to do non-derive() proc macros in the codegen // cate so we must sadly use a newline like this. codegen manages indentation - data_type.derive(&format!("Derivative)]\n#[derivative({}", key_derives(false).iter().map(|tr| match *tr { - // the derivative crate doesn't support enums tagged with ord/partialord yet without this - "Ord" | "PartialOrd" if is_enum => format!("{}=\"feature_allow_slow_enum\"", tr), - _ => String::from(*tr), - }).collect::>().join(", "))); + data_type.derive(&format!( + "Derivative)]\n#[derivative({}", + key_derives(false) + .iter() + .map(|tr| match *tr { + // the derivative crate doesn't support enums tagged with ord/partialord yet without this + "Ord" | "PartialOrd" if is_enum => + format!("{}=\"feature_allow_slow_enum\"", tr), + _ => String::from(*tr), + }) + .collect::>() + .join(", ") + )); } else { for key_derive in key_derives(false) { data_type.derive(key_derive); @@ -4557,12 +5756,14 @@ fn generate_int(gen_scope: &mut GenerationScope, types: &IntermediateTypes) { let mut uint = codegen::Variant::new("Uint"); let mut nint = codegen::Variant::new("Nint"); if CLI_ARGS.preserve_encodings { - uint - .named("value", "u64") - .named(&format!("{}encoding", encoding_var_macros(types.used_as_key(&ident))), "Option"); - nint - .named("value", "u64") - .named(&format!("{}encoding", encoding_var_macros(types.used_as_key(&ident))), "Option"); + uint.named("value", "u64").named( + &format!("{}encoding", encoding_var_macros(types.used_as_key(&ident))), + "Option", + ); + nint.named("value", "u64").named( + &format!("{}encoding", encoding_var_macros(types.used_as_key(&ident))), + "Option", + ); } else { uint.tuple("u64"); nint.tuple("u64"); @@ -4574,15 +5775,10 @@ fn generate_int(gen_scope: &mut GenerationScope, types: &IntermediateTypes) { // impl Int let mut native_impl = codegen::Impl::new("Int"); let mut new_uint = codegen::Function::new("new_uint"); - new_uint - .vis("pub") - .arg("value", "u64") - .ret("Self"); + new_uint.vis("pub").arg("value", "u64").ret("Self"); if CLI_ARGS.preserve_encodings { let mut new_uint_ctor = codegen::Block::new("Self::Uint"); - new_uint_ctor - .line("value,") - .line("encoding: None,"); + new_uint_ctor.line("value,").line("encoding: None,"); new_uint.push_block(new_uint_ctor); } else { new_uint.line("Self::Uint(value)"); @@ -4597,9 +5793,7 @@ fn generate_int(gen_scope: &mut GenerationScope, types: &IntermediateTypes) { .ret("Self"); if CLI_ARGS.preserve_encodings { let mut new_nint_ctor = codegen::Block::new("Self::Nint"); - new_nint_ctor - .line("value,") - .line("encoding: None,"); + new_nint_ctor.line("value,").line("encoding: None,"); new_nint.push_block(new_nint_ctor); } else { new_nint.line("Self::Nint(value)"); @@ -4644,10 +5838,7 @@ fn generate_int(gen_scope: &mut GenerationScope, types: &IntermediateTypes) { // traits let mut int_err = codegen::Enum::new("IntError"); - int_err - .vis("pub") - .derive("Clone") - .derive("Debug"); + int_err.vis("pub").derive("Clone").derive("Debug"); int_err .new_variant("Bounds") .tuple("std::num::TryFromIntError"); @@ -4673,7 +5864,7 @@ fn generate_int(gen_scope: &mut GenerationScope, types: &IntermediateTypes) { .arg("f", "&mut std::fmt::Formatter<'_>") .ret("std::fmt::Result") .push_block(display_match); - + let mut from_str = codegen::Impl::new("Int"); from_str .impl_trait("std::str::FromStr") @@ -4689,7 +5880,8 @@ fn generate_int(gen_scope: &mut GenerationScope, types: &IntermediateTypes) { let mut try_from_else = codegen::Block::new("else"); if CLI_ARGS.preserve_encodings { try_from_if.line("u64::try_from(x).map(|x| Self::Uint{ value: x, encoding: None })"); - try_from_else.line("u64::try_from((x + 1).abs()).map(|x| Self::Nint{ value: x, encoding: None })"); + try_from_else + .line("u64::try_from((x + 1).abs()).map(|x| Self::Nint{ value: x, encoding: None })"); } else { try_from_if.line("u64::try_from(x).map(Self::Uint)"); try_from_else.line("u64::try_from((x + 1).abs()).map(Self::Nint)"); @@ -4725,9 +5917,10 @@ fn rustfmt_path<'a>() -> std::io::Result> { #[cfg(feature = "which-rustfmt")] match which::which("rustfmt") { Ok(p) => Ok(Cow::Owned(p)), - Err(e) => { - Err(std::io::Error::new(std::io::ErrorKind::Other, format!("{}", e))) - } + Err(e) => Err(std::io::Error::new( + std::io::ErrorKind::Other, + format!("{}", e), + )), } #[cfg(not(feature = "which-rustfmt"))] Err(std::io::Error::new( @@ -4737,9 +5930,7 @@ fn rustfmt_path<'a>() -> std::io::Result> { } /// Runs rustfmt on the string -pub fn rustfmt_generated_string( - source: &str, -) -> std::io::Result> { +pub fn rustfmt_generated_string(source: &str) -> std::io::Result> { let mut cmd = Command::new(&rustfmt_path().unwrap().as_ref()); cmd.stdin(Stdio::piped()).stdout(Stdio::piped()); @@ -4774,15 +5965,15 @@ pub fn rustfmt_generated_string( Some(2) => { println!("Rustfmt parsing errors."); Ok(Cow::Owned(source)) - }, + } Some(3) => { println!("Rustfmt could not format some lines."); Ok(Cow::Owned(bindings)) } - _ =>{ + _ => { println!("Rustfmt internal error."); Ok(Cow::Owned(source)) - }, + } }, _ => Ok(Cow::Owned(source)), } diff --git a/src/intermediate.rs b/src/intermediate.rs index 147426a..2bf9533 100644 --- a/src/intermediate.rs +++ b/src/intermediate.rs @@ -1,16 +1,13 @@ -use std::collections::{BTreeMap, BTreeSet}; -use cbor_event::{Special, Type as CBORType}; use cbor_event::Special as CBORSpecial; +use cbor_event::{Special, Type as CBORType}; use cddl::ast::parent::ParentVisitor; +use std::collections::{BTreeMap, BTreeSet}; use crate::cli::CLI_ARGS; // TODO: move all of these generation specifics into generation.rs use crate::generation::table_type; use crate::utils::{ - cddl_prelude, - convert_to_camel_case, - convert_to_snake_case, - is_identifier_reserved, + cddl_prelude, convert_to_camel_case, convert_to_snake_case, is_identifier_reserved, is_identifier_user_defined, }; @@ -38,7 +35,10 @@ pub struct IntermediateTypes<'a> { impl<'a> IntermediateTypes<'a> { pub fn new() -> Self { let mut rust_structs = BTreeMap::new(); - rust_structs.insert(RustIdent::new(CDDLIdent::new("int")), RustStruct::new_extern(RustIdent::new(CDDLIdent::new("int")))); + rust_structs.insert( + RustIdent::new(CDDLIdent::new("int")), + RustStruct::new_extern(RustIdent::new(CDDLIdent::new("int"))), + ); Self { plain_groups: BTreeMap::new(), type_aliases: Self::aliases(), @@ -55,17 +55,27 @@ impl<'a> IntermediateTypes<'a> { pub fn has_ident(&self, ident: &RustIdent) -> bool { let foo: Vec = self.type_aliases.keys().fold(vec![], |mut acc, alias| { match alias { - AliasIdent::Reserved(_) => {}, - AliasIdent::Rust(ident) => { acc.push(ident.clone()) } + 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())); + 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) + || 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) } pub fn type_aliases(&self) -> &BTreeMap { @@ -85,7 +95,10 @@ impl<'a> IntermediateTypes<'a> { }; insert_alias("uint", ConceptualRustType::Primitive(Primitive::U64).into()); insert_alias("nint", ConceptualRustType::Primitive(Primitive::N64).into()); - insert_alias("bool", ConceptualRustType::Primitive(Primitive::Bool).into()); + insert_alias( + "bool", + ConceptualRustType::Primitive(Primitive::Bool).into(), + ); // TODO: define enum or something as otherwise it can overflow i64 // and also we can't define the serialization traits for types // that are defined outside of this crate (includes primitives) @@ -93,17 +106,38 @@ impl<'a> IntermediateTypes<'a> { let string_type: RustType = ConceptualRustType::Primitive(Primitive::Str).into(); insert_alias("tstr", string_type.clone()); insert_alias("text", string_type); - insert_alias("bstr", ConceptualRustType::Primitive(Primitive::Bytes).into()); - insert_alias("bytes", ConceptualRustType::Primitive(Primitive::Bytes).into()); + insert_alias( + "bstr", + ConceptualRustType::Primitive(Primitive::Bytes).into(), + ); + insert_alias( + "bytes", + ConceptualRustType::Primitive(Primitive::Bytes).into(), + ); let null_type: RustType = ConceptualRustType::Fixed(FixedValue::Null).into(); insert_alias("null", null_type.clone()); insert_alias("nil", null_type); - insert_alias("true", ConceptualRustType::Fixed(FixedValue::Bool(true)).into()); - insert_alias("false", ConceptualRustType::Fixed(FixedValue::Bool(false)).into()); + insert_alias( + "true", + ConceptualRustType::Fixed(FixedValue::Bool(true)).into(), + ); + insert_alias( + "false", + ConceptualRustType::Fixed(FixedValue::Bool(false)).into(), + ); // Note: defaulting to float64 for "float" (so without precision). - insert_alias("float", ConceptualRustType::Primitive(Primitive::F64).into()); - insert_alias("float64", ConceptualRustType::Primitive(Primitive::F64).into()); - insert_alias("float32", ConceptualRustType::Primitive(Primitive::F32).into()); + insert_alias( + "float", + ConceptualRustType::Primitive(Primitive::F64).into(), + ); + insert_alias( + "float64", + ConceptualRustType::Primitive(Primitive::F64).into(), + ); + insert_alias( + "float32", + ConceptualRustType::Primitive(Primitive::F32).into(), + ); // What about bingint/other stuff in the standard prelude? aliases } @@ -147,32 +181,51 @@ impl<'a> IntermediateTypes<'a> { // see new_type() for why this is mut /// returns: (base type, if the alias should be substituted) - pub fn apply_type_aliases(&mut self, alias_ident: &AliasIdent) -> Option<(RustType, bool)> { + pub fn apply_type_aliases(&mut self, alias_ident: &AliasIdent) -> Option<(RustType, bool)> { // Assumes we are not trying to pass in any kind of compound type (arrays, etc) match self.type_aliases.get(alias_ident) { - Some((alias, gen_alias, _)) => { - Some((alias.clone(), !gen_alias)) - } + Some((alias, gen_alias, _)) => Some((alias.clone(), !gen_alias)), None => match alias_ident { AliasIdent::Rust(_rust_ident) => None, - AliasIdent::Reserved(reserved) => if reserved == "int" { - // We define an Int rust struct in prelude.rs - None - } else { - // we auto-include only the parts of the cddl prelude necessary (and supported) - cddl_prelude(reserved).expect(&format!("Reserved ident {} not a part of cddl_prelude?", reserved)); - self.emit_prelude(reserved.clone()); - Some((ConceptualRustType::Rust(RustIdent::new(CDDLIdent::new(format!("prelude_{}", reserved)))).into(), true)) - }, + AliasIdent::Reserved(reserved) => { + if reserved == "int" { + // We define an Int rust struct in prelude.rs + None + } else { + // we auto-include only the parts of the cddl prelude necessary (and supported) + cddl_prelude(reserved).expect(&format!( + "Reserved ident {} not a part of cddl_prelude?", + reserved + )); + self.emit_prelude(reserved.clone()); + Some(( + ConceptualRustType::Rust(RustIdent::new(CDDLIdent::new(format!( + "prelude_{}", + reserved + )))) + .into(), + true, + )) + } + } }, } } - pub fn register_type_alias(&mut self, alias: RustIdent, base_type: RustType, generate_rust_alias: bool, generate_wasm_alias: bool) { + pub fn register_type_alias( + &mut self, + alias: RustIdent, + base_type: RustType, + generate_rust_alias: bool, + generate_wasm_alias: bool, + ) { if let ConceptualRustType::Alias(_ident, _ty) = &base_type.conceptual_type { panic!("register_type_alias*({}, {:?}) wrap automatically in Alias, no need to provide it.", alias, base_type); } - self.type_aliases.insert(alias.into(), (base_type, generate_rust_alias, generate_wasm_alias)); + self.type_aliases.insert( + alias.into(), + (base_type, generate_rust_alias, generate_wasm_alias), + ); } pub fn rust_struct(&self, ident: &RustIdent) -> Option<&RustStruct> { @@ -180,44 +233,55 @@ impl<'a> IntermediateTypes<'a> { } // this is called by register_table_type / register_array_type automatically - pub fn register_rust_struct(&mut self, parent_visitor: &ParentVisitor, rust_struct: RustStruct) { + pub fn register_rust_struct( + &mut self, + parent_visitor: &ParentVisitor, + rust_struct: RustStruct, + ) { match &rust_struct.variant { RustStructType::Table { domain, range } => { // we must provide the keys type to return - self.create_and_register_array_type(parent_visitor, domain.clone(), &domain.conceptual_type.name_as_wasm_array()); - let mut map_type: RustType = ConceptualRustType::Map(Box::new(domain.clone()), Box::new(range.clone())).into(); + self.create_and_register_array_type( + parent_visitor, + domain.clone(), + &domain.conceptual_type.name_as_wasm_array(), + ); + let mut map_type: RustType = + ConceptualRustType::Map(Box::new(domain.clone()), Box::new(range.clone())) + .into(); if let Some(tag) = rust_struct.tag { map_type = map_type.tag(tag); } - self.register_type_alias( - rust_struct.ident.clone(), - map_type, - true, - false) - }, + self.register_type_alias(rust_struct.ident.clone(), map_type, true, false) + } RustStructType::Array { element_type } => { - let mut array_type: RustType = ConceptualRustType::Array(Box::new(element_type.clone())).into(); + let mut array_type: RustType = + ConceptualRustType::Array(Box::new(element_type.clone())).into(); if let Some(tag) = rust_struct.tag { array_type = array_type.tag(tag); } - self.register_type_alias( - rust_struct.ident.clone(), - array_type, - true, - false) - }, - RustStructType::Wrapper { min_max: Some(_) , ..} => { + self.register_type_alias(rust_struct.ident.clone(), array_type, true, false) + } + RustStructType::Wrapper { + min_max: Some(_), .. + } => { self.mark_new_can_fail(rust_struct.ident.clone()); - }, + } _ => (), } - self.rust_structs.insert(rust_struct.ident().clone(), rust_struct); + self.rust_structs + .insert(rust_struct.ident().clone(), rust_struct); } // creates a RustType for the array type - and if needed, registers a type to generate // TODO: After the split we should be able to only register it directly // and then examine those at generation-time and handle things ALWAYS as RustType::Array - pub fn create_and_register_array_type(&mut self, parent_visitor: &ParentVisitor, element_type: RustType, array_type_name: &str) -> RustType { + pub fn create_and_register_array_type( + &mut self, + parent_visitor: &ParentVisitor, + element_type: RustType, + array_type_name: &str, + ) -> RustType { let raw_arr_type = ConceptualRustType::Array(Box::new(element_type.clone())); // only generate an array wrapper if we can't wasm-expose it raw if raw_arr_type.directly_wasm_exposable() { @@ -232,7 +296,10 @@ impl<'a> IntermediateTypes<'a> { if CLI_ARGS.wasm { // we don't pass in tags here. If a tag-wrapped array is done I think it generates // 2 separate types (array wrapper -> tag wrapper struct) - self.register_rust_struct(parent_visitor, RustStruct::new_array(array_type_ident, None, element_type.clone())); + self.register_rust_struct( + parent_visitor, + RustStruct::new_array(array_type_ident, None, element_type.clone()), + ); } ConceptualRustType::Array(Box::new(element_type)).into() } @@ -251,7 +318,11 @@ impl<'a> IntermediateTypes<'a> { pub fn finalize(&mut self, parent_visitor: &ParentVisitor) { // resolve generics // resolve then register in 2 phases to get around borrow checker - let resolved_generics = self.generic_instances.values().map(|instance| instance.resolve(self)).collect::>(); + let resolved_generics = self + .generic_instances + .values() + .map(|instance| instance.resolve(self)) + .collect::>(); for resolved_instance in resolved_generics { self.register_rust_struct(parent_visitor, resolved_instance); } @@ -263,14 +334,20 @@ impl<'a> IntermediateTypes<'a> { used_as_key.insert(ident.clone()); } } - fn check_used_as_key<'a>(ty: &ConceptualRustType, types: &IntermediateTypes<'a>, used_as_key: &mut BTreeSet) { + fn check_used_as_key<'a>( + ty: &ConceptualRustType, + types: &IntermediateTypes<'a>, + used_as_key: &mut BTreeSet, + ) { if let ConceptualRustType::Map(k, _v) = ty { k.visit_types(types, &mut |ty| mark_used_as_key(ty, used_as_key)); } } for rust_struct in self.rust_structs().values() { - rust_struct.visit_types(self, &mut |ty| check_used_as_key(ty, self, &mut used_as_key)); - if let RustStructType::Table{ domain, .. } = rust_struct.variant() { + rust_struct.visit_types(self, &mut |ty| { + check_used_as_key(ty, self, &mut used_as_key) + }); + if let RustStructType::Table { domain, .. } = rust_struct.variant() { domain.visit_types(self, &mut |ty| mark_used_as_key(ty, &mut used_as_key)); } } @@ -286,9 +363,11 @@ impl<'a> IntermediateTypes<'a> { pub fn is_referenced(&self, ident: &RustIdent) -> bool { let mut found = false; self.visit_types(&mut |ty| match ty { - ConceptualRustType::Rust(id) => if id == ident { - found = true - }, + ConceptualRustType::Rust(id) => { + if id == ident { + found = true + } + } _ => (), }); found @@ -300,7 +379,12 @@ impl<'a> IntermediateTypes<'a> { } // see self.plain_groups comments - pub fn set_rep_if_plain_group(&mut self, parent_visitor: &ParentVisitor, ident: &RustIdent, rep: Representation) { + pub fn set_rep_if_plain_group( + &mut self, + parent_visitor: &ParentVisitor, + ident: &RustIdent, + rep: Representation, + ) { if let Some(plain_group) = self.plain_groups.get(ident) { // the clone is to get around the borrow checker if let Some(group) = plain_group.as_ref().map(|g| g.clone()) { @@ -310,14 +394,22 @@ impl<'a> IntermediateTypes<'a> { // it's already defined, let's check that we're not giving it multiple representations let found_rep = match &rust_struct.variant { RustStructType::Record(record) => Some(record.rep), - RustStructType::GroupChoice{ rep, .. } => Some(*rep), + RustStructType::GroupChoice { rep, .. } => Some(*rep), _ => None, }; assert_eq!(found_rep, Some(rep)); } else { // you can't tag plain groups hence the None // we also don't support generics in plain groups hence the other None - crate::parsing::parse_group(self, parent_visitor, &group, ident, rep, None, None); + crate::parsing::parse_group( + self, + parent_visitor, + &group, + ident, + rep, + None, + None, + ); } } else { // If plain_group is None, then this wasn't defined in .cddl but instead @@ -344,7 +436,10 @@ impl<'a> IntermediateTypes<'a> { pub fn mark_scope(&mut self, ident: RustIdent, scope: String) { if let Some(old_scope) = self.scopes.insert(ident.clone(), scope.clone()) { if old_scope != scope { - panic!("{} defined multiple times, first referenced in scope '{}' then in '{}'", ident, old_scope, scope); + panic!( + "{} defined multiple times, first referenced in scope '{}' then in '{}'", + ident, old_scope, scope + ); } } } @@ -364,7 +459,7 @@ impl<'a> IntermediateTypes<'a> { println!("{}", plain_group.0); } } - + if !self.type_aliases.is_empty() { println!("\n\nAliases:"); for (alias_name, alias_type) in self.type_aliases.iter() { @@ -385,7 +480,7 @@ impl<'a> IntermediateTypes<'a> { println!("{} -> {:?}", ident, def); } } - + if !self.rust_structs.is_empty() { println!("\n\nRustStructs:"); for (ident, rust_struct) in self.rust_structs.iter() { @@ -401,7 +496,11 @@ impl<'a> IntermediateTypes<'a> { // TODO: we might want to custom-write some of these to make them // easier to use instead of directly parsing if self.prelude_to_emit.insert(cddl_name.clone()) { - let def = format!("prelude_{} = {}\n", cddl_name, cddl_prelude(&cddl_name).unwrap()); + let def = format!( + "prelude_{} = {}\n", + cddl_name, + cddl_prelude(&cddl_name).unwrap() + ); let cddl = cddl::parser::cddl_from_str(&def, true).unwrap(); assert_eq!(cddl.rules.len(), 1); let pv = ParentVisitor::new(&cddl).unwrap(); @@ -428,7 +527,10 @@ pub enum FixedValue { } fn convert_to_alphanumeric(input: &str) -> String { - input.chars().filter(|c| c.is_ascii_alphanumeric()).collect() + input + .chars() + .filter(|c| c.is_ascii_alphanumeric()) + .collect() } impl FixedValue { @@ -442,7 +544,9 @@ impl FixedValue { FixedValue::Nint(i) => VariantIdent::new_custom(format!("U{}", i)), FixedValue::Uint(u) => VariantIdent::new_custom(format!("I{}", u)), FixedValue::Float(f) => VariantIdent::new_custom(format!("F{}", f)), - FixedValue::Text(s) => VariantIdent::new_custom(convert_to_alphanumeric(&convert_to_camel_case(&s))), + FixedValue::Text(s) => { + VariantIdent::new_custom(convert_to_alphanumeric(&convert_to_camel_case(&s))) + } } } @@ -455,7 +559,8 @@ impl FixedValue { FixedValue::Uint(u) => buf.write_unsigned_integer(*u as u64), FixedValue::Float(f) => buf.write_special(Special::Float(*f)), FixedValue::Text(s) => buf.write_text(s), - }.expect("Unable to serialize key for canonical ordering"); + } + .expect("Unable to serialize key for canonical ordering"); buf.finalize() } @@ -477,7 +582,7 @@ impl FixedValue { pub fn to_primitive_str_compare(&self) -> String { match self { FixedValue::Text(s) => format!("\"{}\"", s), - _=> self.to_primitive_str_assign(), + _ => self.to_primitive_str_assign(), } } } @@ -571,7 +676,11 @@ impl Primitive { } mod idents { - use crate::{rust_reserved::STD_TYPES, utils::{is_identifier_reserved, is_identifier_in_our_prelude}, cli::CLI_ARGS}; + use crate::{ + cli::CLI_ARGS, + rust_reserved::STD_TYPES, + utils::{is_identifier_in_our_prelude, is_identifier_reserved}, + }; // to resolve ambiguities between raw (from CDDL) and already-formatted // for things like type aliases, etc, we use these wrapper structs @@ -615,9 +724,17 @@ mod idents { // int is special here since it refers to our own rust struct, not a primitive println!("{}", cddl_ident.0); - assert!(!STD_TYPES.contains(&&super::convert_to_camel_case(&cddl_ident.0)[..]), "Cannot use reserved Rust type name: \"{}\"", cddl_ident.0); + assert!( + !STD_TYPES.contains(&&super::convert_to_camel_case(&cddl_ident.0)[..]), + "Cannot use reserved Rust type name: \"{}\"", + cddl_ident.0 + ); if cddl_ident.0 != "int" { - assert!(!is_identifier_reserved(&cddl_ident.0), "Cannot use reserved CDDL keyword: \"{}\"", cddl_ident.0); + assert!( + !is_identifier_reserved(&cddl_ident.0), + "Cannot use reserved CDDL keyword: \"{}\"", + cddl_ident.0 + ); } Self(super::convert_to_camel_case(&cddl_ident.0)) @@ -738,7 +855,8 @@ impl RustType { } pub fn as_alias(mut self, alias_ident: AliasIdent) -> Self { - self.conceptual_type = ConceptualRustType::Alias(alias_ident, Box::new(self.conceptual_type)); + self.conceptual_type = + ConceptualRustType::Alias(alias_ident, Box::new(self.conceptual_type)); self } @@ -749,7 +867,9 @@ impl RustType { pub fn default(mut self, default_value: FixedValue) -> Self { assert!(self.default.is_none()); - let matches = if let ConceptualRustType::Primitive(p) = self.conceptual_type.clone().resolve_aliases() { + let matches = if let ConceptualRustType::Primitive(p) = + self.conceptual_type.clone().resolve_aliases() + { match &default_value { FixedValue::Bool(_) => p == Primitive::Bool, FixedValue::Nint(_) => p.cbor_types().contains(&CBORType::NegativeInteger), @@ -762,7 +882,10 @@ impl RustType { false }; if !matches { - panic!(".default {:?} invalid for type {:?}", default_value, self.conceptual_type); + panic!( + ".default {:?} invalid for type {:?}", + default_value, self.conceptual_type + ); } self.default = Some(default_value); self @@ -799,7 +922,7 @@ impl RustType { ConceptualRustType::Rust(_ident) => { //panic!("TODO: store first cbor tag somewhere") vec![CBORType::Array, CBORType::Map] - }, + } ConceptualRustType::Array(_) => vec![CBORType::Array], ConceptualRustType::Map(_k, _v) => vec![CBORType::Map], ConceptualRustType::Optional(ty) => { @@ -808,9 +931,9 @@ impl RustType { inner_types.push(CBORType::Special); } inner_types - }, + } ConceptualRustType::Alias(_ident, ty) => Self::new((**ty).clone()).cbor_types(), - } + }, } } @@ -827,7 +950,9 @@ impl RustType { ConceptualRustType::Array(_) => true, ConceptualRustType::Optional(_) => false, ConceptualRustType::Map(_, _) => false, - ConceptualRustType::Alias(_ident, ty) => Self::new((**ty).clone())._is_serialize_multiline(), + ConceptualRustType::Alias(_ident, ty) => { + Self::new((**ty).clone())._is_serialize_multiline() + } } } else { true @@ -857,7 +982,6 @@ pub enum ConceptualRustType { Map(Box, Box), // Alias for another type Alias(AliasIdent, Box), - // TODO: for non-table-type ones we could define a RustField(Ident, RustType) and then // a variant here Struct(Vec) and delegate field/argument generation to // RustField so that we could basically expand them and not care about having to generate @@ -870,7 +994,10 @@ impl ConceptualRustType { match self { Self::Array(ty) => Self::Array(Box::new(ty.resolve_aliases())), Self::Alias(_, ty) => ty.resolve_aliases(), - Self::Map(key, value) => Self::Map(Box::new(key.resolve_aliases()), Box::new(value.resolve_aliases())), + Self::Map(key, value) => Self::Map( + Box::new(key.resolve_aliases()), + Box::new(value.resolve_aliases()), + ), Self::Optional(ty) => Self::Optional(Box::new(ty.resolve_aliases())), _ => self, } @@ -891,18 +1018,18 @@ impl ConceptualRustType { match inner { Self::Primitive(p) => match p { // converts to js number which is supported as Vec - Primitive::Bool | - Primitive::F32 | - Primitive::F64 | - Primitive::I8 | - Primitive::U8 | - Primitive::I16 | - Primitive::U16 | - Primitive::I32 | - Primitive::U32 | - Primitive::I64 | - Primitive::N64 | - Primitive::U64 => true, + Primitive::Bool + | Primitive::F32 + | Primitive::F64 + | Primitive::I8 + | Primitive::U8 + | Primitive::I16 + | Primitive::U16 + | Primitive::I32 + | Primitive::U32 + | Primitive::I64 + | Primitive::N64 + | Primitive::U64 => true, // Bytes is already implemented as Vec so we can't nest it Primitive::Bytes => false, // Vec is not supported by wasm-bindgen @@ -911,7 +1038,7 @@ impl ConceptualRustType { Self::Array(_) => false, _ => ty.conceptual_type.directly_wasm_exposable(), } - }, + } Self::Optional(ty) => ty.conceptual_type.directly_wasm_exposable(), Self::Map(_, _) => false, Self::Alias(_ident, ty) => ty.directly_wasm_exposable(), @@ -946,7 +1073,10 @@ impl ConceptualRustType { /// Function parameter TYPE by-non-mut-reference for read-only pub fn _for_rust_read(&self) -> String { match self { - Self::Fixed(_) => panic!("should not expose Fixed type, only here for serialization: {:?}", self), + Self::Fixed(_) => panic!( + "should not expose Fixed type, only here for serialization: {:?}", + self + ), Self::Primitive(p) => p.to_string(), Self::Rust(ident) => format!("&{}", ident), Self::Array(ty) => format!("&{}", ty.conceptual_type.name_as_rust_array(false)), @@ -966,33 +1096,36 @@ impl ConceptualRustType { } fn for_wasm_param_impl(&self, force_not_ref: bool) -> String { - let opt_ref = if force_not_ref { - "" - } else { - "&" - }; + let opt_ref = if force_not_ref { "" } else { "&" }; match self { - Self::Fixed(_) => panic!("should not expose Fixed type to wasm, only here for serialization: {:?}", self), + Self::Fixed(_) => panic!( + "should not expose Fixed type to wasm, only here for serialization: {:?}", + self + ), Self::Primitive(p) => p.to_string(), Self::Rust(ident) => format!("{}{}", opt_ref, ident), - Self::Array(ty) => if self.directly_wasm_exposable() { - ty.conceptual_type.name_as_wasm_array() - } else { - format!("{}{}", opt_ref, ty.conceptual_type.name_as_wasm_array()) - }, - Self::Optional(ty) => format!("Option<{}>", ty.conceptual_type.for_wasm_param_impl(true)), + Self::Array(ty) => { + if self.directly_wasm_exposable() { + ty.conceptual_type.name_as_wasm_array() + } else { + format!("{}{}", opt_ref, ty.conceptual_type.name_as_wasm_array()) + } + } + Self::Optional(ty) => { + format!("Option<{}>", ty.conceptual_type.for_wasm_param_impl(true)) + } Self::Map(_k, _v) => format!("{}{}", opt_ref, self.for_wasm_member()), // it might not be worth generating this as aliases are ignored by wasm-pack build, but // that could change in the future so as long as it doens't cause issues we'll leave it Self::Alias(ident, ty) => match &**ty { - Self::Rust(_) | + Self::Rust(_) | Self::Array(_) | Self::Map(_, _) if !self.directly_wasm_exposable() => format!("{}{}", opt_ref, ident), Self::Optional(_) | // no special handling if for some reason nested aliases, just strip all to avoid hassle Self::Alias(_, _) => ty.for_wasm_param_impl(force_not_ref), _ => ident.to_string(), - } + }, } } @@ -1002,17 +1135,29 @@ impl ConceptualRustType { } pub fn name_for_wasm_map(k: &RustType, v: &RustType) -> RustIdent { - RustIdent::new(CDDLIdent::new(format!("Map{}To{}", k.conceptual_type.for_variant(), v.conceptual_type.for_variant()))) + RustIdent::new(CDDLIdent::new(format!( + "Map{}To{}", + k.conceptual_type.for_variant(), + v.conceptual_type.for_variant() + ))) } pub fn name_for_rust_map(k: &RustType, v: &RustType, from_wasm: bool) -> String { - format!("{}<{}, {}>", table_type(), k.conceptual_type.for_rust_member(from_wasm), v.conceptual_type.for_rust_member(from_wasm)) + format!( + "{}<{}, {}>", + table_type(), + k.conceptual_type.for_rust_member(from_wasm), + v.conceptual_type.for_rust_member(from_wasm) + ) } /// If we were to store a value directly in a wasm-wrapper, this would be used. pub fn for_wasm_member(&self) -> String { match self { - Self::Fixed(_) => panic!("should not expose Fixed type in member, only needed for serializaiton: {:?}", self), + Self::Fixed(_) => panic!( + "should not expose Fixed type in member, only needed for serializaiton: {:?}", + self + ), Self::Primitive(p) => p.to_string(), Self::Rust(ident) => ident.to_string(), Self::Array(ty) => ty.conceptual_type.name_as_wasm_array(), @@ -1030,17 +1175,18 @@ impl ConceptualRustType { /// Type when storing a value inside of a rust struct. This is the underlying raw representation. pub fn for_rust_member(&self, from_wasm: bool) -> String { - let core = if from_wasm { - "core::" - } else { - "" - }; + let core = if from_wasm { "core::" } else { "" }; match self { - Self::Fixed(_) => panic!("should not expose Fixed type in member, only needed for serializaiton: {:?}", self), + Self::Fixed(_) => panic!( + "should not expose Fixed type in member, only needed for serializaiton: {:?}", + self + ), Self::Primitive(p) => p.to_string(), Self::Rust(ident) => format!("{}{}", core, ident), Self::Array(ty) => ty.conceptual_type.name_as_rust_array(from_wasm), - Self::Optional(ty) => format!("Option<{}>", ty.conceptual_type.for_rust_member(from_wasm)), + Self::Optional(ty) => { + format!("Option<{}>", ty.conceptual_type.for_rust_member(from_wasm)) + } Self::Map(k, v) => Self::name_for_rust_map(k, v, from_wasm), Self::Alias(ident, ty) => match ident { // we don't generate type aliases for reserved types, just transform @@ -1058,9 +1204,13 @@ impl ConceptualRustType { Self::Fixed(f) => f.for_variant(), Self::Primitive(p) => p.to_variant(), Self::Rust(ident) => VariantIdent::new_rust(ident.clone()), - Self::Array(inner) => VariantIdent::new_custom(format!("Arr{}", inner.conceptual_type.for_variant())), + Self::Array(inner) => { + VariantIdent::new_custom(format!("Arr{}", inner.conceptual_type.for_variant())) + } // TODO: should we not end up in this situation and just insert a Null fixed value instead? - Self::Optional(ty) => VariantIdent::new_custom(format!("Opt{}", ty.conceptual_type.for_variant())), + Self::Optional(ty) => { + VariantIdent::new_custom(format!("Opt{}", ty.conceptual_type.for_variant())) + } Self::Map(k, v) => VariantIdent::new_custom(Self::name_for_wasm_map(k, v).to_string()), Self::Alias(ident, _ty) => match ident { AliasIdent::Rust(rust_ident) => VariantIdent::new_rust(rust_ident.clone()), @@ -1072,7 +1222,11 @@ impl ConceptualRustType { /// for parameter TYPES from wasm that take ownership (via cloning here) /// can_fail is for cases where checks (e.g. range checks) are done if there /// is a type transformation (i.e. wrapper types) like text (wasm) -> #6.14(text) (rust) - pub fn from_wasm_boundary_clone(&self, expr: &str, can_fail: bool) -> Vec { + pub fn from_wasm_boundary_clone( + &self, + expr: &str, + can_fail: bool, + ) -> Vec { let expr_cloned = if self.is_copy() { expr.to_owned() } else { @@ -1084,15 +1238,19 @@ impl ConceptualRustType { ToWasmBoundaryOperations::Into, ], Self::Alias(_ident, ty) => ty.from_wasm_boundary_clone(expr, can_fail), - Self::Optional(ty) => ty.conceptual_type.from_wasm_boundary_clone_optional(expr, can_fail), - Self::Array(ty) => if self.directly_wasm_exposable() { - ty.conceptual_type.from_wasm_boundary_clone(expr, can_fail) - } else { - vec![ - ToWasmBoundaryOperations::Code(expr_cloned), - ToWasmBoundaryOperations::Into, - ] - }, + Self::Optional(ty) => ty + .conceptual_type + .from_wasm_boundary_clone_optional(expr, can_fail), + Self::Array(ty) => { + if self.directly_wasm_exposable() { + ty.conceptual_type.from_wasm_boundary_clone(expr, can_fail) + } else { + vec![ + ToWasmBoundaryOperations::Code(expr_cloned), + ToWasmBoundaryOperations::Into, + ] + } + } Self::Map(_k, _v) => vec![ ToWasmBoundaryOperations::Code(expr_cloned), ToWasmBoundaryOperations::Into, @@ -1105,13 +1263,15 @@ impl ConceptualRustType { ops } - fn from_wasm_boundary_clone_optional(&self, expr: &str, can_fail: bool) -> Vec { + fn from_wasm_boundary_clone_optional( + &self, + expr: &str, + can_fail: bool, + ) -> Vec { let mut ops = match self { Self::Primitive(_p) => vec![ToWasmBoundaryOperations::Code(expr.to_owned())], Self::Alias(_ident, ty) => ty.from_wasm_boundary_clone_optional(expr, can_fail), - Self::Array(..) | - Self::Rust(..) | - Self::Map(..) => vec![ + Self::Array(..) | Self::Rust(..) | Self::Map(..) => vec![ ToWasmBoundaryOperations::Code(expr.to_owned()), if can_fail { ToWasmBoundaryOperations::MapTryInto @@ -1133,11 +1293,13 @@ impl ConceptualRustType { Self::Rust(_ident) => expr.to_owned(), Self::Alias(_ident, ty) => ty.from_wasm_boundary_ref(expr), Self::Optional(ty) => ty.conceptual_type.from_wasm_boundary_ref(expr), - Self::Array(ty) => if self.directly_wasm_exposable() { - ty.conceptual_type.from_wasm_boundary_ref(expr) - } else { - expr.to_owned() - }, + Self::Array(ty) => { + if self.directly_wasm_exposable() { + ty.conceptual_type.from_wasm_boundary_ref(expr) + } else { + expr.to_owned() + } + } Self::Map(_k, _v) => expr.to_owned(), _ => format!("&{}", expr), } @@ -1147,23 +1309,27 @@ impl ConceptualRustType { pub fn to_wasm_boundary(&self, expr: &str, is_ref: bool) -> String { match self { Self::Fixed(_) => panic!("fixed types are a serialization detail"), - Self::Primitive(_p) => if self.is_copy() { - if is_ref { - format!("*{}", expr) + Self::Primitive(_p) => { + if self.is_copy() { + if is_ref { + format!("*{}", expr) + } else { + expr.to_owned() + } } else { - expr.to_owned() + format!("{}.clone()", expr) } - } else { - format!("{}.clone()", expr) - }, + } Self::Rust(_ident) => format!("{}.clone().into()", expr), //Self::Array(ty) => format!("{}({}.clone())", ty.name_as_wasm_array(), expr), //Self::Map(k, v) => format!("{}({}.clone())", Self::name_for_wasm_map(k, v), expr), - Self::Array(_ty) => if self.directly_wasm_exposable() { - format!("{}.clone()", expr) - } else { - format!("{}.clone().into()", expr) - }, + Self::Array(_ty) => { + if self.directly_wasm_exposable() { + format!("{}.clone()", expr) + } else { + format!("{}.clone().into()", expr) + } + } Self::Map(_k, _v) => format!("{}.clone().into()", expr), Self::Optional(ty) => ty.conceptual_type.to_wasm_boundary_optional(expr, is_ref), Self::Alias(_ident, ty) => ty.to_wasm_boundary(expr, is_ref), @@ -1185,20 +1351,19 @@ impl ConceptualRustType { match self { Self::Fixed(_f) => unreachable!(), Self::Primitive(p) => match p { - Primitive::Bool | - Primitive::F32 | - Primitive::F64 | - Primitive::I8 | - Primitive::I16 | - Primitive::I32 | - Primitive::I64 | - Primitive::N64 | - Primitive::U8 | - Primitive::U16 | - Primitive::U32 | - Primitive::U64 => true, - Primitive::Str | - Primitive::Bytes => false, + Primitive::Bool + | Primitive::F32 + | Primitive::F64 + | Primitive::I8 + | Primitive::I16 + | Primitive::I32 + | Primitive::I64 + | Primitive::N64 + | Primitive::U8 + | Primitive::U16 + | Primitive::U32 + | Primitive::U64 => true, + Primitive::Str | Primitive::Bytes => false, }, Self::Rust(_ident) => false, Self::Array(_) => false, @@ -1228,11 +1393,13 @@ impl ConceptualRustType { // Once we split up parsing and codegen this shouldn't happen but with our current multi-pass // approach we might have out of order struct references which would break here without it // but on the final pass (the one we export) this should't be an issue - Self::Rust(ident) => if types.is_plain_group(ident) { - types.rust_structs.get(&ident)?.fixed_field_count(types) - } else { - Some(1) - }, + Self::Rust(ident) => { + if types.is_plain_group(ident) { + types.rust_structs.get(&ident)?.fixed_field_count(types) + } else { + Some(1) + } + } Self::Alias(_ident, ty) => ty.expanded_field_count(types), _ => Some(1), } @@ -1246,18 +1413,27 @@ impl ConceptualRustType { match self.expanded_field_count(types) { Some(count) => count.to_string(), None => match self { - Self::Optional(ty) => format!("match {} {{ Some(x) => {}, None => 1 }}", self_expr, ty.conceptual_type.definite_info("x", types)), - Self::Rust(ident) => if types.is_plain_group(ident) { - match types.rust_structs.get(&ident) { - Some(rs) => rs.definite_info(types), - None => panic!("rust struct {} not found but referenced by {:?}", ident, self), + Self::Optional(ty) => format!( + "match {} {{ Some(x) => {}, None => 1 }}", + self_expr, + ty.conceptual_type.definite_info("x", types) + ), + Self::Rust(ident) => { + if types.is_plain_group(ident) { + match types.rust_structs.get(&ident) { + Some(rs) => rs.definite_info(types), + None => panic!( + "rust struct {} not found but referenced by {:?}", + ident, self + ), + } + } else { + String::from("1") } - } else { - String::from("1") - }, + } Self::Alias(_ident, ty) => ty.definite_info(self_expr, types), _ => String::from("1"), - } + }, } } @@ -1270,16 +1446,18 @@ impl ConceptualRustType { Some(1) => 1, _ => 0, }, - Self::Rust(ident) => if types.is_plain_group(ident) { - println!("ident: {}", ident); - match types.rust_structs.get(&ident) { - Some(x) => x.expanded_mandatory_field_count(types), - None => panic!("could not find ident: {}", ident), + Self::Rust(ident) => { + if types.is_plain_group(ident) { + println!("ident: {}", ident); + match types.rust_structs.get(&ident) { + Some(x) => x.expanded_mandatory_field_count(types), + None => panic!("could not find ident: {}", ident), + } + //types.rust_structs.get(&ident).unwrap().expanded_mandatory_field_count(types) + } else { + 1 } - //types.rust_structs.get(&ident).unwrap().expanded_mandatory_field_count(types) - } else { - 1 - }, + } Self::Alias(_ident, ty) => ty.expanded_mandatory_field_count(types), _ => 1, } @@ -1289,7 +1467,12 @@ impl ConceptualRustType { self.visit_types_excluding(types, f, &mut BTreeSet::new()) } - pub fn visit_types_excluding(&self, types: &IntermediateTypes, f: &mut F, already_visited: &mut BTreeSet) { + pub fn visit_types_excluding( + &self, + types: &IntermediateTypes, + f: &mut F, + already_visited: &mut BTreeSet, + ) { f(self); match self { Self::Alias(ident, ty) => { @@ -1298,23 +1481,32 @@ impl ConceptualRustType { if already_visited.insert(rust_ident.clone()) { ty.visit_types_excluding(types, f, already_visited) } - }, - _ => ty.visit_types_excluding(types, f, already_visited) + } + _ => ty.visit_types_excluding(types, f, already_visited), }; - }, - Self::Array(ty) => ty.conceptual_type.visit_types_excluding(types, f, already_visited), + } + Self::Array(ty) => ty + .conceptual_type + .visit_types_excluding(types, f, already_visited), Self::Fixed(_) => (), Self::Map(k, v) => { - k.conceptual_type.visit_types_excluding(types, f, already_visited); - v.conceptual_type.visit_types_excluding(types, f, already_visited); - }, - Self::Optional(ty) => ty.conceptual_type.visit_types_excluding(types, f, already_visited), + k.conceptual_type + .visit_types_excluding(types, f, already_visited); + v.conceptual_type + .visit_types_excluding(types, f, already_visited); + } + Self::Optional(ty) => { + ty.conceptual_type + .visit_types_excluding(types, f, already_visited) + } Self::Primitive(_) => (), Self::Rust(ident) => { if already_visited.insert(ident.clone()) { - types.rust_struct(ident).map(|t| t.visit_types_excluding(types, f, already_visited)); + types + .rust_struct(ident) + .map(|t| t.visit_types_excluding(types, f, already_visited)); } - }, + } } } } @@ -1339,17 +1531,13 @@ impl ToWasmBoundaryOperations { }, Self::TryInto => match next { Self::Code(_) => None, - Self::Into | - Self::TryInto => Some(Self::TryInto), - Self::MapInto | - Self::MapTryInto => Some(Self::MapTryInto), + Self::Into | Self::TryInto => Some(Self::TryInto), + Self::MapInto | Self::MapTryInto => Some(Self::MapTryInto), }, Self::MapInto => match next { Self::Code(_) => None, - Self::Into | - Self::MapInto => Some(Self::MapInto), - Self::TryInto | - Self::MapTryInto => Some(Self::MapTryInto), + Self::Into | Self::MapInto => Some(Self::MapInto), + Self::TryInto | Self::MapTryInto => Some(Self::MapTryInto), }, Self::MapTryInto => match next { Self::Code(_) => None, @@ -1364,20 +1552,18 @@ impl ToWasmBoundaryOperations { let mut current: Option = None; while let Some(to_apply) = operations.next() { match current { - Some(c) => { - match c.merge(&to_apply) { - Some(merged) => { - current = Some(merged); - }, - None => { - write!(buf, "{}", c).unwrap(); - current = Some(to_apply); - }, + Some(c) => match c.merge(&to_apply) { + Some(merged) => { + current = Some(merged); + } + None => { + write!(buf, "{}", c).unwrap(); + current = Some(to_apply); } }, None => { current = Some(to_apply); - }, + } } } if let Some(c) = current { @@ -1489,7 +1675,7 @@ pub enum RustStructType { variants: Vec, rep: Representation, }, - Wrapper{ + Wrapper { wrapped: RustType, min_max: Option<(Option, Option)>, }, @@ -1508,14 +1694,16 @@ impl RustStruct { } } - pub fn new_table(ident: RustIdent, tag: Option, domain: RustType, range: RustType) -> Self { + pub fn new_table( + ident: RustIdent, + tag: Option, + domain: RustType, + range: RustType, + ) -> Self { Self { ident, tag, - variant: RustStructType::Table { - domain, - range, - }, + variant: RustStructType::Table { domain, range }, } } @@ -1523,34 +1711,41 @@ impl RustStruct { Self { ident, tag, - variant: RustStructType::Array { - element_type, - }, + variant: RustStructType::Array { element_type }, } } - pub fn new_type_choice(ident: RustIdent, tag: Option, variants: Vec) -> Self { + pub fn new_type_choice( + ident: RustIdent, + tag: Option, + variants: Vec, + ) -> Self { Self { ident, tag, - variant: RustStructType::TypeChoice { - variants - } + variant: RustStructType::TypeChoice { variants }, } } - pub fn new_group_choice(ident: RustIdent, tag: Option, variants: Vec, rep: Representation) -> Self { + pub fn new_group_choice( + ident: RustIdent, + tag: Option, + variants: Vec, + rep: Representation, + ) -> Self { Self { ident, tag, - variant: RustStructType::GroupChoice { - variants, - rep - } + variant: RustStructType::GroupChoice { variants, rep }, } } - pub fn new_wrapper(ident: RustIdent, tag: Option, wrapped_type: RustType, min_max: Option<(Option, Option)>) -> Self { + pub fn new_wrapper( + ident: RustIdent, + tag: Option, + wrapped_type: RustType, + min_max: Option<(Option, Option)>, + ) -> Self { Self { ident, tag, @@ -1584,19 +1779,25 @@ impl RustStruct { // The following methods are used internally to generate serialize/deserialize code // INSIDE of the serialize/deserialize implementations for this specific type. // You probably aren't interested in this from outside of that use-case. - + // Some(count) if it always has the same number of fields (ie no optional fields), None otherwise pub fn fixed_field_count(&self, types: &IntermediateTypes) -> Option { match &self.variant { RustStructType::Record(record) => record.fixed_field_count(types), - RustStructType::Table{ .. } => None, - RustStructType::Array{ .. } => None, + RustStructType::Table { .. } => None, + RustStructType::Array { .. } => None, // TODO: investigate if we should be supporting this for TypeChoice (also wrapper?) //RustStructType::TypeChoice { .. } => None, - RustStructType::TypeChoice{ .. } => unreachable!("I don't think type choices should be using length?"), - RustStructType::GroupChoice{ .. } => unreachable!("I don't think group choices should be using length?"), - RustStructType::Wrapper{ .. } => unreachable!("wrapper types don't use length"), - RustStructType::Extern{ .. } => panic!("do we need to look this up ever? will the prelude have structs with fields?"), + RustStructType::TypeChoice { .. } => { + unreachable!("I don't think type choices should be using length?") + } + RustStructType::GroupChoice { .. } => { + unreachable!("I don't think group choices should be using length?") + } + RustStructType::Wrapper { .. } => unreachable!("wrapper types don't use length"), + RustStructType::Extern { .. } => panic!( + "do we need to look this up ever? will the prelude have structs with fields?" + ), } } @@ -1606,12 +1807,18 @@ impl RustStruct { pub fn definite_info(&self, types: &IntermediateTypes) -> String { match &self.variant { RustStructType::Record(record) => record.definite_info(types), - RustStructType::Table{ .. } => String::from("self.0.len() as u64"), - RustStructType::Array{ .. } => String::from("self.0.len() as u64"), - RustStructType::TypeChoice{ .. } => unreachable!("I don't think type choices should be using length?"), - RustStructType::GroupChoice{ .. } => unreachable!("I don't think group choices should be using length?"), - RustStructType::Wrapper{ .. } => unreachable!("wrapper types don't use length"), - RustStructType::Extern{ .. } => panic!("do we need to look this up ever? will the prelude have structs with fields?"), + RustStructType::Table { .. } => String::from("self.0.len() as u64"), + RustStructType::Array { .. } => String::from("self.0.len() as u64"), + RustStructType::TypeChoice { .. } => { + unreachable!("I don't think type choices should be using length?") + } + RustStructType::GroupChoice { .. } => { + unreachable!("I don't think group choices should be using length?") + } + RustStructType::Wrapper { .. } => unreachable!("wrapper types don't use length"), + RustStructType::Extern { .. } => panic!( + "do we need to look this up ever? will the prelude have structs with fields?" + ), } } @@ -1621,43 +1828,77 @@ impl RustStruct { pub fn expanded_mandatory_field_count(&self, types: &IntermediateTypes) -> usize { match &self.variant { RustStructType::Record(record) => record.expanded_mandatory_field_count(types), - RustStructType::Table{ .. } => 0, - RustStructType::Array{ .. } => 0, + RustStructType::Table { .. } => 0, + RustStructType::Array { .. } => 0, //RustStructType::TypeChoice{ .. } => 0, - RustStructType::TypeChoice{ .. } => unreachable!("I don't think type choices should be using length?"), - RustStructType::GroupChoice{ .. } => unreachable!("I don't think group choices should be using length?"), - RustStructType::Wrapper{ .. } => unreachable!("wrapper types don't use length"), - RustStructType::Extern{ .. } => panic!("do we need to look this up ever? will the prelude have structs with fields?"), + RustStructType::TypeChoice { .. } => { + unreachable!("I don't think type choices should be using length?") + } + RustStructType::GroupChoice { .. } => { + unreachable!("I don't think group choices should be using length?") + } + RustStructType::Wrapper { .. } => unreachable!("wrapper types don't use length"), + RustStructType::Extern { .. } => panic!( + "do we need to look this up ever? will the prelude have structs with fields?" + ), } } fn _cbor_len_info(&self, types: &IntermediateTypes) -> RustStructCBORLen { match &self.variant { RustStructType::Record(record) => record.cbor_len_info(types), - RustStructType::Table{ .. } => RustStructCBORLen::Dynamic, - RustStructType::Array{ .. } => RustStructCBORLen::Dynamic, + RustStructType::Table { .. } => RustStructCBORLen::Dynamic, + RustStructType::Array { .. } => RustStructCBORLen::Dynamic, //RustStructType::TypeChoice{ .. } => RustStructCBORLen::Dynamic, - RustStructType::TypeChoice{ .. } => unreachable!("I don't think type choices should be using length?"), - RustStructType::GroupChoice{ .. } => unreachable!("I don't think group choices should be using length?"), - RustStructType::Wrapper{ .. } => unreachable!("wrapper types don't use length"), - RustStructType::Extern{ .. } => panic!("do we need to look this up ever? will the prelude have structs with fields?"), + RustStructType::TypeChoice { .. } => { + unreachable!("I don't think type choices should be using length?") + } + RustStructType::GroupChoice { .. } => { + unreachable!("I don't think group choices should be using length?") + } + RustStructType::Wrapper { .. } => unreachable!("wrapper types don't use length"), + RustStructType::Extern { .. } => panic!( + "do we need to look this up ever? will the prelude have structs with fields?" + ), } } pub fn visit_types(&self, types: &IntermediateTypes, f: &mut F) { self.visit_types_excluding(types, f, &mut BTreeSet::new()) } - pub fn visit_types_excluding(&self, types: &IntermediateTypes, f: &mut F, already_visited: &mut BTreeSet) { + pub fn visit_types_excluding( + &self, + types: &IntermediateTypes, + f: &mut F, + already_visited: &mut BTreeSet, + ) { match &self.variant { - RustStructType::Array{ element_type } => element_type.conceptual_type.visit_types_excluding(types, f, already_visited), - RustStructType::GroupChoice{ variants, .. } | - RustStructType::TypeChoice{ variants, .. } => variants.iter().for_each(|v| v.rust_type.conceptual_type.visit_types_excluding(types, f, already_visited)), - RustStructType::Record(record) => record.fields.iter().for_each(|field| field.rust_type.conceptual_type.visit_types_excluding(types, f, already_visited)), - RustStructType::Table{domain, range} => { - domain.conceptual_type.visit_types_excluding(types, f, already_visited); - range.conceptual_type.visit_types_excluding(types, f, already_visited); - }, - RustStructType::Wrapper{ wrapped, .. } => wrapped.conceptual_type.visit_types_excluding(types, f, already_visited), + RustStructType::Array { element_type } => element_type + .conceptual_type + .visit_types_excluding(types, f, already_visited), + RustStructType::GroupChoice { variants, .. } + | RustStructType::TypeChoice { variants, .. } => variants.iter().for_each(|v| { + v.rust_type + .conceptual_type + .visit_types_excluding(types, f, already_visited) + }), + RustStructType::Record(record) => record.fields.iter().for_each(|field| { + field + .rust_type + .conceptual_type + .visit_types_excluding(types, f, already_visited) + }), + RustStructType::Table { domain, range } => { + domain + .conceptual_type + .visit_types_excluding(types, f, already_visited); + range + .conceptual_type + .visit_types_excluding(types, f, already_visited); + } + RustStructType::Wrapper { wrapped, .. } => wrapped + .conceptual_type + .visit_types_excluding(types, f, already_visited), RustStructType::Extern => (), } } @@ -1678,14 +1919,17 @@ impl RustRecord { return None; } count += match self.rep { - Representation::Array => field.rust_type.conceptual_type.expanded_field_count(types)?, + Representation::Array => field + .rust_type + .conceptual_type + .expanded_field_count(types)?, Representation::Map => 1, }; } Some(count) } - // This is guaranteed + // This is guaranteed pub fn definite_info(&self, types: &IntermediateTypes) -> String { match self.fixed_field_count(types) { Some(count) => count.to_string(), @@ -1698,7 +1942,10 @@ impl RustRecord { conditional_field_expr.push_str(" + "); } let (field_expr, field_contribution) = match self.rep { - Representation::Array => ("x", field.rust_type.conceptual_type.definite_info("x", types)), + Representation::Array => ( + "x", + field.rust_type.conceptual_type.definite_info("x", types), + ), // maps are defined by their keys instead (although they shouldn't have multi-length values either...) Representation::Map => ("_", String::from("1")), }; @@ -1715,31 +1962,46 @@ impl RustRecord { "if self.{} != {} {{ {} }} else {{ 0 }}", field.name, default_value.to_primitive_str_compare(), - field_contribution)); + field_contribution + )); } } else { - conditional_field_expr.push_str(&format!("match &self.{} {{ Some({}) => {}, None => 0 }}", field.name, field_expr, field_contribution)); + conditional_field_expr.push_str(&format!( + "match &self.{} {{ Some({}) => {}, None => 0 }}", + field.name, field_expr, field_contribution + )); } } else { match self.rep { - Representation::Array => match field.rust_type.conceptual_type.expanded_field_count(types) { - Some(field_expanded_count) => fixed_field_count += field_expanded_count, - None => { - if !conditional_field_expr.is_empty() { - conditional_field_expr.push_str(" + "); + Representation::Array => { + match field.rust_type.conceptual_type.expanded_field_count(types) { + Some(field_expanded_count) => { + fixed_field_count += field_expanded_count + } + None => { + if !conditional_field_expr.is_empty() { + conditional_field_expr.push_str(" + "); + } + let field_len_expr = field + .rust_type + .conceptual_type + .definite_info(&format!("self.{}", field.name), types); + conditional_field_expr.push_str(&field_len_expr); } - let field_len_expr = field.rust_type.conceptual_type.definite_info(&format!("self.{}", field.name), types); - conditional_field_expr.push_str(&field_len_expr); - }, - }, + } + } Representation::Map => { fixed_field_count += 1; - }, + } }; } } if conditional_field_expr.is_empty() || fixed_field_count != 0 { - format!("{} + {}", fixed_field_count.to_string(), conditional_field_expr) + format!( + "{} + {}", + fixed_field_count.to_string(), + conditional_field_expr + ) } else { conditional_field_expr } @@ -1748,7 +2010,16 @@ impl RustRecord { } pub fn expanded_mandatory_field_count(&self, types: &IntermediateTypes) -> usize { - self.fields.iter().filter(|field| !field.optional).map(|field| field.rust_type.conceptual_type.expanded_mandatory_field_count(types)).sum() + self.fields + .iter() + .filter(|field| !field.optional) + .map(|field| { + field + .rust_type + .conceptual_type + .expanded_mandatory_field_count(types) + }) + .sum() } pub fn cbor_len_info(&self, types: &IntermediateTypes) -> RustStructCBORLen { @@ -1799,7 +2070,11 @@ pub struct GenericInstance { } impl GenericInstance { - pub fn new(instance_ident: RustIdent, generic_ident: RustIdent, generic_args: Vec) -> Self { + pub fn new( + instance_ident: RustIdent, + generic_ident: RustIdent, + generic_args: Vec, + ) -> Self { Self { instance_ident, generic_ident, @@ -1812,45 +2087,50 @@ impl GenericInstance { pub fn resolve(&self, types: &IntermediateTypes) -> RustStruct { let def = match types.generic_defs.get(&self.generic_ident) { Some(def) => def, - None => panic!("Generic instance used on {} without definition", self.generic_ident), + None => panic!( + "Generic instance used on {} without definition", + self.generic_ident + ), }; assert_eq!(def.generic_params.len(), self.generic_args.len()); let resolved_args = def .generic_params .iter() .zip(self.generic_args.iter()) - .collect::>(); + .collect::>(); let mut instance = def.orig.clone(); instance.ident = self.instance_ident.clone(); - + match &mut instance.variant { RustStructType::Record(record) => { for field in record.fields.iter_mut() { field.rust_type = Self::resolve_type(&resolved_args, &field.rust_type); } - }, - RustStructType::Table{ domain, range } => { + } + RustStructType::Table { domain, range } => { *domain = Self::resolve_type(&resolved_args, domain); *range = Self::resolve_type(&resolved_args, range); - }, - RustStructType::Array{ element_type } => { + } + RustStructType::Array { element_type } => { *element_type = Self::resolve_type(&resolved_args, element_type); - }, - RustStructType::TypeChoice{ variants } => { + } + RustStructType::TypeChoice { variants } => { for variant in variants.iter_mut() { variant.rust_type = Self::resolve_type(&resolved_args, &variant.rust_type); } - }, - RustStructType::GroupChoice{ .. } => { + } + RustStructType::GroupChoice { .. } => { // for variant in variants.mut_iter() { // variant.rust_type = Self::resolve_type(&resolved_args, &variant.rust_type); // } todo!("we might need to recursively resolve on these"); - }, - RustStructType::Wrapper{ .. } => { + } + RustStructType::Wrapper { .. } => { todo!("should we look this up in types to resolve?"); - }, - RustStructType::Extern => panic!("generics should not be used on types in the prelude (e.g. int)"), + } + RustStructType::Extern => { + panic!("generics should not be used on types in the prelude (e.g. int)") + } }; instance } @@ -1865,11 +2145,15 @@ impl GenericInstance { } } -fn try_ident_with_id(intermediate_types: &IntermediateTypes, name: &CDDLIdent, value: u32) -> CDDLIdent { +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) + true => try_ident_with_id(intermediate_types, name, value + 1), } } diff --git a/src/main.rs b/src/main.rs index 4474998..ada0414 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,30 +1,25 @@ -pub (crate) mod cli; -pub (crate) mod dep_graph; -pub (crate) mod generation; -pub (crate) mod intermediate; -pub (crate) mod parsing; -pub (crate) mod utils; -pub (crate) mod rust_reserved; -pub (crate) mod comment_ast; +pub(crate) mod cli; +pub(crate) mod comment_ast; +pub(crate) mod dep_graph; +pub(crate) mod generation; +pub(crate) mod intermediate; +pub(crate) mod parsing; +pub(crate) mod rust_reserved; +pub(crate) mod utils; #[cfg(test)] mod test; use generation::GenerationScope; -use intermediate::{ - CDDLIdent, - IntermediateTypes, - RustIdent, -}; -use parsing::{ - parse_rule, - rule_ident, - rule_is_scope_marker -}; +use intermediate::{CDDLIdent, IntermediateTypes, RustIdent}; +use parsing::{parse_rule, rule_ident, rule_is_scope_marker}; use cli::CLI_ARGS; -fn cddl_paths(output: &mut Vec, cd: &std::path::PathBuf) -> std::io::Result<()> { +fn cddl_paths( + output: &mut Vec, + cd: &std::path::PathBuf, +) -> std::io::Result<()> { for dir_entry in std::fs::read_dir(cd)? { let path = dir_entry?.path(); if path.is_dir() { @@ -61,12 +56,20 @@ fn main() -> Result<(), Box> { .map(|(i, input_file)| { let scope = if input_files.len() > 1 { input_file.file_stem().unwrap().to_str().unwrap() - } else { + } else { "lib" }; - std::fs::read_to_string(input_file) - .map(|raw| format!("\n{}{} = \"{}\"\n{}\n", parsing::SCOPE_MARKER, i, scope, raw)) - }).collect::>()?; + std::fs::read_to_string(input_file).map(|raw| { + format!( + "\n{}{} = \"{}\"\n{}\n", + parsing::SCOPE_MARKER, + i, + scope, + raw + ) + }) + }) + .collect::>()?; // we also need to mark the extern marker to a placeholder struct that won't get codegened input_files_content.push_str(&format!("{} = [0]", parsing::EXTERN_MARKER)); @@ -77,27 +80,34 @@ fn main() -> Result<(), Box> { let mut types = IntermediateTypes::new(); // mark scope and filter scope markers let mut scope = "lib".to_owned(); - let cddl_rules = cddl.rules.iter().filter(|cddl_rule| { - // We inserted string constants with specific prefixes earlier to mark scope - if let Some(new_scope) = rule_is_scope_marker(*cddl_rule) { - println!("Switching from scope '{}' to '{}'", scope, new_scope); - scope = new_scope; - false - } else { - let ident = rule_ident(cddl_rule); - types.mark_scope(ident, scope.clone()); - true - } - }).collect::>(); + let cddl_rules = cddl + .rules + .iter() + .filter(|cddl_rule| { + // We inserted string constants with specific prefixes earlier to mark scope + if let Some(new_scope) = rule_is_scope_marker(*cddl_rule) { + println!("Switching from scope '{}' to '{}'", scope, new_scope); + scope = new_scope; + false + } else { + let ident = rule_ident(cddl_rule); + types.mark_scope(ident, scope.clone()); + true + } + }) + .collect::>(); // We need to know beforehand which are plain groups so we can serialize them properly // e.g. x = (3, 4), y = [1, x, 2] should be [1, 3, 4, 2] instead of [1, [3, 4], 2] for cddl_rule in cddl_rules.iter() { - if let cddl::ast::Rule::Group{ rule, .. } = cddl_rule { + if let cddl::ast::Rule::Group { rule, .. } = cddl_rule { // Freely defined group - no need to generate anything outside of group module match &rule.entry { - cddl::ast::GroupEntry::InlineGroup{ group, .. } => { - types.mark_plain_group(RustIdent::new(CDDLIdent::new(rule.name.to_string())), Some(group.clone())); - }, + cddl::ast::GroupEntry::InlineGroup { group, .. } => { + types.mark_plain_group( + RustIdent::new(CDDLIdent::new(rule.name.to_string())), + Some(group.clone()), + ); + } x => panic!("Group rule with non-inline group? {:?}", x), } } diff --git a/src/parsing.rs b/src/parsing.rs index 82e5e81..60d9467 100644 --- a/src/parsing.rs +++ b/src/parsing.rs @@ -1,31 +1,16 @@ use cddl::ast::parent::ParentVisitor; use cddl::{ast::*, token}; -use either::{Either}; -use std::collections::{BTreeMap}; +use either::Either; +use std::collections::BTreeMap; -use crate::comment_ast::{RuleMetadata, metadata_from_comments, merge_metadata}; +use crate::comment_ast::{merge_metadata, metadata_from_comments, RuleMetadata}; use crate::intermediate::{ - AliasIdent, - CDDLIdent, - ConceptualRustType, - EnumVariant, - FixedValue, - GenericDef, - GenericInstance, - IntermediateTypes, - Primitive, - Representation, - RustIdent, - RustRecord, - RustStruct, - RustType, - RustField, - VariantIdent, + AliasIdent, CDDLIdent, ConceptualRustType, EnumVariant, FixedValue, GenericDef, + GenericInstance, IntermediateTypes, Primitive, Representation, RustField, RustIdent, + RustRecord, RustStruct, RustType, VariantIdent, }; use crate::utils::{ - append_number_if_duplicate, - convert_to_camel_case, - convert_to_snake_case, + append_number_if_duplicate, convert_to_camel_case, convert_to_snake_case, is_identifier_user_defined, }; @@ -42,23 +27,35 @@ pub const EXTERN_MARKER: &'static str = "_CDDL_CODEGEN_EXTERN_TYPE_"; /// Some means it is a scope marker, containing the scope pub fn rule_is_scope_marker(cddl_rule: &cddl::ast::Rule) -> Option { match cddl_rule { - Rule::Type{ rule: TypeRule{ name: Identifier{ ident , .. }, value, .. }, .. } => { + Rule::Type { + rule: + TypeRule { + name: Identifier { ident, .. }, + value, + .. + }, + .. + } => { if value.type_choices.len() == 1 && ident.starts_with(SCOPE_MARKER) { match &value.type_choices[0].type1.type2 { - Type2::TextValue{ value, .. } => Some(value.to_string()), + Type2::TextValue { value, .. } => Some(value.to_string()), _ => None, } } else { None } - }, + } _ => None, } } -pub fn parse_rule(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, cddl_rule: &cddl::ast::Rule) { +pub fn parse_rule( + types: &mut IntermediateTypes, + parent_visitor: &ParentVisitor, + cddl_rule: &cddl::ast::Rule, +) { match cddl_rule { - cddl::ast::Rule::Type{ rule, .. } => { + cddl::ast::Rule::Type { rule, .. } => { let rust_ident = RustIdent::new(CDDLIdent::new(rule.name.to_string())); if rule.name.to_string() == EXTERN_MARKER { // ignore - this was inserted by us so that cddl's parsing succeeds @@ -69,41 +66,70 @@ pub fn parse_rule(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, // (which is also valid cddl), but it would be fine as = instead of /= // (2) ignores control operators - only used in shelley spec to limit string length for application metadata - let generic_params = rule - .generic_params - .as_ref() - .map(|gp| gp.params.iter().map(|id| RustIdent::new(CDDLIdent::new(id.param.to_string()))).collect::>()); + let generic_params = rule.generic_params.as_ref().map(|gp| { + gp.params + .iter() + .map(|id| RustIdent::new(CDDLIdent::new(id.param.to_string()))) + .collect::>() + }); if rule.value.type_choices.len() == 1 { let choice = &rule.value.type_choices.first().unwrap(); - parse_type(types, parent_visitor, &rust_ident, choice, None, generic_params); + parse_type( + types, + parent_visitor, + &rust_ident, + choice, + None, + generic_params, + ); } else { - parse_type_choices(types, parent_visitor, &rust_ident, &rule.value.type_choices, None, generic_params); + parse_type_choices( + types, + parent_visitor, + &rust_ident, + &rule.value.type_choices, + None, + generic_params, + ); } } - }, - cddl::ast::Rule::Group{ rule, .. } => { - assert_eq!(rule.generic_params, None, "{}: Generics not supported on plain groups", rule.name); + } + cddl::ast::Rule::Group { rule, .. } => { + assert_eq!( + rule.generic_params, None, + "{}: Generics not supported on plain groups", + rule.name + ); // Freely defined group - no need to generate anything outside of group module // already handled in main.rs match &rule.entry { - cddl::ast::GroupEntry::InlineGroup{ .. } => (), + cddl::ast::GroupEntry::InlineGroup { .. } => (), x => panic!("Group rule with non-inline group? {:?}", x), } - }, + } } } pub fn rule_ident(cddl_rule: &cddl::ast::Rule) -> RustIdent { match cddl_rule { - cddl::ast::Rule::Type{ rule, .. } => RustIdent::new(CDDLIdent::new(rule.name.to_string())), - cddl::ast::Rule::Group{ rule, .. } => match &rule.entry { - cddl::ast::GroupEntry::InlineGroup{ .. } => RustIdent::new(CDDLIdent::new(rule.name.to_string())), + cddl::ast::Rule::Type { rule, .. } => RustIdent::new(CDDLIdent::new(rule.name.to_string())), + cddl::ast::Rule::Group { rule, .. } => match &rule.entry { + cddl::ast::GroupEntry::InlineGroup { .. } => { + RustIdent::new(CDDLIdent::new(rule.name.to_string())) + } x => panic!("Group rule with non-inline group? {:?}", x), }, } } -fn parse_type_choices(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, name: &RustIdent, type_choices: &Vec, tag: Option, generic_params: Option>) { +fn parse_type_choices( + types: &mut IntermediateTypes, + parent_visitor: &ParentVisitor, + name: &RustIdent, + type_choices: &Vec, + tag: Option, + generic_params: Option>, +) { let optional_inner_type = if type_choices.len() == 2 { let a = &type_choices[0].type1; let b = &type_choices[1].type1; @@ -125,11 +151,18 @@ fn parse_type_choices(types: &mut IntermediateTypes, parent_visitor: &ParentVisi } let inner_rust_type = rust_type_from_type1(types, parent_visitor, inner_type2); let final_type = match tag { - Some(tag) => RustType::new(ConceptualRustType::Optional(Box::new(inner_rust_type))).tag(tag), + Some(tag) => { + RustType::new(ConceptualRustType::Optional(Box::new(inner_rust_type))).tag(tag) + } None => RustType::new(ConceptualRustType::Optional(Box::new(inner_rust_type))), }; let rule_metadata = RuleMetadata::from(inner_type2.comments_after_type.as_ref()); - types.register_type_alias(name.clone(), final_type, !rule_metadata.no_alias, !rule_metadata.no_alias); + types.register_type_alias( + name.clone(), + final_type, + !rule_metadata.no_alias, + !rule_metadata.no_alias, + ); } else { let variants = create_variants_from_type_choices(types, parent_visitor, type_choices); let rust_struct = RustStruct::new_type_choice(name.clone(), tag, variants); @@ -142,192 +175,341 @@ fn parse_type_choices(types: &mut IntermediateTypes, parent_visitor: &ParentVisi fn type2_to_number_literal(type2: &Type2) -> isize { match type2 { - Type2::UintValue{ value, .. } => *value as isize, - Type2::IntValue{ value, .. } => *value, - Type2::FloatValue{ value, .. } => *value as isize, - _ => panic!("Value specified: {:?} must be a number literal to be used here", type2), + Type2::UintValue { value, .. } => *value as isize, + Type2::IntValue { value, .. } => *value, + Type2::FloatValue { value, .. } => *value as isize, + _ => panic!( + "Value specified: {:?} must be a number literal to be used here", + type2 + ), } } fn type2_to_fixed_value(type2: &Type2) -> FixedValue { match type2 { - Type2::UintValue{ value, .. } => FixedValue::Uint(*value), - Type2::IntValue{ value, .. } => FixedValue::Nint(*value), - Type2::FloatValue{ value, .. } => FixedValue::Float(*value), - Type2::TextValue{ value, .. } => FixedValue::Text(value.to_string()), - _ => panic!("Type2: {:?} does not correspond to a supported FixedValue", type2), + Type2::UintValue { value, .. } => FixedValue::Uint(*value), + Type2::IntValue { value, .. } => FixedValue::Nint(*value), + Type2::FloatValue { value, .. } => FixedValue::Float(*value), + Type2::TextValue { value, .. } => FixedValue::Text(value.to_string()), + _ => panic!( + "Type2: {:?} does not correspond to a supported FixedValue", + type2 + ), } } -fn parse_control_operator(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, type2: &Type2, operator: &Operator) -> ControlOperator { +fn parse_control_operator( + types: &mut IntermediateTypes, + parent_visitor: &ParentVisitor, + type2: &Type2, + operator: &Operator, +) -> ControlOperator { let lower_bound = match type2 { - Type2::Typename{ ident, .. } if ident.to_string() == "uint" => Some(0), + Type2::Typename { ident, .. } if ident.to_string() == "uint" => Some(0), _ => None, }; //todo: read up on other range control operators in CDDL RFC // (rangeop / ctlop) S type2 match operator.operator { - RangeCtlOp::RangeOp{ is_inclusive, .. } => { + RangeCtlOp::RangeOp { is_inclusive, .. } => { let range_start = match type2 { - Type2::UintValue{ value, .. } => *value as isize, - Type2::IntValue{ value, .. } => *value, - Type2::FloatValue{ value, .. } => *value as isize, - _ => panic!("Number expected as range start. Found {:?}", type2) + Type2::UintValue { value, .. } => *value as isize, + Type2::IntValue { value, .. } => *value, + Type2::FloatValue { value, .. } => *value as isize, + _ => panic!("Number expected as range start. Found {:?}", type2), }; let range_end = match operator.type2 { - Type2::UintValue{ value, .. } => value as isize, - Type2::IntValue{ value, ..} => value, - Type2::FloatValue{ value, .. } => value as isize, + Type2::UintValue { value, .. } => value as isize, + Type2::IntValue { value, .. } => value, + Type2::FloatValue { value, .. } => value as isize, _ => unimplemented!("unsupported type in range control operator: {:?}", operator), }; - ControlOperator::Range((Some(range_start as i128), Some(if is_inclusive { range_end as i128 } else { (range_end + 1) as i128 }))) - }, - RangeCtlOp::CtlOp{ ctrl, .. } => match ctrl { - token::ControlOperator::CBORSEQ | - token::ControlOperator::WITHIN | - token::ControlOperator::AND => todo!("control operator {} not supported", ctrl), - token::ControlOperator::DEFAULT => ControlOperator::Default(type2_to_fixed_value(&operator.type2)), - token::ControlOperator::CBOR => ControlOperator::CBOR(rust_type_from_type2(types, parent_visitor, &operator.type2)), - token::ControlOperator::EQ => ControlOperator::Range((Some(type2_to_number_literal(&operator.type2) as i128), Some(type2_to_number_literal(&operator.type2) as i128))), + ControlOperator::Range(( + Some(range_start as i128), + Some(if is_inclusive { + range_end as i128 + } else { + (range_end + 1) as i128 + }), + )) + } + RangeCtlOp::CtlOp { ctrl, .. } => match ctrl { + token::ControlOperator::CBORSEQ + | token::ControlOperator::WITHIN + | token::ControlOperator::AND => todo!("control operator {} not supported", ctrl), + token::ControlOperator::DEFAULT => { + ControlOperator::Default(type2_to_fixed_value(&operator.type2)) + } + token::ControlOperator::CBOR => { + ControlOperator::CBOR(rust_type_from_type2(types, parent_visitor, &operator.type2)) + } + token::ControlOperator::EQ => ControlOperator::Range(( + Some(type2_to_number_literal(&operator.type2) as i128), + Some(type2_to_number_literal(&operator.type2) as i128), + )), // TODO: this would be MUCH nicer (for error displaying, etc) to handle this in its own dedicated way // which might be necessary once we support other control operators anyway - token::ControlOperator::NE => ControlOperator::Range((Some((type2_to_number_literal(&operator.type2) + 1) as i128), Some((type2_to_number_literal(&operator.type2) - 1) as i128))), - token::ControlOperator::LE => ControlOperator::Range((lower_bound, Some(type2_to_number_literal(&operator.type2) as i128))), - token::ControlOperator::LT => ControlOperator::Range((lower_bound, Some((type2_to_number_literal(&operator.type2) - 1) as i128))), - token::ControlOperator::GE => ControlOperator::Range((Some(type2_to_number_literal(&operator.type2) as i128), None)), - token::ControlOperator::GT => ControlOperator::Range((Some((type2_to_number_literal(&operator.type2) + 1) as i128), None)), + token::ControlOperator::NE => ControlOperator::Range(( + Some((type2_to_number_literal(&operator.type2) + 1) as i128), + Some((type2_to_number_literal(&operator.type2) - 1) as i128), + )), + token::ControlOperator::LE => ControlOperator::Range(( + lower_bound, + Some(type2_to_number_literal(&operator.type2) as i128), + )), + token::ControlOperator::LT => ControlOperator::Range(( + lower_bound, + Some((type2_to_number_literal(&operator.type2) - 1) as i128), + )), + token::ControlOperator::GE => ControlOperator::Range(( + Some(type2_to_number_literal(&operator.type2) as i128), + None, + )), + token::ControlOperator::GT => ControlOperator::Range(( + Some((type2_to_number_literal(&operator.type2) + 1) as i128), + None, + )), token::ControlOperator::SIZE => { let base_range = match &operator.type2 { - Type2::UintValue{ value, .. } => ControlOperator::Range((None, Some(*value as i128))), - Type2::IntValue{ value, .. } => ControlOperator::Range((None, Some(*value as i128))), - Type2::FloatValue{ value, .. } => ControlOperator::Range((None, Some(*value as i128))), - Type2::ParenthesizedType{ pt, .. } => { + Type2::UintValue { value, .. } => { + ControlOperator::Range((None, Some(*value as i128))) + } + Type2::IntValue { value, .. } => { + ControlOperator::Range((None, Some(*value as i128))) + } + Type2::FloatValue { value, .. } => { + ControlOperator::Range((None, Some(*value as i128))) + } + Type2::ParenthesizedType { pt, .. } => { assert_eq!(pt.type_choices.len(), 1); let inner_type = &pt.type_choices.first().unwrap().type1; let min = match inner_type.type2 { - Type2::UintValue{ value, .. } => Some(value as i128), - Type2::IntValue{ value, .. } => Some(value as i128), - Type2::FloatValue{ value, .. } => Some(value as i128), - _ => unimplemented!("unsupported type in range control operator: {:?}", operator), + Type2::UintValue { value, .. } => Some(value as i128), + Type2::IntValue { value, .. } => Some(value as i128), + Type2::FloatValue { value, .. } => Some(value as i128), + _ => unimplemented!( + "unsupported type in range control operator: {:?}", + operator + ), }; match &inner_type.operator { // if there was only one value instead of a range, we take that value to be the max // ex: uint .size (1) None => ControlOperator::Range((None, min)), Some(op) => match op.operator { - RangeCtlOp::RangeOp{ is_inclusive, ..} => { + RangeCtlOp::RangeOp { is_inclusive, .. } => { let value = match op.type2 { - Type2::UintValue{ value, .. } => value as i128, - Type2::IntValue{ value, ..} => value as i128, - Type2::FloatValue{ value, .. } => value as i128, - _ => unimplemented!("unsupported type in range control operator: {:?}", operator), + Type2::UintValue { value, .. } => value as i128, + Type2::IntValue { value, .. } => value as i128, + Type2::FloatValue { value, .. } => value as i128, + _ => unimplemented!( + "unsupported type in range control operator: {:?}", + operator + ), }; let max = Some(if is_inclusive { value } else { value + 1 }); ControlOperator::Range((min, max)) - }, - RangeCtlOp::CtlOp{ .. } => panic!(""), + } + RangeCtlOp::CtlOp { .. } => panic!(""), }, } - }, - _ => unimplemented!("unsupported type in range control operator: {:?}", operator), + } + _ => { + unimplemented!("unsupported type in range control operator: {:?}", operator) + } }; match type2 { - Type2::Typename{ ident, .. } if ident.to_string() == "uint" => { + Type2::Typename { ident, .. } if ident.to_string() == "uint" => { // .size 3 means 24 bits match &base_range { - ControlOperator::Range((Some(l), Some(h))) => ControlOperator::Range((Some(i128::pow(2, 8 * *l as u32)), Some(i128::pow(2, 8 * *h as u32) - 1))), - ControlOperator::Range((None, Some(h))) => ControlOperator::Range((Some(0), Some(i128::pow(2, 8 * *h as u32) - 1))), - _ => panic!("unexpected partial range in size control operator: {:?}", operator) + ControlOperator::Range((Some(l), Some(h))) => ControlOperator::Range(( + Some(i128::pow(2, 8 * *l as u32)), + Some(i128::pow(2, 8 * *h as u32) - 1), + )), + ControlOperator::Range((None, Some(h))) => ControlOperator::Range(( + Some(0), + Some(i128::pow(2, 8 * *h as u32) - 1), + )), + _ => panic!( + "unexpected partial range in size control operator: {:?}", + operator + ), } - }, - Type2::Typename{ ident, .. } if ident.to_string() == "int" => { + } + Type2::Typename { ident, .. } if ident.to_string() == "int" => { match &base_range { // this is complex to support since it requires two disjoint ranges of possible values - ControlOperator::Range((Some(_), Some(_))) => panic!(".size range unsupported for signed int type: {:?}", operator), - ControlOperator::Range((None, Some(h))) => ControlOperator::Range((Some(-i128::pow(2, ((8 * *h) - 1) as u32)), Some(i128::pow(2, ((8 * *h) - 1) as u32) - 1))), - _ => panic!("unexpected partial range in size control operator: {:?}", operator) + ControlOperator::Range((Some(_), Some(_))) => panic!( + ".size range unsupported for signed int type: {:?}", + operator + ), + ControlOperator::Range((None, Some(h))) => ControlOperator::Range(( + Some(-i128::pow(2, ((8 * *h) - 1) as u32)), + Some(i128::pow(2, ((8 * *h) - 1) as u32) - 1), + )), + _ => panic!( + "unexpected partial range in size control operator: {:?}", + operator + ), } } _ => { match base_range { // for strings & byte arrays, specifying an upper value means an exact value (.size 3 means a 3 char string) - ControlOperator::Range((None, Some(h))) => ControlOperator::Range((Some(h), Some(h))), + ControlOperator::Range((None, Some(h))) => { + ControlOperator::Range((Some(h), Some(h))) + } range => range, } } } - }, - _ => panic!("Unknown (not seen in RFC-8610) range control operator: {}", ctrl), - } + } + _ => panic!( + "Unknown (not seen in RFC-8610) range control operator: {}", + ctrl + ), + }, } } fn range_to_primitive(low: Option, high: Option) -> Option { match (low, high) { - (Some(l), Some(h)) if l == u8::MIN as i128 && h == u8::MAX as i128 => Some(ConceptualRustType::Primitive(Primitive::U8)), - (Some(l), Some(h)) if l == i8::MIN as i128 && h == i8::MAX as i128 => Some(ConceptualRustType::Primitive(Primitive::I8)), - (Some(l), Some(h)) if l == u16::MIN as i128 && h == u16::MAX as i128 => Some(ConceptualRustType::Primitive(Primitive::U16)), - (Some(l), Some(h)) if l == i16::MIN as i128 && h == i16::MAX as i128 => Some(ConceptualRustType::Primitive(Primitive::I16)), - (Some(l), Some(h)) if l == u32::MIN as i128 && h == u32::MAX as i128 => Some(ConceptualRustType::Primitive(Primitive::U32)), - (Some(l), Some(h)) if l == i32::MIN as i128 && h == i32::MAX as i128 => Some(ConceptualRustType::Primitive(Primitive::I32)), - (Some(l), Some(h)) if l == u64::MIN as i128 && h == u64::MAX as i128 => Some(ConceptualRustType::Primitive(Primitive::U64)), - (Some(l), Some(h)) if l == i64::MIN as i128 && h == i64::MAX as i128 => Some(ConceptualRustType::Primitive(Primitive::I64)), - (Some(l), Some(h)) if l == f32::MIN as i128 && h == f32::MAX as i128 => Some(ConceptualRustType::Primitive(Primitive::F32)), - (Some(l), Some(h)) if l == f64::MIN as i128 && h == f64::MAX as i128 => Some(ConceptualRustType::Primitive(Primitive::F64)), - _ => None + (Some(l), Some(h)) if l == u8::MIN as i128 && h == u8::MAX as i128 => { + Some(ConceptualRustType::Primitive(Primitive::U8)) + } + (Some(l), Some(h)) if l == i8::MIN as i128 && h == i8::MAX as i128 => { + Some(ConceptualRustType::Primitive(Primitive::I8)) + } + (Some(l), Some(h)) if l == u16::MIN as i128 && h == u16::MAX as i128 => { + Some(ConceptualRustType::Primitive(Primitive::U16)) + } + (Some(l), Some(h)) if l == i16::MIN as i128 && h == i16::MAX as i128 => { + Some(ConceptualRustType::Primitive(Primitive::I16)) + } + (Some(l), Some(h)) if l == u32::MIN as i128 && h == u32::MAX as i128 => { + Some(ConceptualRustType::Primitive(Primitive::U32)) + } + (Some(l), Some(h)) if l == i32::MIN as i128 && h == i32::MAX as i128 => { + Some(ConceptualRustType::Primitive(Primitive::I32)) + } + (Some(l), Some(h)) if l == u64::MIN as i128 && h == u64::MAX as i128 => { + Some(ConceptualRustType::Primitive(Primitive::U64)) + } + (Some(l), Some(h)) if l == i64::MIN as i128 && h == i64::MAX as i128 => { + Some(ConceptualRustType::Primitive(Primitive::I64)) + } + (Some(l), Some(h)) if l == f32::MIN as i128 && h == f32::MAX as i128 => { + Some(ConceptualRustType::Primitive(Primitive::F32)) + } + (Some(l), Some(h)) if l == f64::MIN as i128 && h == f64::MAX as i128 => { + Some(ConceptualRustType::Primitive(Primitive::F64)) + } + _ => None, } } -fn parse_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, type_name: &RustIdent, type_choice: &TypeChoice, outer_tag: Option, generic_params: Option>) { +fn parse_type( + types: &mut IntermediateTypes, + parent_visitor: &ParentVisitor, + type_name: &RustIdent, + type_choice: &TypeChoice, + outer_tag: Option, + generic_params: Option>, +) { let type1 = &type_choice.type1; let rule_metadata = merge_metadata( &RuleMetadata::from(type1.comments_after_type.as_ref()), &RuleMetadata::from(type_choice.comments_after_type.as_ref()), ); match &type1.type2 { - Type2::Typename{ ident, generic_args, .. } => { + Type2::Typename { + ident, + generic_args, + .. + } => { if ident.ident == EXTERN_MARKER { - types.register_rust_struct(parent_visitor, RustStruct::new_extern(type_name.clone())); + types.register_rust_struct( + parent_visitor, + RustStruct::new_extern(type_name.clone()), + ); } else { // Note: this handles bool constants too, since we apply the type aliases and they resolve // and there's no Type2::BooleanValue let cddl_ident = CDDLIdent::new(ident.to_string()); - let control = type1.operator.as_ref().map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); + let control = type1 + .operator + .as_ref() + .map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); match control { Some(control) => { - assert!(generic_params.is_none(), "Generics combined with range specifiers not supported"); + assert!( + generic_params.is_none(), + "Generics combined with range specifiers not supported" + ); // TODO: what about aliases that resolve to these? is it even possible to know this at this stage? let field_type = || match cddl_ident.to_string().as_str() { "tstr" | "text" => ConceptualRustType::Primitive(Primitive::Str), "bstr" | "bytes" => ConceptualRustType::Primitive(Primitive::Bytes), - other => panic!("range control specifiers not supported for type: {}", other), + other => { + panic!("range control specifiers not supported for type: {}", other) + } }; match control { ControlOperator::Range(min_max) => { match cddl_ident.to_string().as_str() { - "int" | "uint" | "float" | "float64" | "float32" | "float16" => match range_to_primitive(min_max.0, min_max.1) { - Some(t) => types.register_type_alias(type_name.clone(), t.into(), !rule_metadata.no_alias, !rule_metadata.no_alias), - None => panic!("unsupported range for {:?}: {:?}", cddl_ident.to_string().as_str(), control) + "int" | "uint" | "float" | "float64" | "float32" + | "float16" => match range_to_primitive(min_max.0, min_max.1) { + Some(t) => types.register_type_alias( + type_name.clone(), + t.into(), + !rule_metadata.no_alias, + !rule_metadata.no_alias, + ), + None => panic!( + "unsupported range for {:?}: {:?}", + cddl_ident.to_string().as_str(), + control + ), }, - _ => types.register_rust_struct(parent_visitor, RustStruct::new_wrapper(type_name.clone(), outer_tag, field_type().clone().into(), Some(min_max))) + _ => types.register_rust_struct( + parent_visitor, + RustStruct::new_wrapper( + type_name.clone(), + outer_tag, + field_type().clone().into(), + Some(min_max), + ), + ), } - }, + } ControlOperator::CBOR(ty) => match field_type() { ConceptualRustType::Primitive(Primitive::Bytes) => { - types.register_type_alias(type_name.clone(), ty.as_bytes(), !rule_metadata.no_alias, !rule_metadata.no_alias); - }, + types.register_type_alias( + type_name.clone(), + ty.as_bytes(), + !rule_metadata.no_alias, + !rule_metadata.no_alias, + ); + } _ => panic!(".cbor is only allowed on bytes as per CDDL spec"), }, ControlOperator::Default(default_value) => { - let default_type = rust_type_from_type2(types, parent_visitor, &type1.type2) - .default(default_value); - types.register_type_alias(type_name.clone(), default_type, !rule_metadata.no_alias, !rule_metadata.no_alias); - }, + let default_type = + rust_type_from_type2(types, parent_visitor, &type1.type2) + .default(default_value); + types.register_type_alias( + type_name.clone(), + default_type, + !rule_metadata.no_alias, + !rule_metadata.no_alias, + ); + } } - }, + } None => { let mut concrete_type = types.new_type(&cddl_ident); - if let ConceptualRustType::Alias(_ident, ty) = concrete_type.conceptual_type { + if let ConceptualRustType::Alias(_ident, ty) = concrete_type.conceptual_type + { concrete_type.conceptual_type = *ty; }; match &generic_params { @@ -335,38 +517,77 @@ fn parse_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, typ // this should be the only situation where you need this as otherwise the params would be unbound todo!("generics on defined types e.g. foo = [T, U], bar = foo"); // TODO: maybe you could do this by resolving it here then storing the resolved one as GenericDef - }, + } None => { match generic_args { Some(arg) => { // This is for named generic instances such as: // foo = bar - let generic_args = arg.args.iter().map(|a| rust_type_from_type1(types, parent_visitor, &a.arg)).collect(); - types.register_generic_instance(GenericInstance::new(type_name.clone(), RustIdent::new(cddl_ident.clone()), generic_args)) - }, + let generic_args = arg + .args + .iter() + .map(|a| { + rust_type_from_type1(types, parent_visitor, &a.arg) + }) + .collect(); + types.register_generic_instance(GenericInstance::new( + type_name.clone(), + RustIdent::new(cddl_ident.clone()), + generic_args, + )) + } None => { if rule_metadata.is_newtype { - types.register_rust_struct(parent_visitor, RustStruct::new_wrapper(type_name.clone(), None, concrete_type, None)); + types.register_rust_struct( + parent_visitor, + RustStruct::new_wrapper( + type_name.clone(), + None, + concrete_type, + None, + ), + ); } else { - types.register_type_alias(type_name.clone(), concrete_type, !rule_metadata.no_alias, !rule_metadata.no_alias); + types.register_type_alias( + type_name.clone(), + concrete_type, + !rule_metadata.no_alias, + !rule_metadata.no_alias, + ); } } } } } - }, + } } } - }, - Type2::Map{ group, .. } => { - parse_group(types, parent_visitor, group, type_name, Representation::Map, outer_tag, generic_params); - }, - Type2::Array{ group, .. } => { + } + Type2::Map { group, .. } => { + parse_group( + types, + parent_visitor, + group, + type_name, + Representation::Map, + outer_tag, + generic_params, + ); + } + Type2::Array { group, .. } => { // TODO: We could potentially generate an array-wrapper type around this // possibly based on the occurency specifier. - parse_group(types, parent_visitor, group, type_name, Representation::Array, outer_tag, generic_params); - }, - Type2::TaggedData{ tag, t, .. } => { + parse_group( + types, + parent_visitor, + group, + type_name, + Representation::Array, + outer_tag, + generic_params, + ); + } + Type2::TaggedData { tag, t, .. } => { if let Some(_) = outer_tag { panic!("doubly nested tags are not supported"); } @@ -375,127 +596,233 @@ fn parse_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, typ 1 => { let inner_type = &t.type_choices.first().unwrap(); match match &inner_type.type1.type2 { - Type2::Typename{ ident, .. } => Either::Right(ident), - Type2::Map{ group, .. } => Either::Left(group), - Type2::Array{ group, .. } => Either::Left(group), - x => panic!("only supports tagged arrays/maps/typenames - found: {:?} in rule {}", x, type_name), + Type2::Typename { ident, .. } => Either::Right(ident), + Type2::Map { group, .. } => Either::Left(group), + Type2::Array { group, .. } => Either::Left(group), + x => panic!( + "only supports tagged arrays/maps/typenames - found: {:?} in rule {}", + x, type_name + ), } { - Either::Left(_group) => parse_type(types, parent_visitor, type_name, inner_type, *tag, generic_params), + Either::Left(_group) => parse_type( + types, + parent_visitor, + type_name, + inner_type, + *tag, + generic_params, + ), Either::Right(ident) => { let new_type = types.new_type(&CDDLIdent::new(ident.to_string())); - let control = inner_type.type1.operator.as_ref().map(|op| parse_control_operator(types, parent_visitor, &inner_type.type1.type2, op)); + let control = inner_type.type1.operator.as_ref().map(|op| { + parse_control_operator( + types, + parent_visitor, + &inner_type.type1.type2, + op, + ) + }); match control { Some(ControlOperator::CBOR(ty)) => { let base_type = types - .apply_type_aliases(&AliasIdent::new(CDDLIdent::new(ident.to_string()))) + .apply_type_aliases(&AliasIdent::new(CDDLIdent::new( + ident.to_string(), + ))) .expect("should not fail since ordered by dep graph") .0; - assert_eq!(base_type.conceptual_type, ConceptualRustType::Primitive(Primitive::Bytes)); + assert_eq!( + base_type.conceptual_type, + ConceptualRustType::Primitive(Primitive::Bytes) + ); assert_eq!(base_type.default, None); assert!(base_type.encodings.is_empty()); - types.register_type_alias(type_name.clone(), ty.as_bytes().tag(tag_unwrap), !rule_metadata.no_alias, !rule_metadata.no_alias); - }, + types.register_type_alias( + type_name.clone(), + ty.as_bytes().tag(tag_unwrap), + !rule_metadata.no_alias, + !rule_metadata.no_alias, + ); + } Some(ControlOperator::Range(min_max)) => { match ident.to_string().as_str() { - "int" | "uint" | "float" | "float64" | "float32" | "float16" => match range_to_primitive(min_max.0, min_max.1) { - Some(t) => types.register_type_alias(type_name.clone(), t.into(), !rule_metadata.no_alias, !rule_metadata.no_alias), - None => panic!("unsupported range for {:?}: {:?}", ident.to_string().as_str(), control) - }, - _ => types.register_rust_struct(parent_visitor, RustStruct::new_wrapper(type_name.clone(), *tag, new_type, Some(min_max))) + "int" | "uint" | "float" | "float64" | "float32" + | "float16" => { + match range_to_primitive(min_max.0, min_max.1) { + Some(t) => types.register_type_alias( + type_name.clone(), + t.into(), + !rule_metadata.no_alias, + !rule_metadata.no_alias, + ), + None => panic!( + "unsupported range for {:?}: {:?}", + ident.to_string().as_str(), + control + ), + } + } + _ => types.register_rust_struct( + parent_visitor, + RustStruct::new_wrapper( + type_name.clone(), + *tag, + new_type, + Some(min_max), + ), + ), } - }, + } Some(ControlOperator::Default(default_value)) => { - let default_tagged_type = rust_type_from_type2(types, parent_visitor, &inner_type.type1.type2) - .default(default_value) - .tag(tag_unwrap); - types.register_type_alias(type_name.clone(), default_tagged_type, !rule_metadata.no_alias, !rule_metadata.no_alias); - }, + let default_tagged_type = rust_type_from_type2( + types, + parent_visitor, + &inner_type.type1.type2, + ) + .default(default_value) + .tag(tag_unwrap); + types.register_type_alias( + type_name.clone(), + default_tagged_type, + !rule_metadata.no_alias, + !rule_metadata.no_alias, + ); + } None => { let base_type = types - .apply_type_aliases(&AliasIdent::new(CDDLIdent::new(ident.to_string()))) + .apply_type_aliases(&AliasIdent::new(CDDLIdent::new( + ident.to_string(), + ))) .expect("should not fail since ordered by dep graph") .0; - types.register_type_alias(type_name.clone(), base_type.tag(tag_unwrap), !rule_metadata.no_alias, !rule_metadata.no_alias); - }, + types.register_type_alias( + type_name.clone(), + base_type.tag(tag_unwrap), + !rule_metadata.no_alias, + !rule_metadata.no_alias, + ); + } } - }, + } }; - }, + } _ => { - parse_type_choices(types, parent_visitor, type_name, &t.type_choices, *tag, generic_params); + parse_type_choices( + types, + parent_visitor, + type_name, + &t.type_choices, + *tag, + generic_params, + ); } }; - }, + } // Note: bool constants are handled via Type2::Typename - Type2::IntValue{ value, .. } => { + Type2::IntValue { value, .. } => { let fallback_type = ConceptualRustType::Fixed(FixedValue::Nint(*value)); - let control = type1.operator.as_ref().map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); + let control = type1 + .operator + .as_ref() + .map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); let base_type = match control { Some(ControlOperator::Range(min_max)) => { match range_to_primitive(min_max.0, min_max.1) { Some(t) => t, - _ => fallback_type + _ => fallback_type, } - }, - _ => fallback_type + } + _ => fallback_type, }; - types.register_type_alias(type_name.clone(), base_type.into(), !rule_metadata.no_alias, !rule_metadata.no_alias); - }, - Type2::UintValue{ value, .. } => { + types.register_type_alias( + type_name.clone(), + base_type.into(), + !rule_metadata.no_alias, + !rule_metadata.no_alias, + ); + } + Type2::UintValue { value, .. } => { let fallback_type = ConceptualRustType::Fixed(FixedValue::Uint(*value)); - let control = type1.operator.as_ref().map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); + let control = type1 + .operator + .as_ref() + .map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); let base_type = match control { Some(ControlOperator::Range(min_max)) => { match range_to_primitive(min_max.0, min_max.1) { Some(t) => t, - _ => fallback_type + _ => fallback_type, } - }, - _ => fallback_type + } + _ => fallback_type, }; - types.register_type_alias(type_name.clone(), base_type.into(), !rule_metadata.no_alias, !rule_metadata.no_alias); - }, - Type2::TextValue{ value, .. } => { - types.register_type_alias(type_name.clone(), ConceptualRustType::Fixed(FixedValue::Text(value.to_string())).into(), !rule_metadata.no_alias, !rule_metadata.no_alias); - }, + types.register_type_alias( + type_name.clone(), + base_type.into(), + !rule_metadata.no_alias, + !rule_metadata.no_alias, + ); + } + Type2::TextValue { value, .. } => { + types.register_type_alias( + type_name.clone(), + ConceptualRustType::Fixed(FixedValue::Text(value.to_string())).into(), + !rule_metadata.no_alias, + !rule_metadata.no_alias, + ); + } Type2::FloatValue { value, .. } => { let fallback_type = ConceptualRustType::Fixed(FixedValue::Float(*value)); - let control = type1.operator.as_ref().map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); + let control = type1 + .operator + .as_ref() + .map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); let base_type = match control { Some(ControlOperator::Range(min_max)) => { match range_to_primitive(min_max.0, min_max.1) { Some(t) => t, - _ => fallback_type + _ => fallback_type, } - }, - _ => fallback_type + } + _ => fallback_type, }; types.register_type_alias(type_name.clone(), base_type.into(), true, true); - }, + } x => { panic!("\nignored typename {} -> {:?}\n", type_name, x); - }, + } } } // TODO: Also generates individual choices if required, ie for a / [foo] / c would generate Foos -pub fn create_variants_from_type_choices(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, type_choices: &Vec) -> Vec { +pub fn create_variants_from_type_choices( + types: &mut IntermediateTypes, + parent_visitor: &ParentVisitor, + type_choices: &Vec, +) -> Vec { let mut variant_names_used = BTreeMap::::new(); - type_choices.iter().map(|choice| { - let rust_type = rust_type_from_type1(types, parent_visitor, &choice.type1); - let base_name = match RuleMetadata::from(choice.type1.comments_after_type.as_ref()) { - RuleMetadata { name: Some(name), .. } => convert_to_camel_case(&name), - _ => rust_type.for_variant().to_string(), - }; - let variant_name = append_number_if_duplicate(&mut variant_names_used, base_name); - EnumVariant::new(VariantIdent::new_custom(variant_name), rust_type, false) - }).collect() + type_choices + .iter() + .map(|choice| { + let rust_type = rust_type_from_type1(types, parent_visitor, &choice.type1); + let base_name = match RuleMetadata::from(choice.type1.comments_after_type.as_ref()) { + RuleMetadata { + name: Some(name), .. + } => convert_to_camel_case(&name), + _ => rust_type.for_variant().to_string(), + }; + let variant_name = append_number_if_duplicate(&mut variant_names_used, base_name); + EnumVariant::new(VariantIdent::new_custom(variant_name), rust_type, false) + }) + .collect() } -fn table_domain_range<'a>(group_choice: &'a GroupChoice<'a>, rep: Representation) -> Option<(&'a Type1<'a>, &'a Type<'a>)> { +fn table_domain_range<'a>( + group_choice: &'a GroupChoice<'a>, + rep: Representation, +) -> Option<(&'a Type1<'a>, &'a Type<'a>)> { // Here we test if this is a struct vs a table. // struct: { x: int, y: int }, etc // table: { * int => tstr }, etc @@ -505,19 +832,22 @@ fn table_domain_range<'a>(group_choice: &'a GroupChoice<'a>, rep: Representation if let Representation::Map = rep { if group_choice.group_entries.len() == 1 { match group_choice.group_entries.first() { - Some((GroupEntry::ValueMemberKey{ ge, .. }, _)) => { + Some((GroupEntry::ValueMemberKey { ge, .. }, _)) => { match &ge.member_key { - Some(MemberKey::Type1{ t1, .. }) => { + Some(MemberKey::Type1 { t1, .. }) => { // TODO: Do we need to handle cuts for what we're doing? // Does the range control operator matter? return Some((&t1, &ge.entry_type)); - }, + } // has a fixed value - this is just a 1-element struct - Some(MemberKey::Value{ .. }) => return None, + Some(MemberKey::Value { .. }) => return None, _ => panic!("unsupported table map key (1): {:?}", ge), } - }, - _ => panic!("unsupported table map key (2): {:?}", group_choice.group_entries.first().unwrap()), + } + _ => panic!( + "unsupported table map key (2): {:?}", + group_choice.group_entries.first().unwrap() + ), } } } @@ -528,36 +858,40 @@ fn table_domain_range<'a>(group_choice: &'a GroupChoice<'a>, rep: Representation // would use rust_type_from_type1 but that requires IntermediateTypes which we shouldn't fn type2_is_null(t2: &Type2) -> bool { match t2 { - Type2::Typename{ ident, .. } => ident.ident == "null" || ident.ident == "nil", + Type2::Typename { ident, .. } => ident.ident == "null" || ident.ident == "nil", _ => false, } } fn type_to_field_name(t: &Type) -> Option { let type2_to_field_name = |t2: &Type2| match t2 { - Type2::Typename{ ident, .. } => Some(ident.to_string()), - Type2::TextValue { value, .. } => Some(value.to_string()), - Type2::Array { group, .. } => match group.group_choices.len() { - 1 => { - let entries = &group.group_choices.first().unwrap().group_entries; - match entries.len() { - 1 => { - match &entries.first().unwrap().0 { - // should we do this? here it possibly allows [[foo]] -> fooss - GroupEntry::ValueMemberKey{ ge, .. } => Some(format!("{}s", type_to_field_name(&ge.entry_type)?)), - GroupEntry::TypeGroupname{ ge, .. } => Some(format!("{}s", ge.name.to_string())), - GroupEntry::InlineGroup { .. } => None, + Type2::Typename { ident, .. } => Some(ident.to_string()), + Type2::TextValue { value, .. } => Some(value.to_string()), + Type2::Array { group, .. } => match group.group_choices.len() { + 1 => { + let entries = &group.group_choices.first().unwrap().group_entries; + match entries.len() { + 1 => { + match &entries.first().unwrap().0 { + // should we do this? here it possibly allows [[foo]] -> fooss + GroupEntry::ValueMemberKey { ge, .. } => { + Some(format!("{}s", type_to_field_name(&ge.entry_type)?)) + } + GroupEntry::TypeGroupname { ge, .. } => { + Some(format!("{}s", ge.name.to_string())) } - }, - // only supports homogenous arrays for now - _ => None, + GroupEntry::InlineGroup { .. } => None, + } } - }, - // no group choice support here - _ => None + // only supports homogenous arrays for now + _ => None, + } } - // non array/text/identifier types not supported here - value keys are caught earlier anyway - _ => None + // no group choice support here + _ => None, + }, + // non array/text/identifier types not supported here - value keys are caught earlier anyway + _ => None, }; match t.type_choices.len() { 1 => type2_to_field_name(&t.type_choices.first().unwrap().type1.type2), @@ -573,7 +907,7 @@ fn type_to_field_name(t: &Type) -> Option { // neither are null - we do not support type choices here None } - }, + } // no type choice support here _ => None, } @@ -589,9 +923,12 @@ fn _field_name_from_comments<'a>(comments: &Option>) -> Option(a: &'a Option, b: &'a Option) -> Option> { - match (a.as_ref().map(|comment| comment.0.clone()), b.as_ref().map(|comment| comment.0.clone())) { + match ( + a.as_ref().map(|comment| comment.0.clone()), + b.as_ref().map(|comment| comment.0.clone()), + ) { (Some(a), Some(b)) => Some([a, b].concat()), - (opt_a, opt_b) => opt_a.or(opt_b) + (opt_a, opt_b) => opt_a.or(opt_b), } } @@ -599,46 +936,74 @@ fn combine_comments<'a>(a: &'a Option, b: &'a Option) -> Opt // generated one, then we simply add numerals starting at 2, 3, 4... // If you wish to only check if there is an explicitly stated field name, // then use group_entry_to_raw_field_name() -fn group_entry_to_field_name(entry: &GroupEntry, index: usize, already_generated: &mut BTreeMap, optional_comma: &OptionalComma) -> String { +fn group_entry_to_field_name( + entry: &GroupEntry, + index: usize, + already_generated: &mut BTreeMap, + optional_comma: &OptionalComma, +) -> String { //println!("group_entry_to_field_name() = {:#?}", entry); let field_name = convert_to_snake_case(&match entry { - GroupEntry::ValueMemberKey{ trailing_comments, ge, .. } => match ge.member_key.as_ref() { + GroupEntry::ValueMemberKey { + trailing_comments, + ge, + .. + } => match ge.member_key.as_ref() { Some(member_key) => match member_key { - MemberKey::Value{ value, .. } => { - let combined_comments = combine_comments(trailing_comments, &optional_comma.trailing_comments); + MemberKey::Value { value, .. } => { + let combined_comments = + combine_comments(trailing_comments, &optional_comma.trailing_comments); match metadata_from_comments(&combined_comments.unwrap_or_default()) { - RuleMetadata { name: Some(name), .. } => name, - _ => format!("key_{}", value) + RuleMetadata { + name: Some(name), .. + } => name, + _ => format!("key_{}", value), } + } + MemberKey::Bareword { ident, .. } => ident.to_string(), + MemberKey::Type1 { t1, .. } => match t1.type2 { + Type2::UintValue { value, .. } => format!("key_{}", value), + _ => panic!( + "Encountered Type1 member key in multi-field map - not supported: {:?}", + entry + ), }, - MemberKey::Bareword{ ident, .. } => ident.to_string(), - MemberKey::Type1{ t1, .. } => match t1.type2 { - Type2::UintValue{ value, .. } => format!("key_{}", value), - _ => panic!("Encountered Type1 member key in multi-field map - not supported: {:?}", entry), - }, - MemberKey::NonMemberKey{ .. } => panic!("Please open a github issue with repro steps"), + MemberKey::NonMemberKey { .. } => { + panic!("Please open a github issue with repro steps") + } }, - None => { - type_to_field_name(&ge.entry_type).unwrap_or_else(|| { - let combined_comments = combine_comments(trailing_comments, &optional_comma.trailing_comments); - match metadata_from_comments(&combined_comments.unwrap_or_default()) { - RuleMetadata { name: Some(name), .. } => name, - _ => format!("index_{}", index), - } - }) - } + None => type_to_field_name(&ge.entry_type).unwrap_or_else(|| { + let combined_comments = + combine_comments(trailing_comments, &optional_comma.trailing_comments); + match metadata_from_comments(&combined_comments.unwrap_or_default()) { + RuleMetadata { + name: Some(name), .. + } => name, + _ => format!("index_{}", index), + } + }), }, - GroupEntry::TypeGroupname{ trailing_comments, ge: TypeGroupnameEntry { name, .. }, .. } => match !is_identifier_user_defined(&name.to_string()) { + GroupEntry::TypeGroupname { + trailing_comments, + ge: TypeGroupnameEntry { name, .. }, + .. + } => match !is_identifier_user_defined(&name.to_string()) { true => { - let combined_comments = combine_comments(trailing_comments, &optional_comma.trailing_comments); + let combined_comments = + combine_comments(trailing_comments, &optional_comma.trailing_comments); match metadata_from_comments(&combined_comments.unwrap_or_default()) { - RuleMetadata { name: Some(name), .. } => name, + RuleMetadata { + name: Some(name), .. + } => name, _ => format!("index_{}", index), } - }, + } false => name.to_string(), }, - GroupEntry::InlineGroup{ group, .. } => panic!("not implemented (define a new struct for this!) = {}\n\n {:?}", group, group), + GroupEntry::InlineGroup { group, .. } => panic!( + "not implemented (define a new struct for this!) = {}\n\n {:?}", + group, group + ), }); append_number_if_duplicate(already_generated, field_name.clone()) } @@ -648,49 +1013,90 @@ fn group_entry_to_field_name(entry: &GroupEntry, index: usize, already_generated // Also does not do any CamelCase or snake_case formatting. fn group_entry_to_raw_field_name(entry: &GroupEntry) -> Option { match entry { - GroupEntry::ValueMemberKey{ ge, .. } => match ge.member_key.as_ref() { - Some(MemberKey::Bareword{ ident, .. } ) => Some(ident.to_string()), + GroupEntry::ValueMemberKey { ge, .. } => match ge.member_key.as_ref() { + Some(MemberKey::Bareword { ident, .. }) => Some(ident.to_string()), _ => None, }, - GroupEntry::TypeGroupname{ ge: TypeGroupnameEntry { name, .. }, .. } => match !is_identifier_user_defined(&name.to_string()) { + GroupEntry::TypeGroupname { + ge: TypeGroupnameEntry { name, .. }, + .. + } => match !is_identifier_user_defined(&name.to_string()) { true => None, false => Some(name.to_string()), }, - GroupEntry::InlineGroup{ group, .. } => panic!("not implemented (define a new struct for this!) = {}\n\n {:?}", group, group), + GroupEntry::InlineGroup { group, .. } => panic!( + "not implemented (define a new struct for this!) = {}\n\n {:?}", + group, group + ), } } -fn rust_type_from_type1(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, type1: &Type1) -> RustType { - let control = type1.operator.as_ref().map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); +fn rust_type_from_type1( + types: &mut IntermediateTypes, + parent_visitor: &ParentVisitor, + type1: &Type1, +) -> RustType { + let control = type1 + .operator + .as_ref() + .map(|op| parse_control_operator(types, parent_visitor, &type1.type2, op)); let base_type = rust_type_from_type2(types, parent_visitor, &type1.type2); // println!("type1: {:#?}", type1); match control { Some(ControlOperator::CBOR(ty)) => { - assert!(matches!(base_type.conceptual_type.resolve_aliases(), ConceptualRustType::Primitive(Primitive::Bytes))); + assert!(matches!( + base_type.conceptual_type.resolve_aliases(), + ConceptualRustType::Primitive(Primitive::Bytes) + )); ty.as_bytes() - }, - Some(ControlOperator::Range(min_max)) => { - match &type1.type2 { - Type2::Typename{ ident, .. } if ident.to_string() == "uint" || ident.to_string() == "int" || ident.to_string() == "float" || ident.to_string() == "float16" || ident.to_string() == "float32" || ident.to_string() == "float64" => match range_to_primitive(min_max.0, min_max.1) { + } + Some(ControlOperator::Range(min_max)) => match &type1.type2 { + Type2::Typename { ident, .. } + if ident.to_string() == "uint" + || ident.to_string() == "int" + || ident.to_string() == "float" + || ident.to_string() == "float16" + || ident.to_string() == "float32" + || ident.to_string() == "float64" => + { + match range_to_primitive(min_max.0, min_max.1) { Some(t) => t.into(), - None => panic!("unsupported range for {:?}: {:?}", ident.to_string().as_str(), control) - }, - _ => base_type + None => panic!( + "unsupported range for {:?}: {:?}", + ident.to_string().as_str(), + control + ), + } } + _ => base_type, }, Some(ControlOperator::Default(default_value)) => base_type.default(default_value), None => base_type, } } -fn rust_type_from_type2(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, type2: &Type2) -> RustType { +fn rust_type_from_type2( + types: &mut IntermediateTypes, + parent_visitor: &ParentVisitor, + type2: &Type2, +) -> RustType { // TODO: socket plugs (used in hash type) match &type2 { - Type2::UintValue{ value, .. } => ConceptualRustType::Fixed(FixedValue::Uint(*value)).into(), - Type2::IntValue{ value, .. } => ConceptualRustType::Fixed(FixedValue::Nint(*value)).into(), - Type2::FloatValue{ value, .. } => ConceptualRustType::Fixed(FixedValue::Float(*value)).into(), - Type2::TextValue{ value, .. } => ConceptualRustType::Fixed(FixedValue::Text(value.to_string())).into(), - Type2::Typename{ ident, generic_args, .. } => { + Type2::UintValue { value, .. } => { + ConceptualRustType::Fixed(FixedValue::Uint(*value)).into() + } + Type2::IntValue { value, .. } => ConceptualRustType::Fixed(FixedValue::Nint(*value)).into(), + Type2::FloatValue { value, .. } => { + ConceptualRustType::Fixed(FixedValue::Float(*value)).into() + } + Type2::TextValue { value, .. } => { + ConceptualRustType::Fixed(FixedValue::Text(value.to_string())).into() + } + Type2::Typename { + ident, + generic_args, + .. + } => { let cddl_ident = CDDLIdent::new(ident.ident); match generic_args { Some(args) => { @@ -698,18 +1104,31 @@ fn rust_type_from_type2(types: &mut IntermediateTypes, parent_visitor: &ParentVi // foo = [a: bar] // so to be able to expose it to wasm, we create a new generic instance // under the name bar_string_bool in this case. - let generic_args = args.args.iter().map(|a| rust_type_from_type1(types, parent_visitor, &a.arg)).collect::>(); - let args_name = generic_args.iter().map(|t| t.for_variant().to_string()).collect::>().join("_"); - let instance_cddl_ident = CDDLIdent::new(format!("{}_{}", cddl_ident, args_name)); + let generic_args = args + .args + .iter() + .map(|a| rust_type_from_type1(types, parent_visitor, &a.arg)) + .collect::>(); + let args_name = generic_args + .iter() + .map(|t| t.for_variant().to_string()) + .collect::>() + .join("_"); + let instance_cddl_ident = + CDDLIdent::new(format!("{}_{}", cddl_ident, args_name)); let instance_ident = RustIdent::new(instance_cddl_ident.clone()); let generic_ident = RustIdent::new(cddl_ident); - types.register_generic_instance(GenericInstance::new(instance_ident, generic_ident, generic_args)); + types.register_generic_instance(GenericInstance::new( + instance_ident, + generic_ident, + generic_args, + )); types.new_type(&instance_cddl_ident) - }, + } None => types.new_type(&cddl_ident), } - }, - Type2::Array{ group, .. } => { + } + Type2::Array { group, .. } => { // TODO: support for group choices in arrays? let element_type = match group.group_choices.len() { 1 => { @@ -718,23 +1137,38 @@ fn rust_type_from_type2(types: &mut IntermediateTypes, parent_visitor: &ParentVi if choice.group_entries.len() == 1 { let (entry, _has_comma) = choice.group_entries.first().unwrap(); match entry { - GroupEntry::ValueMemberKey{ ge, .. } => rust_type(types, parent_visitor, &ge.entry_type), - GroupEntry::TypeGroupname{ ge, .. } => types.new_type(&CDDLIdent::new(&ge.name.to_string())), + GroupEntry::ValueMemberKey { ge, .. } => { + rust_type(types, parent_visitor, &ge.entry_type) + } + GroupEntry::TypeGroupname { ge, .. } => { + types.new_type(&CDDLIdent::new(&ge.name.to_string())) + } _ => panic!("UNSUPPORTED_ARRAY_ELEMENT<{:?}>", entry), } } else { - let rule_metadata = RuleMetadata::from(get_comment_after(parent_visitor, &CDDLType::from(type2), None).as_ref());; + let rule_metadata = RuleMetadata::from( + get_comment_after(parent_visitor, &CDDLType::from(type2), None) + .as_ref(), + ); let name = match rule_metadata.name.as_ref() { Some(name) => name, None => panic!("Anonymous groups not allowed. Either create an explicit rule (foo = [0, bytes]) or give it a name using the @name notation. Group: {:#?}", group) }; let cddl_ident = CDDLIdent::new(name); let rust_ident = RustIdent::new(cddl_ident.clone()); - parse_group(types, parent_visitor, group, &rust_ident, Representation::Array, None, None); + parse_group( + types, + parent_visitor, + group, + &rust_ident, + Representation::Array, + None, + None, + ); // we aren't returning an array, but rather a struct where the fields are ordered - return types.new_type(&cddl_ident) + return types.new_type(&cddl_ident); } - }, + } // array of elements with choices: enums? _ => unimplemented!("group choices in array type not supported"), }; @@ -745,7 +1179,7 @@ fn rust_type_from_type2(types: &mut IntermediateTypes, parent_visitor: &ParentVi types.set_rep_if_plain_group(parent_visitor, element_ident, Representation::Array); } ConceptualRustType::Array(Box::new(element_type)).into() - }, + } Type2::Map { group, .. } => { match group.group_choices.len() { 1 => { @@ -763,40 +1197,55 @@ fn rust_type_from_type2(types: &mut IntermediateTypes, parent_visitor: &ParentVi //let table_type_ident = RustIdent::new(CDDLIdent::new(format!("Map{}To{}", key_type.for_wasm_member(), value_type.for_wasm_member()))); //types.register_rust_struct(RustStruct::new_table(table_type_ident, None, key_type.clone(), value_type.clone())); ConceptualRustType::Map(Box::new(key_type), Box::new(value_type)).into() - }, + } None => unimplemented!("TODO: non-table types as types: {:?}", group), } - }, - _ => unimplemented!("group choices in inlined map types not allowed: {:?}", group), + } + _ => unimplemented!( + "group choices in inlined map types not allowed: {:?}", + group + ), } - }, + } // unsure if we need to handle the None case - when does this happen? - Type2::TaggedData{ tag, t, .. } => { + Type2::TaggedData { tag, t, .. } => { let tag_unwrap = tag.expect("tagged data without tag not supported"); rust_type(types, parent_visitor, t).tag(tag_unwrap) - }, - Type2::ParenthesizedType { pt, .. } => { - rust_type(types, parent_visitor, pt) - }, + } + Type2::ParenthesizedType { pt, .. } => rust_type(types, parent_visitor, pt), _ => { panic!("Ignoring Type2: {:?}", type2); - }, + } } } fn rust_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, t: &Type) -> RustType { if t.type_choices.len() == 1 { - rust_type_from_type1(types, parent_visitor, &t.type_choices.first().unwrap().type1) + rust_type_from_type1( + types, + parent_visitor, + &t.type_choices.first().unwrap().type1, + ) } else { if t.type_choices.len() == 2 { // T / null or null / T should map to Option let a = &t.type_choices[0].type1; let b = &t.type_choices[1].type1; if type2_is_null(&a.type2) { - return ConceptualRustType::Optional(Box::new(rust_type_from_type1(types, parent_visitor, b))).into(); + return ConceptualRustType::Optional(Box::new(rust_type_from_type1( + types, + parent_visitor, + b, + ))) + .into(); } if type2_is_null(&b.type2) { - return ConceptualRustType::Optional(Box::new(rust_type_from_type1(types, parent_visitor, a))).into(); + return ConceptualRustType::Optional(Box::new(rust_type_from_type1( + types, + parent_visitor, + a, + ))) + .into(); } } let variants = create_variants_from_type_choices(types, parent_visitor, &t.type_choices); @@ -811,16 +1260,19 @@ fn rust_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, t: & combined_name.push_str(&variant.rust_type.for_variant().to_string()); } let combined_ident = RustIdent::new(CDDLIdent::new(&combined_name)); - types.register_rust_struct(parent_visitor, RustStruct::new_type_choice(combined_ident, None, variants)); + types.register_rust_struct( + parent_visitor, + RustStruct::new_type_choice(combined_ident, None, variants), + ); types.new_type(&CDDLIdent::new(combined_name)) } } fn group_entry_optional(entry: &GroupEntry) -> bool { let occur = match entry { - GroupEntry::ValueMemberKey{ ge, .. } => &ge.occur, - GroupEntry::TypeGroupname{ ge, .. } => &ge.occur, - GroupEntry::InlineGroup{ .. } => panic!("inline group entries are not implemented"), + GroupEntry::ValueMemberKey { ge, .. } => &ge.occur, + GroupEntry::TypeGroupname { ge, .. } => &ge.occur, + GroupEntry::InlineGroup { .. } => panic!("inline group entries are not implemented"), }; occur .as_ref() @@ -831,10 +1283,14 @@ fn group_entry_optional(entry: &GroupEntry) -> bool { .unwrap_or(false) } -fn group_entry_to_type(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, entry: &GroupEntry) -> RustType { +fn group_entry_to_type( + types: &mut IntermediateTypes, + parent_visitor: &ParentVisitor, + entry: &GroupEntry, +) -> RustType { let ret = match entry { - GroupEntry::ValueMemberKey{ ge, .. } => rust_type(types, parent_visitor, &ge.entry_type), - GroupEntry::TypeGroupname{ ge, .. } => { + GroupEntry::ValueMemberKey { ge, .. } => rust_type(types, parent_visitor, &ge.entry_type), + GroupEntry::TypeGroupname { ge, .. } => { if ge.generic_args.is_some() { // I am not sure how we end up with this kind of generic args since definitional ones // and member ones are created elsewhere. I thought that if you had a field like @@ -844,8 +1300,8 @@ fn group_entry_to_type(types: &mut IntermediateTypes, parent_visitor: &ParentVis } let cddl_ident = CDDLIdent::new(ge.name.to_string()); types.new_type(&cddl_ident) - }, - GroupEntry::InlineGroup{ .. } => panic!("inline group entries are not implemented"), + } + GroupEntry::InlineGroup { .. } => panic!("inline group entries are not implemented"), }; //println!("group_entry_to_typename({:?}) = {:?}\n", entry, ret); ret @@ -853,35 +1309,46 @@ fn group_entry_to_type(types: &mut IntermediateTypes, parent_visitor: &ParentVis fn group_entry_to_key(entry: &GroupEntry) -> Option { match entry { - GroupEntry::ValueMemberKey{ ge, .. } => { - match ge.member_key.as_ref()? { - MemberKey::Value{ value, .. } => match value { - cddl::token::Value::UINT(x) => Some(FixedValue::Uint(*x)), - cddl::token::Value::INT(x) => Some(FixedValue::Nint(*x)), - cddl::token::Value::TEXT(x) => Some(FixedValue::Text(x.to_string())), - cddl::token::Value::FLOAT(x) => Some(FixedValue::Float(*x)), - _ => panic!("unsupported map identifier(1): {:?}", value), - }, - MemberKey::Bareword{ ident, .. } => Some(FixedValue::Text(ident.to_string())), - MemberKey::Type1{ t1, .. } => match &t1.type2 { - Type2::UintValue{ value, .. } => Some(FixedValue::Uint(*value)), - Type2::IntValue{ value, .. } => Some(FixedValue::Nint(*value)), - Type2::TextValue{ value, .. } => Some(FixedValue::Text(value.to_string())), - Type2::FloatValue { value, .. } => Some(FixedValue::Float(*value)), - _ => panic!("unsupported map identifier(2): {:?}", entry), - }, - MemberKey::NonMemberKey{ .. } => panic!("Please open a github issue with repro steps"), - } + GroupEntry::ValueMemberKey { ge, .. } => match ge.member_key.as_ref()? { + MemberKey::Value { value, .. } => match value { + cddl::token::Value::UINT(x) => Some(FixedValue::Uint(*x)), + cddl::token::Value::INT(x) => Some(FixedValue::Nint(*x)), + cddl::token::Value::TEXT(x) => Some(FixedValue::Text(x.to_string())), + cddl::token::Value::FLOAT(x) => Some(FixedValue::Float(*x)), + _ => panic!("unsupported map identifier(1): {:?}", value), + }, + MemberKey::Bareword { ident, .. } => Some(FixedValue::Text(ident.to_string())), + MemberKey::Type1 { t1, .. } => match &t1.type2 { + Type2::UintValue { value, .. } => Some(FixedValue::Uint(*value)), + Type2::IntValue { value, .. } => Some(FixedValue::Nint(*value)), + Type2::TextValue { value, .. } => Some(FixedValue::Text(value.to_string())), + Type2::FloatValue { value, .. } => Some(FixedValue::Float(*value)), + _ => panic!("unsupported map identifier(2): {:?}", entry), + }, + MemberKey::NonMemberKey { .. } => panic!("Please open a github issue with repro steps"), }, _ => None, } } -fn parse_record_from_group_choice(types: &mut IntermediateTypes, rep: Representation, parent_visitor: &ParentVisitor, group_choice: &GroupChoice) -> RustRecord { +fn parse_record_from_group_choice( + types: &mut IntermediateTypes, + rep: Representation, + parent_visitor: &ParentVisitor, + group_choice: &GroupChoice, +) -> RustRecord { let mut generated_fields = BTreeMap::::new(); - let fields = group_choice.group_entries.iter().enumerate().map( - |(index, (group_entry, optional_comma))| { - let field_name = group_entry_to_field_name(group_entry, index, &mut generated_fields, optional_comma); + let fields = group_choice + .group_entries + .iter() + .enumerate() + .map(|(index, (group_entry, optional_comma))| { + let field_name = group_entry_to_field_name( + group_entry, + index, + &mut generated_fields, + optional_comma, + ); // does not exist for fixed values importantly let field_type = group_entry_to_type(types, parent_visitor, group_entry); if let ConceptualRustType::Rust(ident) = &field_type.conceptual_type { @@ -889,19 +1356,26 @@ fn parse_record_from_group_choice(types: &mut IntermediateTypes, rep: Representa } let optional_field = group_entry_optional(group_entry); let key = match rep { - Representation::Map => Some(group_entry_to_key(group_entry).expect("map fields need keys")), + Representation::Map => { + Some(group_entry_to_key(group_entry).expect("map fields need keys")) + } Representation::Array => None, }; RustField::new(field_name, field_type, optional_field, key) - } - ).collect(); - RustRecord { - rep, - fields, - } + }) + .collect(); + RustRecord { rep, fields } } -fn parse_group_choice<'a>(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, group_choice: &'a GroupChoice, name: &RustIdent, rep: Representation, tag: Option, generic_params: Option>) { +fn parse_group_choice<'a>( + types: &mut IntermediateTypes, + parent_visitor: &ParentVisitor, + group_choice: &'a GroupChoice, + name: &RustIdent, + rep: Representation, + tag: Option, + generic_params: Option>, +) { let table_types = table_domain_range(group_choice, rep); let rust_struct = match table_types { // Table map - homogenous key/value types @@ -909,7 +1383,7 @@ fn parse_group_choice<'a>(types: &mut IntermediateTypes, parent_visitor: &Parent let key_type = rust_type_from_type1(types, parent_visitor, domain); let value_type = rust_type(types, parent_visitor, range); RustStruct::new_table(name.clone(), tag, key_type, value_type) - }, + } // Heterogenous map (or array!) with defined key/value pairs in the cddl like a struct None => { let record = parse_record_from_group_choice(types, rep, parent_visitor, group_choice); @@ -923,10 +1397,26 @@ fn parse_group_choice<'a>(types: &mut IntermediateTypes, parent_visitor: &Parent }; } -pub fn parse_group(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor, group: &Group, name: &RustIdent, rep: Representation, tag: Option, generic_params: Option>) { +pub fn parse_group( + types: &mut IntermediateTypes, + parent_visitor: &ParentVisitor, + group: &Group, + name: &RustIdent, + rep: Representation, + tag: Option, + generic_params: Option>, +) { if group.group_choices.len() == 1 { // Handle simple (no choices) group. - parse_group_choice(types, parent_visitor, group.group_choices.first().unwrap(), name, rep, tag, generic_params); + parse_group_choice( + types, + parent_visitor, + group.group_choices.first().unwrap(), + name, + rep, + tag, + generic_params, + ); } else { if generic_params.is_some() { todo!("{}: generic group choices not supported", name); @@ -938,94 +1428,160 @@ pub fn parse_group(types: &mut IntermediateTypes, parent_visitor: &ParentVisitor // It would not be as trivial to add as we do the outer group's array/map tag writing inside the variant match // to avoid having to always generate SerializeEmbeddedGroup when not necessary. assert!(!types.is_plain_group(name)); - + // Handle group with choices by generating an enum then generating a group for every choice let mut variants_names_used = BTreeMap::::new(); - let variants: Vec = group.group_choices.iter().enumerate().map(|(i, group_choice)| { - // If we're a 1-element we should just wrap that type in the variant rather than - // define a new struct just for each variant. - // TODO: handle map-based enums? It would require being able to extract the key logic - // We might end up doing this anyway to support table-maps in choices though. - if group_choice.group_entries.len() == 1 { - let group_entry = &group_choice.group_entries.first().unwrap().0; - let ty = group_entry_to_type(types, parent_visitor, group_entry); - let serialize_as_embedded = if let ConceptualRustType::Rust(ident) = &ty.conceptual_type { - // we might need to generate it if not used elsewhere - types.set_rep_if_plain_group(parent_visitor, ident, rep); - types.is_plain_group(ident) + let variants: Vec = group + .group_choices + .iter() + .enumerate() + .map(|(i, group_choice)| { + // If we're a 1-element we should just wrap that type in the variant rather than + // define a new struct just for each variant. + // TODO: handle map-based enums? It would require being able to extract the key logic + // We might end up doing this anyway to support table-maps in choices though. + if group_choice.group_entries.len() == 1 { + let group_entry = &group_choice.group_entries.first().unwrap().0; + let ty = group_entry_to_type(types, parent_visitor, group_entry); + let serialize_as_embedded = + if let ConceptualRustType::Rust(ident) = &ty.conceptual_type { + // we might need to generate it if not used elsewhere + types.set_rep_if_plain_group(parent_visitor, ident, rep); + types.is_plain_group(ident) + } else { + false + }; + let variant_ident = + convert_to_camel_case(&match group_entry_to_raw_field_name(group_entry) { + Some(name) => name, + None => append_number_if_duplicate( + &mut variants_names_used, + ty.for_variant().to_string(), + ), + }); + let variant_ident = VariantIdent::new_custom(variant_ident); + EnumVariant::new(variant_ident, ty, serialize_as_embedded) + // None => { + // // TODO: Weird case, group choice with only one fixed-value field. + // // What should we do here? In the future we could make this a + // // non-value-taking enum then handle this in the serialization code. + // // However, for now we just default to default behavior: + // let variant_name = format!("{}{}", name, i); + // // TODO: Should we generate these within their own namespace? + // codegen_group_choice(global, group_choice, &variant_name, rep, None); + // EnumVariant::new(variant_name.clone(), RustType::Rust(variant_name), true) + // }, } else { - false - }; - let variant_ident = convert_to_camel_case(&match group_entry_to_raw_field_name(group_entry) { - Some(name) => name, - None => append_number_if_duplicate(&mut variants_names_used, ty.for_variant().to_string()), - }); - let variant_ident = VariantIdent::new_custom(variant_ident); - EnumVariant::new(variant_ident, ty, serialize_as_embedded) - // None => { - // // TODO: Weird case, group choice with only one fixed-value field. - // // What should we do here? In the future we could make this a - // // non-value-taking enum then handle this in the serialization code. - // // However, for now we just default to default behavior: - // let variant_name = format!("{}{}", name, i); - // // TODO: Should we generate these within their own namespace? - // codegen_group_choice(global, group_choice, &variant_name, rep, None); - // EnumVariant::new(variant_name.clone(), RustType::Rust(variant_name), true) - // }, - } else { - let rule_metadata = RuleMetadata::from(group_choice.comments_before_grpchoice.as_ref()); - let ident_name = rule_metadata.name.unwrap_or_else(|| format!("{}{}", name, i)); - // General case, GroupN type identifiers and generate group choice since it's inlined here - let variant_name = RustIdent::new(CDDLIdent::new(ident_name)); - types.mark_plain_group(variant_name.clone(), None); - parse_group_choice(types, parent_visitor, group_choice, &variant_name, rep, None, generic_params.clone()); - EnumVariant::new(VariantIdent::new_rust(variant_name.clone()), ConceptualRustType::Rust(variant_name).into(), true) - } - }).collect(); - types.register_rust_struct(parent_visitor, RustStruct::new_group_choice(name.clone(), tag, variants, rep)); + let rule_metadata = + RuleMetadata::from(group_choice.comments_before_grpchoice.as_ref()); + let ident_name = rule_metadata + .name + .unwrap_or_else(|| format!("{}{}", name, i)); + // General case, GroupN type identifiers and generate group choice since it's inlined here + let variant_name = RustIdent::new(CDDLIdent::new(ident_name)); + types.mark_plain_group(variant_name.clone(), None); + parse_group_choice( + types, + parent_visitor, + group_choice, + &variant_name, + rep, + None, + generic_params.clone(), + ); + EnumVariant::new( + VariantIdent::new_rust(variant_name.clone()), + ConceptualRustType::Rust(variant_name).into(), + true, + ) + } + }) + .collect(); + types.register_rust_struct( + parent_visitor, + RustStruct::new_group_choice(name.clone(), tag, variants, rep), + ); } } -fn get_comments_if_group_parent<'a>(parent_visitor: &'a ParentVisitor<'a, 'a>, cddl_type: &CDDLType<'a, 'a>, child: Option<&CDDLType<'a, 'a>>, comments_after_group: &Option>) -> Option> { +fn get_comments_if_group_parent<'a>( + parent_visitor: &'a ParentVisitor<'a, 'a>, + cddl_type: &CDDLType<'a, 'a>, + child: Option<&CDDLType<'a, 'a>>, + comments_after_group: &Option>, +) -> Option> { if let Some(CDDLType::Group(_)) = child { - return comments_after_group.clone() + return comments_after_group.clone(); } - get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)) + get_comment_after( + parent_visitor, + cddl_type.parent(parent_visitor).unwrap(), + Some(cddl_type), + ) } -fn get_comments_if_type_parent<'a>(parent_visitor: &'a ParentVisitor<'a, 'a>, cddl_type: &CDDLType<'a, 'a>, child: Option<&CDDLType<'a, 'a>>, comments_after_type: &Option>) -> Option> { +fn get_comments_if_type_parent<'a>( + parent_visitor: &'a ParentVisitor<'a, 'a>, + cddl_type: &CDDLType<'a, 'a>, + child: Option<&CDDLType<'a, 'a>>, + comments_after_type: &Option>, +) -> Option> { if let Some(CDDLType::Type(_)) = child { - return comments_after_type.clone() + return comments_after_type.clone(); } - get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)) + get_comment_after( + parent_visitor, + cddl_type.parent(parent_visitor).unwrap(), + Some(cddl_type), + ) } - /// Gets the comment(s) that come after a type by parsing the CDDL AST -/// +/// /// (implementation detail) sometimes getting the comment after a type requires walking up the AST /// This happens when whether or not the type has a comment after it depends in which structure it is embedded in /// For example, CDDLType::Group has no "comment_after_group" type /// However, when part of a Type2::Array, it does have a "comment_after_group" embedded inside the Type2 -/// +/// /// Note: we do NOT merge comments when the type is coincidentally the last node inside its parent structure /// For example, the last CDDLType::GroupChoice inside a CDDLType::Group will not return its parent's comment -fn get_comment_after<'a>(parent_visitor: &'a ParentVisitor<'a, 'a>, cddl_type: &CDDLType<'a, 'a>, child: Option<&CDDLType<'a, 'a>>) -> Option> { +fn get_comment_after<'a>( + parent_visitor: &'a ParentVisitor<'a, 'a>, + cddl_type: &CDDLType<'a, 'a>, + child: Option<&CDDLType<'a, 'a>>, +) -> Option> { match cddl_type { CDDLType::CDDL(_) => None, - CDDLType::Rule(t) => - match t { - Rule::Type { comments_after_rule, .. } => comments_after_rule.clone(), - Rule::Group { comments_after_rule, .. } => comments_after_rule.clone(), - }, - CDDLType::TypeRule(_) => get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)), - CDDLType::GroupRule(_) => get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)), - CDDLType::Group(_) => { - match cddl_type.parent(parent_visitor).unwrap() { - parent@CDDLType::GroupEntry(_) => get_comment_after(parent_visitor, parent, Some(cddl_type)), - parent@CDDLType::Type2(_) => get_comment_after(parent_visitor, parent, Some(cddl_type)), - parent@CDDLType::MemberKey(_) => get_comment_after(parent_visitor, parent, Some(cddl_type)), - _ => None, + CDDLType::Rule(t) => match t { + Rule::Type { + comments_after_rule, + .. + } => comments_after_rule.clone(), + Rule::Group { + comments_after_rule, + .. + } => comments_after_rule.clone(), + }, + CDDLType::TypeRule(_) => get_comment_after( + parent_visitor, + cddl_type.parent(parent_visitor).unwrap(), + Some(cddl_type), + ), + CDDLType::GroupRule(_) => get_comment_after( + parent_visitor, + cddl_type.parent(parent_visitor).unwrap(), + Some(cddl_type), + ), + CDDLType::Group(_) => match cddl_type.parent(parent_visitor).unwrap() { + parent @ CDDLType::GroupEntry(_) => { + get_comment_after(parent_visitor, parent, Some(cddl_type)) + } + parent @ CDDLType::Type2(_) => { + get_comment_after(parent_visitor, parent, Some(cddl_type)) } + parent @ CDDLType::MemberKey(_) => { + get_comment_after(parent_visitor, parent, Some(cddl_type)) + } + _ => None, }, // TODO: handle child by looking up the group entry in group_entries // the expected behavior of this may instead be to combine_comments based off its parents @@ -1034,26 +1590,33 @@ fn get_comment_after<'a>(parent_visitor: &'a ParentVisitor<'a, 'a>, cddl_type: & CDDLType::GenericParams(_) => None, CDDLType::GenericParam(t) => { if let Some(CDDLType::Identifier(_)) = child { - return t.comments_after_ident.clone() + return t.comments_after_ident.clone(); } None - }, + } CDDLType::GenericArgs(_) => None, CDDLType::GenericArg(t) => { if let Some(CDDLType::Type1(_)) = child { - return t.comments_after_type.clone() + return t.comments_after_type.clone(); } None - }, + } CDDLType::GroupEntry(t) => match t { - GroupEntry::ValueMemberKey { trailing_comments, .. } => trailing_comments.clone(), - GroupEntry::TypeGroupname { trailing_comments, .. } => trailing_comments.clone(), - GroupEntry::InlineGroup { comments_after_group, .. } => { + GroupEntry::ValueMemberKey { + trailing_comments, .. + } => trailing_comments.clone(), + GroupEntry::TypeGroupname { + trailing_comments, .. + } => trailing_comments.clone(), + GroupEntry::InlineGroup { + comments_after_group, + .. + } => { if let Some(CDDLType::Group(_)) = child { - return comments_after_group.clone() + return comments_after_group.clone(); } None - }, + } }, CDDLType::Identifier(_) => None, // TODO: recurse up for GenericParam CDDLType::Type(_) => None, @@ -1061,63 +1624,107 @@ fn get_comment_after<'a>(parent_visitor: &'a ParentVisitor<'a, 'a>, cddl_type: & CDDLType::Type1(t) => { if let Some(CDDLType::Type2(_)) = child { if let Some(op) = &t.operator { - return op.comments_before_operator.clone() + return op.comments_before_operator.clone(); } else { - return t.comments_after_type.clone() + return t.comments_after_type.clone(); } }; if t.operator.is_none() { - get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)) + get_comment_after( + parent_visitor, + cddl_type.parent(parent_visitor).unwrap(), + Some(cddl_type), + ) } else { None } - }, + } CDDLType::Type2(t) => match t { - Type2::ParenthesizedType { comments_after_type, .. } => get_comments_if_type_parent(parent_visitor, cddl_type, child, comments_after_type), - Type2::Map { comments_after_group, .. } => get_comments_if_group_parent(parent_visitor, cddl_type, child, comments_after_group), - Type2::Array { comments_after_group, .. } => get_comments_if_group_parent(parent_visitor, cddl_type, child, comments_after_group), - Type2::Unwrap { .. } => get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)), - Type2::ChoiceFromInlineGroup { comments_after_group, .. } => get_comments_if_group_parent(parent_visitor, cddl_type, child, comments_after_group), - Type2::ChoiceFromGroup { .. } => get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)), - Type2::TaggedData { comments_after_type, .. } => get_comments_if_type_parent(parent_visitor, cddl_type, child, comments_after_type), + Type2::ParenthesizedType { + comments_after_type, + .. + } => get_comments_if_type_parent(parent_visitor, cddl_type, child, comments_after_type), + Type2::Map { + comments_after_group, + .. + } => { + get_comments_if_group_parent(parent_visitor, cddl_type, child, comments_after_group) + } + Type2::Array { + comments_after_group, + .. + } => { + get_comments_if_group_parent(parent_visitor, cddl_type, child, comments_after_group) + } + Type2::Unwrap { .. } => get_comment_after( + parent_visitor, + cddl_type.parent(parent_visitor).unwrap(), + Some(cddl_type), + ), + Type2::ChoiceFromInlineGroup { + comments_after_group, + .. + } => { + get_comments_if_group_parent(parent_visitor, cddl_type, child, comments_after_group) + } + Type2::ChoiceFromGroup { .. } => get_comment_after( + parent_visitor, + cddl_type.parent(parent_visitor).unwrap(), + Some(cddl_type), + ), + Type2::TaggedData { + comments_after_type, + .. + } => get_comments_if_type_parent(parent_visitor, cddl_type, child, comments_after_type), _ => None, }, CDDLType::Operator(t) => { if let Some(CDDLType::RangeCtlOp(_)) = child { - return t.comments_after_operator.clone() + return t.comments_after_operator.clone(); } if let Some(CDDLType::Type2(t2)) = child { // "comments_before_operator" is associated with the 1st type2 and not the second (t.type2) if std::ptr::eq(*t2, &t.type2) { - return None + return None; } else { - return t.comments_before_operator.clone() + return t.comments_before_operator.clone(); } } None - }, + } CDDLType::Occurrence(t) => t.comments.clone(), CDDLType::Occur(_) => None, CDDLType::Value(_) => None, CDDLType::ValueMemberKeyEntry(_) => None, CDDLType::TypeGroupnameEntry(_) => None, CDDLType::MemberKey(t) => match t { - MemberKey::NonMemberKey { comments_after_type_or_group, .. } => comments_after_type_or_group.clone(), - _ => None + MemberKey::NonMemberKey { + comments_after_type_or_group, + .. + } => comments_after_type_or_group.clone(), + _ => None, }, - CDDLType::NonMemberKey(_) => get_comment_after(parent_visitor, cddl_type.parent(parent_visitor).unwrap(), Some(cddl_type)), - _ => None + CDDLType::NonMemberKey(_) => get_comment_after( + parent_visitor, + cddl_type.parent(parent_visitor).unwrap(), + Some(cddl_type), + ), + _ => None, } } -fn get_rule_name<'a, 'b>(parent_visitor: &'a ParentVisitor, cddl_type: &CDDLType<'a, 'b>) -> Identifier<'a> { +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"), - CDDLType::Rule(t) => - match t { - Rule::Type { rule, .. } => get_rule_name(parent_visitor, &CDDLType::from(rule)), - Rule::Group { rule, .. } => get_rule_name(parent_visitor, &CDDLType::from(rule.as_ref())), - }, + CDDLType::Rule(t) => match t { + Rule::Type { rule, .. } => get_rule_name(parent_visitor, &CDDLType::from(rule)), + Rule::Group { rule, .. } => { + get_rule_name(parent_visitor, &CDDLType::from(rule.as_ref())) + } + }, CDDLType::TypeRule(t) => t.name.clone(), CDDLType::GroupRule(t) => t.name.clone(), other => get_rule_name(parent_visitor, other.parent(parent_visitor).unwrap()), diff --git a/src/rust_reserved.rs b/src/rust_reserved.rs index a3ef878..6cd8324 100644 --- a/src/rust_reserved.rs +++ b/src/rust_reserved.rs @@ -44,5 +44,5 @@ pub const STD_TYPES: [&str; 40] = [ "Vec", "TryFrom", "TryInto", - "FromIterator" -]; \ No newline at end of file + "FromIterator", +]; diff --git a/src/test.rs b/src/test.rs index 70c84b5..17cce54 100644 --- a/src/test.rs +++ b/src/test.rs @@ -5,11 +5,12 @@ fn run_test( options: &[&str], export_suffix: Option<&str>, external_core_file_path: Option, - external_wasm_file_path: Option) { + external_wasm_file_path: Option, +) { use std::str::FromStr; let export_path = match export_suffix { Some(suffix) => format!("export_{}", suffix), - None => "export".to_owned() + None => "export".to_owned(), }; let test_path = std::path::PathBuf::from_str("tests").unwrap().join(dir); println!("--------- running test: {} ---------", dir); @@ -18,8 +19,14 @@ fn run_test( cargo_run .arg("run") .arg("--") - .arg(format!("--input={}", test_path.join("input.cddl").to_str().unwrap())) - .arg(format!("--output={}", test_path.join(&export_path).to_str().unwrap())); + .arg(format!( + "--input={}", + test_path.join("input.cddl").to_str().unwrap() + )) + .arg(format!( + "--output={}", + test_path.join(&export_path).to_str().unwrap() + )); for option in options { cargo_run.arg(option); } @@ -41,7 +48,12 @@ fn run_test( lib_rs.write("\n\n".as_bytes()).unwrap(); lib_rs.write_all(extern_rs.as_bytes()).unwrap(); } - let deser_test_rs = std::fs::read_to_string(std::path::PathBuf::from_str("tests").unwrap().join("deser_test")).unwrap(); + let deser_test_rs = std::fs::read_to_string( + std::path::PathBuf::from_str("tests") + .unwrap() + .join("deser_test"), + ) + .unwrap(); lib_rs.write("\n\n".as_bytes()).unwrap(); lib_rs.write_all(deser_test_rs.as_bytes()).unwrap(); let test_rs = std::fs::read_to_string(test_path.join("tests.rs")).unwrap(); @@ -56,9 +68,15 @@ fn run_test( .output() .unwrap(); if !cargo_test.status.success() { - eprintln!("test stderr:\n{}", String::from_utf8(cargo_test.stderr).unwrap()); + eprintln!( + "test stderr:\n{}", + String::from_utf8(cargo_test.stderr).unwrap() + ); } - println!("test stdout:\n{}", String::from_utf8(cargo_test.stdout).unwrap()); + println!( + "test stdout:\n{}", + String::from_utf8(cargo_test.stdout).unwrap() + ); assert!(cargo_test.status.success()); // wasm @@ -84,18 +102,27 @@ fn run_test( .output() .unwrap(); if !cargo_test_wasm.status.success() { - eprintln!("test stderr:\n{}", String::from_utf8(cargo_test_wasm.stderr).unwrap()); + eprintln!( + "test stderr:\n{}", + String::from_utf8(cargo_test_wasm.stderr).unwrap() + ); } - println!("test stdout:\n{}", String::from_utf8(cargo_test_wasm.stdout).unwrap()); + println!( + "test stdout:\n{}", + String::from_utf8(cargo_test_wasm.stdout).unwrap() + ); assert!(cargo_test_wasm.status.success()); } else if wasm_export_dir.exists() { let cargo_build_wasm = std::process::Command::new("cargo") - .arg("build") + .arg("build") .current_dir(wasm_export_dir) .output() .unwrap(); if !cargo_build_wasm.status.success() { - eprintln!("wasm build stderr:\n{}", String::from_utf8(cargo_build_wasm.stderr).unwrap()); + eprintln!( + "wasm build stderr:\n{}", + String::from_utf8(cargo_build_wasm.stderr).unwrap() + ); } assert!(cargo_build_wasm.status.success()); } @@ -104,31 +131,67 @@ fn run_test( #[test] fn core_with_wasm() { use std::str::FromStr; - let extern_core_path = std::path::PathBuf::from_str("tests").unwrap().join("external_core_defs"); - let extern_wasm_path = std::path::PathBuf::from_str("tests").unwrap().join("external_wasm_defs"); - run_test("core", &[], Some("wasm"), Some(extern_core_path), Some(extern_wasm_path)); + let extern_core_path = std::path::PathBuf::from_str("tests") + .unwrap() + .join("external_core_defs"); + let extern_wasm_path = std::path::PathBuf::from_str("tests") + .unwrap() + .join("external_wasm_defs"); + run_test( + "core", + &[], + Some("wasm"), + Some(extern_core_path), + Some(extern_wasm_path), + ); } #[test] fn core_no_wasm() { use std::str::FromStr; - let extern_core_path = std::path::PathBuf::from_str("tests").unwrap().join("external_core_defs"); - run_test("core", &["--wasm=false"], None, Some(extern_core_path), None); + let extern_core_path = std::path::PathBuf::from_str("tests") + .unwrap() + .join("external_core_defs"); + run_test( + "core", + &["--wasm=false"], + None, + Some(extern_core_path), + None, + ); } #[test] fn comment_dsl() { - run_test("comment-dsl", &["--preserve-encodings=true"], Some("wasm"), None , None); + run_test( + "comment-dsl", + &["--preserve-encodings=true"], + Some("wasm"), + None, + None, + ); } #[test] fn preserve_encodings() { - run_test("preserve-encodings", &["--preserve-encodings=true"], None, None, None); + run_test( + "preserve-encodings", + &["--preserve-encodings=true"], + None, + None, + None, + ); } #[test] fn canonical() { - run_test("canonical", &["--preserve-encodings=true", "--canonical-form=true"], None, None, None); + run_test( + "canonical", + &["--preserve-encodings=true", "--canonical-form=true"], + None, + None, + None, + ); } #[test] diff --git a/src/utils.rs b/src/utils.rs index ddf3c9e..10ee6e7 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,5 @@ use cbor_event::Type as CBORType; -use std::collections::{BTreeMap}; +use std::collections::BTreeMap; use crate::cli::CLI_ARGS; @@ -22,10 +22,10 @@ pub fn convert_to_snake_case(ident: &str) -> String { match c { '-' => { snake_case.push('_'); - }, + } '$' | '@' => { // ignored - }, + } c => { if c.is_ascii_uppercase() && !snake_case.is_empty() { snake_case.push('_') @@ -44,10 +44,10 @@ pub fn convert_to_camel_case(ident: &str) -> String { match c { '_' | '-' => { uppercase = true; - }, + } '$' | '@' => { // ignored - }, + } c => { if uppercase { camel_case.push(c.to_ascii_uppercase()); @@ -55,7 +55,7 @@ pub fn convert_to_camel_case(ident: &str) -> String { } else { camel_case.push(c); } - }, + } } } camel_case @@ -101,6 +101,7 @@ pub fn cddl_prelude(name: &str) -> Option<&str> { } } +#[rustfmt::skip] pub fn is_identifier_reserved(name: &str) -> bool { match name { // These are all possible reserved identifiers, even if we don't support them @@ -148,6 +149,7 @@ pub fn is_identifier_reserved(name: &str) -> bool { } // as we also support our own identifiers for selecting integer precision, we need this too +#[rustfmt::skip] pub fn is_identifier_in_our_prelude(name: &str) -> bool { match name { "u8" | @@ -176,4 +178,4 @@ pub fn append_number_if_duplicate(used_names: &mut BTreeMap, name: } else { name } -} \ No newline at end of file +}