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
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pub use len::*;
pub use result::Result;
pub use se::Serialize;
pub use types::*;
pub use value::{ObjectKey, Value};
pub use value::Value;

const MAX_INLINE_ENCODING: u64 = 23;

Expand Down
132 changes: 64 additions & 68 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
//! This is why all the objects here are marked as deprecated

use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use alloc::format;
use alloc::string::String;
use alloc::vec::Vec;
#[cfg(test)]
Expand All @@ -22,53 +20,13 @@ use quickcheck::{Arbitrary, Gen};

use core::convert::TryFrom;
use de::*;
#[cfg(test)]
use error::Error;
use len::Len;
use result::Result;
use se::*;
use types::{Special, SpecialValue, Type};

/// CBOR Object key, represents the possible supported values for
/// a CBOR key in a CBOR Map.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum ObjectKey {
Integer(u64),
Bytes(Vec<u8>),
Text(String),
}
impl ObjectKey {
/// convert the given `ObjectKey` into a CBOR [`Value`](./struct.Value.html)
pub fn value(self) -> Value {
match self {
ObjectKey::Integer(v) => Value::U64(v),
ObjectKey::Bytes(v) => Value::Bytes(v),
ObjectKey::Text(v) => Value::Text(v),
}
}
}
impl Serialize for ObjectKey {
fn serialize<'se>(&self, serializer: &'se mut Serializer) -> Result<&'se mut Serializer> {
match self {
ObjectKey::Integer(ref v) => serializer.write_unsigned_integer(*v),
ObjectKey::Bytes(ref v) => serializer.write_bytes(v),
ObjectKey::Text(ref v) => serializer.write_text(v),
}
}
}
impl Deserialize for ObjectKey {
fn deserialize(raw: &mut Deserializer) -> Result<Self> {
match raw.cbor_type()? {
Type::UnsignedInteger => Ok(ObjectKey::Integer(raw.unsigned_integer()?)),
Type::Bytes => Ok(ObjectKey::Bytes(raw.bytes()?)),
Type::Text => Ok(ObjectKey::Text(raw.text()?)),
t => Err(Error::CustomError(format!(
"Type `{:?}' is not a support type for CBOR Map's key",
t
))),
}
}
}

