You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This works with zcbor.py, but with cddl-codegen, I get this output:
thread 'main' panicked at src/intermediate.rs:1748:31:
should not expose Fixed type in member, only needed for serializaiton: Fixed(Uint(0))
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
I think it is valid CDDL, but maybe it is some edge case. Would be also ok if there is a way to write it differently, and if this works then with zcbor as well.
--- a/src/intermediate.rs
+++ b/src/intermediate.rs
@@ -1612,7 +1612,7 @@ impl ConceptualRustType {
/// Function parameter TYPE by-non-mut-reference for read-only
pub fn _for_rust_read(&self, types: &IntermediateTypes, cli: &Cli) -> String {
match self {
- Self::Fixed(_) => panic!(
+ Self::Fixed(_) => format!(
"should not expose Fixed type, only here for serialization: {:?}",
self
),
@@ -1745,9 +1745,8 @@ impl ConceptualRustType {
/// Type when storing a value inside of a rust struct. This is the underlying raw representation.
pub fn for_rust_member(&self, types: &IntermediateTypes, from_wasm: bool, cli: &Cli) -> String {
match self {
- Self::Fixed(_) => panic!(
- "should not expose Fixed type in member, only needed for serializaiton: {:?}",
- self
+ Self::Fixed(_) => format!(
+ "u8"
),
Self::Primitive(p) => p.to_string(),
Self::Rust(ident) => {
It creates 2 unnecessary types, but it compiles, and the serialization code looks good, but haven't tested it yet. Of course, this would be an ugly solution, it should just ignore it for constants and not trying to create types for it, but haven't looked at the rest of the code how to do this.
What are the unnecessary types? Did you create 2 extra cmd_start / cmd_stop types to get it to work? I guess it would depend on how you re-wrote the cddl.
In case you're talking about a MyCommandKind, it's because for WASM we create a EnumKind for each Enum type because group choices have/can contain extra information e.g. the array length and we code this for the general case e.g. group_choice = [0, uint // tstr, bytes]. You cannot expose these directly to wasm and thus we generate the EnumKind type to let wasm_bindgen have a way of easily differentiating types (no pattern matching like in rust). This is more important for your case when running with --preserve-encodings=true as then the group choice has to keep information about its encoding (definite vs indefinite array encoding, and if definite, how many bytes were used for the length part or if it was inlined) to ensure correct round-tripping and exposing control over encoding details. In the protocols we work with when it is a genuine C-style enum we've usually seen it as a type choice instead (no need to waste extra byte(s) on the array part):
Thanks, but with the @ comments doesn't work with zcbor, and I want to use the same CDDL files for both, the C program (a Zephyr project) and the Rust project. With my patch it works. It generates an extra type, but also an enum. Here is the generated lib.rs for the CDDL file I posted:
#![allow(clippy::too_many_arguments)]pubmod error;// This file was code-generated using an experimental CDDL to rust tool:// https://github.com/dcSpark/cddl-codegenpubmod serialization;usecrate::error::*;use std::collections::BTreeMap;use std::convert::TryFrom;pubtypeCmdStart = u8;#[derive(Copy,Eq,PartialEq,Ord,PartialOrd,Clone,Debug)]#[wasm_bindgen::prelude::wasm_bindgen]pubenumCmdStartOrCmdStop{CmdStart,CmdStop,}pubtypeCmdStop = u8;#[derive(Clone,Debug)]pubstructMyCommand{pubcommand:CmdStartOrCmdStop,}implMyCommand{pubfnnew(command:CmdStartOrCmdStop) -> Self{Self{ command }}}
I think it is a bug in cddl-codegen that it tries to generate a type for a number constant. And I think it should be valid CDDL, at least syntactically: According to the ABNF of RFC 8610, a rule is a typename = type, where type can be type1, which can be type2, which can be a value, which can be a number.
Yeah the ; @<tag> notation is a cddl-codegen specific thing we've done to provide extra information when it's not directly available e.g. to tell cddl-codegen to encode it differently or to derive rust traits or to rename things. You could just remove it but then your types will be called like MyCommand::I0 and MyCommand::I1
I think it should be valid CDDL, at least syntactically
It is.
I think it is a bug in cddl-codegen that it tries to generate a type for a number constant.
It probably is. I thought we had constant support although for wasm it does it via function like function cmd_start(): number.
results in this crash (with my applied patch, otherwise it crashes already for the constants earlier) :
thread 'main' panicked at src/intermediate.rs:1408:64:
called `Option::unwrap()` on a `None` value
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Problem is the last foobar definition. If I remove it, then it works, but it is not usable for me. I guess this is a good candidate for a new test case? I simplified it already from my real usecase.
zcbor works just fine with it. Calling it like this:
I'm not sure this is technically proper CBOR as both are basic groups still and not yet concrete types. Try doing foo // bar instead if you want to use group choices (//). Type choices (/) require the type variants to be concrete types afaik, but maybe all type choices being a basic group is enough to lock in the type, but type choices as per the CDDL RFC are meant to be used on types and a basic group isn't a type until it knows if it's an array or map group as that completely changes the CBOR representation. Either way I can't imagine what [foo / bar] would represent that wouldn't just be [foo // bar] so try that instead, as the second notation is meant specifically for this situation. I can't find anything 100% in the RFC but it is explicit about group choices being used for groups and type choices on types and that groups on their own don't seem to be types yet, unless made into one by wrapping it with []/{}, which in this case would happen after the point where you need it to be a type. I could be wrong here but it just seems like using group choices instead is what you would want here. Basic groups (like foo/bar here defined with only(/)) don't have a concrete cbor definition yet (they are abstract concepts since you don't know if they're array or map yet but maybe zbor just assumes based on the context there), to do that you need to do e.g.
baz = [
a: uint,
foo, ; this embeds all fields into baz so baz has 3 fields
]
or
baz = [
a: uint,
foo: [foo], ; now baz has 2 fields, the second of which is an array with 2 elements aka foo
]
or group choices
foobar = [
foo // bar
]
We use a lot of similar cddl defs written like:
; probably not as useful for you since you can't use our @name notation to name the variants
foobar = [
type: 0, something1: uint .size 4 //
type: 1, something2: uint .size 4, something3: uint .size 4
]
Commas work. Sorry, that was a mistake on my end, I simply forgot to add them there since I was only typing in the browser as an example and had copied/pasted from other lines. I'm surprised it worked without commas, I would have thought they would be required based on the CDDL RFC. I didn't write the parsing code though, we use the external cddl crate for that and then just operate on their AST to do our codegen.
Looks like the deserialize had a tricky problem: It did a read_len.read_elems(4), independent of the type. But with a group_foo_or_bar, the array has only 1 element. I also fixed this manually, looks like now I can read it correctly.
Might be good to add my last test as a new test case and then enhance the tests to try to serialize and deserialize it.
Another problem: The Rust code expected an additional array for the inner group_baz//group_foo_or_bar. But the zcbor code generated it inline, without an additional array. I think zcbor is right. After manually fixing this, both types work now for my application. But would be good, if it could be fixed for the cddl-codegen project as well, because I might need to regenerate the code when the CDDL changes, and then I would need to apply the manual patches again.
I've only ever seen group choices at the full group level e.g. [group1 // group2] for basic (non-array/map) groups group1/group2 so the code kind of assumes that structure. If you do [uint, group1 // group2, tstr] I have no idea what the code would generate or even think it is.
What happens if you do this? e.g. move the TYPE1 into the other two groups.
I'll test it, but is my example valid CDDL, and which program is right, zcbor or cddl-codegen? But I think this is a different problem. I think I fixed the constant problem, see here: #242 and we can close this issue, and create a new issue for the nested array, if it is wrong, otherwise we should create an issue in the zcbor repository ( https://github.com/NordicSemiconductor/zcbor ).
Activity
Frank-Buss commentedon Oct 31, 2024
I tried this patch:
It creates 2 unnecessary types, but it compiles, and the serialization code looks good, but haven't tested it yet. Of course, this would be an ugly solution, it should just ignore it for constants and not trying to create types for it, but haven't looked at the rest of the code how to do this.
rooooooooob commentedon Oct 31, 2024
@Frank-Buss
try:
if that format works for you.
What are the unnecessary types? Did you create 2 extra
cmd_start/cmd_stoptypes to get it to work? I guess it would depend on how you re-wrote the cddl.In case you're talking about a
MyCommandKind, it's because for WASM we create aEnumKindfor eachEnumtype because group choices have/can contain extra information e.g. the array length and we code this for the general case e.g.group_choice = [0, uint // tstr, bytes]. You cannot expose these directly to wasm and thus we generate theEnumKindtype to letwasm_bindgenhave a way of easily differentiating types (no pattern matching like in rust). This is more important for your case when running with--preserve-encodings=trueas then the group choice has to keep information about its encoding (definite vs indefinite array encoding, and if definite, how many bytes were used for the length part or if it was inlined) to ensure correct round-tripping and exposing control over encoding details. In the protocols we work with when it is a genuine C-style enum we've usually seen it as a type choice instead (no need to waste extra byte(s) on the array part):which wouldn't generate the extra
MyCommandKindtype in rust. This won't help if you're interfacing with an existing protocol though.Frank-Buss commentedon Oct 31, 2024
Thanks, but with the @ comments doesn't work with zcbor, and I want to use the same CDDL files for both, the C program (a Zephyr project) and the Rust project. With my patch it works. It generates an extra type, but also an enum. Here is the generated lib.rs for the CDDL file I posted:
I think it is a bug in cddl-codegen that it tries to generate a type for a number constant. And I think it should be valid CDDL, at least syntactically: According to the ABNF of RFC 8610, a rule is a typename = type, where type can be type1, which can be type2, which can be a value, which can be a number.
rooooooooob commentedon Oct 31, 2024
Yeah the
; @<tag>notation is a cddl-codegen specific thing we've done to provide extra information when it's not directly available e.g. to tell cddl-codegen to encode it differently or to derive rust traits or to rename things. You could just remove it but then your types will be called likeMyCommand::I0andMyCommand::I1It is.
It probably is. I thought we had constant support although for wasm it does it via function like
function cmd_start(): number.Frank-Buss commentedon Nov 6, 2024
Might be a related problems with constants, haven't looked into it, but it currently blocks my project. This file:
results in this crash (with my applied patch, otherwise it crashes already for the constants earlier) :
Problem is the last foobar definition. If I remove it, then it works, but it is not usable for me. I guess this is a good candidate for a new test case? I simplified it already from my real usecase.
zcbor works just fine with it. Calling it like this:
generates this file:
rooooooooob commentedon Nov 6, 2024
@Frank-Buss
I'm not sure this is technically proper CBOR as both are basic groups still and not yet concrete types. Try doing
foo // barinstead if you want to use group choices (//). Type choices (/) require the type variants to be concrete types afaik, but maybe all type choices being a basic group is enough to lock in the type, but type choices as per the CDDL RFC are meant to be used on types and a basic group isn't a type until it knows if it's an array or map group as that completely changes the CBOR representation. Either way I can't imagine what[foo / bar]would represent that wouldn't just be[foo // bar]so try that instead, as the second notation is meant specifically for this situation. I can't find anything 100% in the RFC but it is explicit about group choices being used for groups and type choices on types and that groups on their own don't seem to be types yet, unless made into one by wrapping it with[]/{}, which in this case would happen after the point where you need it to be a type. I could be wrong here but it just seems like using group choices instead is what you would want here. Basic groups (like foo/bar here defined with only(/)) don't have a concrete cbor definition yet (they are abstract concepts since you don't know if they're array or map yet but maybe zbor just assumes based on the context there), to do that you need to do e.g.or
or group choices
We use a lot of similar cddl defs written like:
or
I hope this helps.
Frank-Buss commentedon Nov 6, 2024
Thanks, looks like zcbor generates the same code for "//". But I need a comma at the end of the lines:
cddl-codegen works without commas as well (with my patch with the constants). Haven't checked the BNF, is a comma required?
Will check if the Rust code works tomorrow.
rooooooooob commentedon Nov 7, 2024
Commas work. Sorry, that was a mistake on my end, I simply forgot to add them there since I was only typing in the browser as an example and had copied/pasted from other lines. I'm surprised it worked without commas, I would have thought they would be required based on the CDDL RFC. I didn't write the parsing code though, we use the external
cddlcrate for that and then just operate on their AST to do our codegen.Frank-Buss commentedon Nov 7, 2024
I tested it, and there is one compilation error for the generated code. Here is the test file:
For this, it generates this code in serialization.rs:
The error is in line "+ match &self.group_baz.max {". It needs to be "+ match &group_baz.max {". This is probably easy to fix, but couldn't find it.
Haven't tested yet if it runs, but at least now it compiles everything.
Frank-Buss commentedon Nov 7, 2024
Looks like the deserialize had a tricky problem: It did a read_len.read_elems(4), independent of the type. But with a group_foo_or_bar, the array has only 1 element. I also fixed this manually, looks like now I can read it correctly.
Might be good to add my last test as a new test case and then enhance the tests to try to serialize and deserialize it.
Frank-Buss commentedon Nov 7, 2024
Another problem: The Rust code expected an additional array for the inner group_baz//group_foo_or_bar. But the zcbor code generated it inline, without an additional array. I think zcbor is right. After manually fixing this, both types work now for my application. But would be good, if it could be fixed for the cddl-codegen project as well, because I might need to regenerate the code when the CDDL changes, and then I would need to apply the manual patches again.
rooooooooob commentedon Nov 7, 2024
I've only ever seen group choices at the full group level e.g.
[group1 // group2]for basic (non-array/map) groupsgroup1/group2so the code kind of assumes that structure. If you do[uint, group1 // group2, tstr]I have no idea what the code would generate or even think it is.What happens if you do this? e.g. move the
TYPE1into the other two groups.Frank-Buss commentedon Nov 8, 2024
I'll test it, but is my example valid CDDL, and which program is right, zcbor or cddl-codegen? But I think this is a different problem. I think I fixed the constant problem, see here: #242 and we can close this issue, and create a new issue for the nested array, if it is wrong, otherwise we should create an issue in the zcbor repository ( https://github.com/NordicSemiconductor/zcbor ).