Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
322 changes: 288 additions & 34 deletions src/generation.rs

Large diffs are not rendered by default.

39 changes: 23 additions & 16 deletions src/intermediate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ pub enum Representation {
pub enum FixedValue {
Null,
Bool(bool),
Int(isize),
Nint(isize),
Uint(usize),
// float not supported right now - doesn't appear to be in cbor_event
//Float(f64),
Expand All @@ -386,7 +386,7 @@ impl FixedValue {
true => "True",
false => "False",
}),
FixedValue::Int(i) => VariantIdent::new_custom(format!("U{}", i)),
FixedValue::Nint(i) => VariantIdent::new_custom(format!("U{}", i)),
FixedValue::Uint(u) => VariantIdent::new_custom(format!("I{}", u)),
//FixedValue::Float(f) => format!("F{}", f),
FixedValue::Text(s) => VariantIdent::new_custom(convert_to_alphanumeric(&convert_to_camel_case(&s))),
Expand All @@ -398,7 +398,7 @@ impl FixedValue {
match self {
FixedValue::Null => buf.write_special(cbor_event::Special::Null),
FixedValue::Bool(b) => buf.write_special(cbor_event::Special::Bool(*b)),
FixedValue::Int(i) => buf.write_negative_integer(*i as i64),
FixedValue::Nint(i) => buf.write_negative_integer(*i as i64),
FixedValue::Uint(u) => buf.write_unsigned_integer(*u as u64),
FixedValue::Text(s) => buf.write_text(s),
}.expect("Unable to serialize key for canonical ordering");
Expand Down Expand Up @@ -444,8 +444,7 @@ impl Primitive {
Primitive::I32 => "i32",
Primitive::U64 => "u64",
Primitive::I64 => "i64",
// TODO: this should ideally be a u64 but the cbor_event lib takes i64 anyway so we don't get that extra precision
Primitive::N64 => "i64",
Primitive::N64 => "u64",
Primitive::Str => "String",
Primitive::Bytes => "Vec<u8>",
})
Expand Down Expand Up @@ -672,11 +671,10 @@ impl RustType {
Primitive::I16 |
Primitive::U16 |
Primitive::I32 |
Primitive::U32 => true,
// since we generate these as BigNum/Int wrappers we can't nest them
Primitive::U32 |
Primitive::I64 |
Primitive::N64 |
Primitive::U64 => false,
Primitive::U64 => true,
// Bytes is already implemented as Vec<u8> so we can't nest it
Primitive::Bytes => false,
// Vec<String> is not supported by wasm-bindgen
Expand Down Expand Up @@ -743,25 +741,34 @@ impl RustType {

/// Function parameter TYPE from wasm (i.e. ref for non-primitives, value for supported primitives)
pub fn for_wasm_param(&self) -> String {
self.for_wasm_param_impl(false)
}

fn for_wasm_param_impl(&self, force_not_ref: bool) -> String {
let opt_ref = if force_not_ref {
""
} else {
"&"
};
match self {
RustType::Fixed(_) => panic!("should not expose Fixed type to wasm, only here for serialization: {:?}", self),
RustType::Primitive(p) => p.to_string(),
RustType::Rust(ident) => format!("&{}", ident),
RustType::Rust(ident) => format!("{}{}", opt_ref, ident),
RustType::Array(ty) => if self.directly_wasm_exposable() {
ty.name_as_wasm_array()
} else {
format!("&{}", ty.name_as_wasm_array())
format!("{}{}", opt_ref, ty.name_as_wasm_array())
},
RustType::Tagged(_tag, ty) => ty.for_wasm_param(),
RustType::Optional(ty) => format!("Option<{}>", ty.for_wasm_param()),
RustType::Map(_k, _v) => format!("&{}", self.for_wasm_member()),
RustType::Tagged(_tag, ty) => ty.for_wasm_param_impl(force_not_ref),
RustType::Optional(ty) => format!("Option<{}>", ty.for_wasm_param_impl(true)),
RustType::Map(_k, _v) => format!("{}{}", opt_ref, self.for_wasm_member()),
// it might not be worth generating this as alises 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
RustType::Alias(ident, ty) => match &**ty {
RustType::Rust(_) => format!("&{}", ident),
RustType::Rust(_) => format!("{}{}", opt_ref, ident),
_ => ident.to_string(),
}
RustType::CBORBytes(ty) => ty.for_wasm_member(),
RustType::CBORBytes(ty) => ty.for_wasm_param(),
}
}

Expand Down Expand Up @@ -1005,7 +1012,7 @@ impl RustType {
match self {
RustType::Fixed(f) => vec![match f {
FixedValue::Uint(_) => CBORType::UnsignedInteger,
FixedValue::Int(_) => CBORType::NegativeInteger,
FixedValue::Nint(_) => CBORType::NegativeInteger,
FixedValue::Text(_) => CBORType::Text,
FixedValue::Null => CBORType::Special,
FixedValue::Bool(_) => CBORType::Special,
Expand Down
2 changes: 0 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
gen_scope.wasm().import("wasm_bindgen::prelude", "*");
gen_scope
.wasm()
.raw("mod prelude;")
.raw("use std::collections::BTreeMap;");

if CLI_ARGS.preserve_encodings {
Expand Down Expand Up @@ -193,7 +192,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
wasm_toml.push_str("serde_json = \"1.0.57\"\n");
}
std::fs::write(rust_dir.join("wasm/Cargo.toml"), wasm_toml)?;
std::fs::copy("static/prelude_wasm.rs", rust_dir.join("wasm/src/prelude.rs"))?;
}

// json-gen crate for exporting JSON schemas
Expand Down
8 changes: 4 additions & 4 deletions src/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ fn parse_type(types: &mut IntermediateTypes, type_name: &RustIdent, type_choice:
},
// Note: bool constants are handled via Type2::Typename
Type2::IntValue{ value, .. } => {
let fallback_type = RustType::Fixed(FixedValue::Int(*value));
let fallback_type = RustType::Fixed(FixedValue::Nint(*value));

let control = type1.operator.as_ref().map(|op| parse_control_operator(types, &Type2AndParent { parent: type1, type2: &type1.type2 }, op));
let base_type = match control {
Expand Down Expand Up @@ -588,7 +588,7 @@ fn rust_type_from_type2(types: &mut IntermediateTypes, type2: &Type2AndParent) -
// TODO: socket plugs (used in hash type)
match &type2.type2 {
Type2::UintValue{ value, .. } => RustType::Fixed(FixedValue::Uint(*value)),
Type2::IntValue{ value, .. } => RustType::Fixed(FixedValue::Int(*value)),
Type2::IntValue{ value, .. } => RustType::Fixed(FixedValue::Nint(*value)),
//Type2::FloatValue{ value, .. } => RustType::Fixed(FixedValue::Float(*value)),
Type2::TextValue{ value, .. } => RustType::Fixed(FixedValue::Text(value.to_string())),
Type2::Typename{ ident, generic_args, .. } => {
Expand Down Expand Up @@ -751,14 +751,14 @@ fn group_entry_to_key(entry: &GroupEntry) -> Option<FixedValue> {
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::Int(*x)),
cddl::token::Value::INT(x) => Some(FixedValue::Nint(*x)),
cddl::token::Value::TEXT(x) => Some(FixedValue::Text(x.to_string())),
_ => 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::Int(*value)),
Type2::IntValue{ value, .. } => Some(FixedValue::Nint(*value)),
Type2::TextValue{ value, .. } => Some(FixedValue::Text(value.to_string())),
_ => panic!("unsupported map identifier(2): {:?}", entry),
},
Expand Down
10 changes: 8 additions & 2 deletions static/ordered_hash_map.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::hash::Hash;
use core::hash::{Hash, Hasher};

#[derive(Clone, Debug)]
#[derive(Clone, Debug, Ord, Eq, PartialEq, PartialOrd)]
pub struct OrderedHashMap<K, V>(linked_hash_map::LinkedHashMap<K, V>) where
K : Hash + Eq + Ord;

Expand All @@ -24,3 +24,9 @@ impl<K, V> OrderedHashMap<K, V> where K : Hash + Eq + Ord {
}
}

impl<K, V> Hash for OrderedHashMap<K, V> where K : Hash + Eq + Ord, V : Hash {
fn hash<H: Hasher>(&self, h: &mut H) {
self.0.hash(h);
}
}

26 changes: 0 additions & 26 deletions static/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,29 +144,3 @@ impl<T: Deserialize + Sized> FromBytes for T {
}
}

#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Int {
Uint(u64),
Nint(u64),
}

impl cbor_event::se::Serialize for Int {
fn serialize<'se, W: Write>(&self, serializer: &'se mut Serializer<W>) -> cbor_event::Result<&'se mut Serializer<W>> {
match self {
Self::Uint(x) => serializer.write_unsigned_integer(*x),
Self::Nint(x) => serializer.write_negative_integer(-(*x as i128) as i64),
}
}
}

impl Deserialize for Int {
fn deserialize<R: BufRead + Seek>(raw: &mut Deserializer<R>) -> Result<Self, DeserializeError> {
(|| -> Result<_, DeserializeError> {
match raw.cbor_type()? {
cbor_event::Type::UnsignedInteger => Ok(Self::Uint(raw.unsigned_integer()?)),
cbor_event::Type::NegativeInteger => Ok(Self::Nint(-raw.negative_integer()? as u64)),
_ => Err(DeserializeFailure::NoVariantMatched.into()),
}
})().map_err(|e| e.annotate("Int"))
}
}
28 changes: 0 additions & 28 deletions static/prelude_wasm.rs

This file was deleted.

21 changes: 20 additions & 1 deletion tests/core/input.cddl
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,23 @@ u16 = uint .le 65535
u32 = 0..4294967295
u64 = uint .size 8 ; 8 bytes
i8 = -128..127
i64 = int .size 8 ; 8 bytes
i64 = int .size 8 ; 8 bytes

signed_ints = [
u_8: uint .size 1,
u_16: uint .size 2,
u_32: uint .size 4,
u_64: uint .size 8,
i_8: int .size 1,
i_16: int .size 2,
i_32: int .size 4,
i_64: int .size 8,
n_64: nint
u64_max: 18446744073709551615,
; this test assumes i64::BITS == isize::BITS (i.e. 64-bit programs) or else the cddl parsing lib would mess up
; if this test fails on your platform we might need to either remove this part
; or make a fix for the cddl library.
; The fix would be ideal as even though the true min in CBOR would be -u64::MAX
; we can't test that since isize::BITS is never > 64 in any normal system and likely never will be
i64_min: -9223372036854775808
]
8 changes: 8 additions & 0 deletions tests/core/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,12 @@ mod tests {
assert_eq!(0u64, U64::from(0u64));
assert_eq!(0i64, I64::from(0i64));
}

#[test]
fn signed_ints() {
let min = SignedInts::new(u8::MIN, u16::MIN, u32::MIN, u64::MIN, i8::MIN, i16::MIN, i32::MIN, i64::MIN, u64::MIN);
deser_test(&min);
let max = SignedInts::new(u8::MAX, u16::MAX, u32::MAX, u64::MAX, i8::MAX, i16::MAX, i32::MAX, i64::MAX, u64::MAX);
deser_test(&max);
}
}
19 changes: 19 additions & 0 deletions tests/preserve-encodings/input.cddl
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,22 @@ foo_bytes = bytes .cbor foo

; since we don't generate code for definitions like the above (should we if no one refers to it?)
cbor_in_cbor = [foo_bytes, uint_bytes: bytes .cbor uint]

signed_ints = [
u_8: uint .size 1,
u_16: uint .size 2,
u_32: uint .size 4,
u_64: uint .size 8,
i_8: int .size 1,
i_16: int .size 2,
i_32: int .size 4,
i_64: int .size 8,
n_64: nint
u64_max: 18446744073709551615,
; this test assumes i64::BITS == isize::BITS or else the cddl parsing lib would mess up
; if this test fails on your platform we might need to either remove this part
; or make a fix for the cddl library.
; The fix would be ideal as even though the true min in CBOR would be -u64::MAX
; we can't support since isize::BITS is never > 64 in any normal system and likely never will be
i64_min: -9223372036854775808
]
59 changes: 59 additions & 0 deletions tests/preserve-encodings/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,4 +447,63 @@ mod tests {
}
}
}