/// All possible CBOR supported values.
///
/// We advise not to use these objects as an intermediary representation before
Expand All @@ -83,8 +41,12 @@ pub enum Value {
Text(String),
Array(Vec<Value>),
IArray(Vec<Value>),
Object(BTreeMap<ObjectKey, Value>),
IObject(BTreeMap<ObjectKey, Value>),
/// maps are key-order-preserving pairs of arbitrary `Value`s: RFC 8949
/// §3.1 allows any type as a map key, and §5.6 leaves duplicate-key
/// handling to the protocol, so the decoder passes every entry through
/// in wire order rather than deduplicating or sorting
Object(Vec<(Value, Value)>),
IObject(Vec<(Value, Value)>),
Tag(u64, Box<Value>),
/// holds [`SpecialValue`], not [`Special`]:
/// Break is a wire-level terminator, not a data item, so a `Value` cannot contain one
Expand Down Expand Up @@ -117,15 +79,15 @@ impl Serialize for Value {
}
Value::Object(ref v) => {
serializer.write_map(Len::Len(v.len() as u64))?;
for element in v {
serializer.serialize(element.0)?.serialize(element.1)?;
for (key, value) in v {
serializer.serialize(key)?.serialize(value)?;
}
Ok(serializer)
}
Value::IObject(ref v) => {
serializer.write_map(Len::Indefinite)?;
for element in v {
serializer.serialize(element.0)?.serialize(element.1)?;
for (key, value) in v {
serializer.serialize(key)?.serialize(value)?;
}
serializer.write_special(Special::Break)
}
Expand Down Expand Up @@ -161,21 +123,21 @@ impl Deserialize for Value {
}
Type::Map => {
let len = raw.map()?;
let mut vec = BTreeMap::new();
let mut vec = Vec::new();
match len {
Len::Indefinite => {
while raw.cbor_type()? != Type::Special || !raw.special_break()? {
let k = Deserialize::deserialize(raw)?;
let v = Deserialize::deserialize(raw)?;
vec.insert(k, v);
vec.push((k, v));
}
Ok(Value::IObject(vec))
}
Len::Len(len) => {
for _ in 0..len {
let k = Deserialize::deserialize(raw)?;
let v = Deserialize::deserialize(raw)?;
vec.insert(k, v);
vec.push((k, v));
}
Ok(Value::Object(vec))
}
Expand All @@ -193,18 +155,6 @@ impl Deserialize for Value {
}
}

#[cfg(test)]
impl Arbitrary for ObjectKey {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
match u8::arbitrary(g) % 3 {
0 => ObjectKey::Integer(Arbitrary::arbitrary(g)),
1 => ObjectKey::Bytes(Arbitrary::arbitrary(g)),
2 => ObjectKey::Text(Arbitrary::arbitrary(g)),
_ => unreachable!(),
}
}
}

// canonical Value integers: non-negative integers are U64 (major type 0),
// so generated I64 must be negative or the round-trip property would
// compare I64(n) against the U64(n) it decodes to
Expand Down Expand Up @@ -261,7 +211,7 @@ fn arbitrary_value_indefinite<G: Gen>(counter: usize, g: &mut G) -> Value {
Value::Object(
repeat_with(|| {
(
ObjectKey::arbitrary(g),
arbitrary_value_indefinite(counter - 1, g),
arbitrary_value_indefinite(counter - 1, g),
)
})
Expand All @@ -274,7 +224,7 @@ fn arbitrary_value_indefinite<G: Gen>(counter: usize, g: &mut G) -> Value {
Value::IObject(
repeat_with(|| {
(
ObjectKey::arbitrary(g),
arbitrary_value_indefinite(counter - 1, g),
arbitrary_value_indefinite(counter - 1, g),
)
})
Expand Down Expand Up @@ -345,13 +295,13 @@ mod test {

#[test]
fn text_invalid_utf8_rejected() {
// regression guard: Value/ObjectKey text decoding must stay strict
// regression guard: Value text decoding must stay strict
// even if text_sz() internals change
let mut raw = Deserializer::from(vec![0x62, 0xff, 0xfe]);
let decoded: Result<Value> = Deserialize::deserialize(&mut raw);
assert!(matches!(decoded, Err(Error::InvalidTextError(_))));

// map with an invalid-UTF-8 text key (exercises ObjectKey)
// map with an invalid-UTF-8 text key (exercises key decoding)
let mut raw = Deserializer::from(vec![0xa1, 0x62, 0xff, 0xfe, 0x01]);
let decoded: Result<Value> = Deserialize::deserialize(&mut raw);
assert!(matches!(decoded, Err(Error::InvalidTextError(_))));
Expand Down Expand Up @@ -403,6 +353,52 @@ mod test {
);
}

// RFC 8949 §3.1 allows any type as a map key
#[test]
fn map_with_arbitrary_key_types() {
// a1 20 01 = {-1: 1} (e.g. COSE negative integer labels)
let mut raw = Deserializer::from(vec![0xa1, 0x20, 0x01]);
let decoded: Value = raw.deserialize().unwrap();
assert_eq!(
decoded,
Value::Object(vec![(Value::I64(-1), Value::U64(1))])
);

// a1 81 01 02 = {[1]: 2}, a container as key
let mut raw = Deserializer::from(vec![0xa1, 0x81, 0x01, 0x02]);
let decoded: Value = raw.deserialize().unwrap();
assert_eq!(
decoded,
Value::Object(vec![(Value::Array(vec![Value::U64(1)]), Value::U64(2))])
);

assert!(test_encode_decode(&decoded).unwrap());
}

// RFC 8949 §5.6: duplicate-key handling belongs to the protocol, so the
// decoder passes all entries through; wire order must survive re-encoding
#[test]
fn map_preserves_duplicate_keys_and_order() {
// a3 02 02 01 01 02 03 = {2: 2, 1: 1, 2: 3}
let mut raw = Deserializer::from(vec![0xa3, 0x02, 0x02, 0x01, 0x01, 0x02, 0x03]);
let decoded: Value = raw.deserialize().unwrap();
assert_eq!(
decoded,
Value::Object(vec![
(Value::U64(2), Value::U64(2)),
(Value::U64(1), Value::U64(1)),
(Value::U64(2), Value::U64(3)),
])
);

let mut se = Serializer::new_vec();
decoded.serialize(&mut se).unwrap();
assert_eq!(
se.finalize(),
vec![0xa3, 0x02, 0x02, 0x01, 0x01, 0x02, 0x03]
);
}

quickcheck! {
fn property_encode_decode(value: Value) -> bool {
test_encode_decode(&value).unwrap()
Expand Down
46 changes: 26 additions & 20 deletions tests/indefinite_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@

extern crate cbor_event;
use cbor_event::de::Deserializer;
use cbor_event::{ObjectKey, SpecialValue, Value};
use cbor_event::{SpecialValue, Value};
use std::collections::BTreeMap;

fn de_value(bytes: &[u8]) -> cbor_event::Result<Value> {
Deserializer::from(bytes.to_vec()).deserialize::<Value>()
}

fn text_key(s: &str) -> ObjectKey {
ObjectKey::Text(s.to_owned())
fn text_key(s: &str) -> Value {
Value::Text(s.to_owned())
}

// class 1 (Break as first item): 9fff = [_ ], RFC 8949
Expand All @@ -45,10 +45,7 @@ fn value_empty_indefinite_array() {
// class 1, map position: bfff = {_ }
#[test]
fn value_empty_indefinite_map() {
assert_eq!(
de_value(&[0xbf, 0xff]).unwrap(),
Value::IObject(BTreeMap::new())
);
assert_eq!(de_value(&[0xbf, 0xff]).unwrap(), Value::IObject(vec![]));
}

// class 2: 9ff4ff = [_ false] -- used to panic on the Break assertion
Expand All @@ -63,9 +60,11 @@ fn value_indefinite_array_with_bool() {
// classes 2+3 in map position: bf6346756ef563416d7421ff = {_ "Fun": true, "Amt": -2}, RFC 8949
#[test]
fn value_indefinite_map_rfc_vector() {
let mut expected = BTreeMap::new();
expected.insert(text_key("Fun"), Value::Special(SpecialValue::Bool(true)));
expected.insert(text_key("Amt"), Value::I64(-2));
// entries appear in wire order
let expected = vec![
(text_key("Fun"), Value::Special(SpecialValue::Bool(true))),
(text_key("Amt"), Value::I64(-2)),
];
assert_eq!(
de_value(&[0xbf, 0x63, 0x46, 0x75, 0x6e, 0xf5, 0x63, 0x41, 0x6d, 0x74, 0x21, 0xff])
.unwrap(),
Expand All @@ -91,23 +90,30 @@ fn value_nested_mixed_arrays_rfc_vector() {
// bf61610161629f0203ffff = {_ "a": 1, "b": [_ 2, 3]}, RFC 8949
#[test]
fn value_indefinite_map_nested_rfc_vector() {
let mut expected = BTreeMap::new();
expected.insert(text_key("a"), Value::U64(1));
expected.insert(
text_key("b"),
Value::IArray(vec![Value::U64(2), Value::U64(3)]),
);
let expected = vec![
(text_key("a"), Value::U64(1)),
(
text_key("b"),
Value::IArray(vec![Value::U64(2), Value::U64(3)]),
),
];
assert_eq!(
de_value(&[0xbf, 0x61, 0x61, 0x01, 0x61, 0x62, 0x9f, 0x02, 0x03, 0xff, 0xff]).unwrap(),
Value::IObject(expected)
);
}

// bff401ff = {_ false: 1} -- valid CBOR, but bool is not representable as an
// ObjectKey in this crate: must be an error, never a panic
// bff401ff = {_ false: 1} -- RFC 8949 §3.1 allows any type as a map key;
// used to error because map keys were the restricted ObjectKey enum
#[test]
fn value_indefinite_map_with_special_key_errors() {
assert!(de_value(&[0xbf, 0xf4, 0x01, 0xff]).is_err());
fn value_indefinite_map_with_special_key() {
assert_eq!(
de_value(&[0xbf, 0xf4, 0x01, 0xff]).unwrap(),
Value::IObject(vec![(
Value::Special(SpecialValue::Bool(false)),
Value::U64(1)
)])
);
}

// class 4: 9ff4 = [_ false <EOF, Break and any further elements missing
Expand Down
Loading