#[test]
fn signed_ints() {
use std::cmp::min;
let umins = [0i128, u8::MIN as i128, u16::MIN as i128, u32::MIN as i128, u64::MIN as i128];
let umaxs = [23i128, u8::MAX as i128, u16::MAX as i128, u32::MAX as i128, u64::MAX as i128];
let imins = [-24i128, i8::MIN as i128, i16::MIN as i128, i32::MIN as i128, i64::MIN as i128];
let imaxs = [-1i128, i8::MAX as i128, i16::MAX as i128, i32::MAX as i128, i64::MAX as i128];
let def_encodings = [Sz::Inline, Sz::One, Sz::Two, Sz::Four, Sz::Eight];
for i in 0..5 {
let i_8 = min(1, i);
let i_16 = min(2, i);
let i_32 = min(3, i);
let i_64 = min(4, i);
let irregular_bytes_min = vec![
vec![ARR_INDEF],
// uints
cbor_int(umins[i_8], def_encodings[i]),
cbor_int(umins[i_16], def_encodings[i]),
cbor_int(umins[i_32], def_encodings[i]),
cbor_int(umins[i_64], def_encodings[i]),
// ints
cbor_int(imins[i_8], def_encodings[i]),
cbor_int(imins[i_16], def_encodings[i]),
cbor_int(imins[i_32], def_encodings[i]),
cbor_int(imins[i_64], def_encodings[i]),
// nint
cbor_int(-1 - umins[i_64], def_encodings[i]),
// u64 max const
cbor_int(u64::MAX as i128, Sz::Eight),
// i64 min const
cbor_int(i64::MIN as i128, Sz::Eight),
vec![BREAK],
].into_iter().flatten().clone().collect::<Vec<u8>>();
let irregular_min = SignedInts::from_bytes(irregular_bytes_min.clone()).unwrap();
assert_eq!(irregular_bytes_min, irregular_min.to_bytes());
let irregular_bytes_max = vec![
arr_sz(11, def_encodings[i]),
// uints
cbor_int(umaxs[i_8], def_encodings[i]),
cbor_int(umaxs[i_16], def_encodings[i]),
cbor_int(umaxs[i_32], def_encodings[i]),
cbor_int(umaxs[i_64], def_encodings[i]),
// ints
cbor_int(imaxs[i_8], def_encodings[i]),
cbor_int(imaxs[i_16], def_encodings[i]),
cbor_int(imaxs[i_32], def_encodings[i]),
cbor_int(imaxs[i_64], def_encodings[i]),
// nint
cbor_int(-1 - umaxs[i_64], def_encodings[i]),
// u64 max const
cbor_int(u64::MAX as i128, Sz::Eight),
// i64 min const
cbor_int(i64::MIN as i128, Sz::Eight),
].into_iter().flatten().clone().collect::<Vec<u8>>();
let irregular_max = SignedInts::from_bytes(irregular_bytes_max.clone()).unwrap();
assert_eq!(irregular_bytes_max, irregular_max.to_bytes());
}
}
}