cbor: support tagged values
This commit is contained in:
committed by
kaczmarczyck
parent
3aca5fbc74
commit
fbe68b55cd
@@ -336,6 +336,14 @@ macro_rules! cbor_bytes {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a CBOR Value of type Tag with the given tag and object.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! cbor_tagged {
|
||||||
|
( $t:expr, $x: expr ) => {
|
||||||
|
$crate::values::Value::Tag($t, ::alloc::boxed::Box::new($x))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a CBOR Value of type Byte String with the given byte string literal.
|
/// Creates a CBOR Value of type Byte String with the given byte string literal.
|
||||||
///
|
///
|
||||||
/// Example usage:
|
/// Example usage:
|
||||||
|
|||||||
@@ -15,7 +15,9 @@
|
|||||||
//! Functionality for deserializing CBOR data into values.
|
//! Functionality for deserializing CBOR data into values.
|
||||||
|
|
||||||
use super::values::{Constants, SimpleValue, Value};
|
use super::values::{Constants, SimpleValue, Value};
|
||||||
use crate::{cbor_array_vec, cbor_bytes_lit, cbor_map_collection, cbor_text, cbor_unsigned};
|
use crate::{
|
||||||
|
cbor_array_vec, cbor_bytes_lit, cbor_map_collection, cbor_tagged, cbor_text, cbor_unsigned,
|
||||||
|
};
|
||||||
use alloc::str;
|
use alloc::str;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
@@ -80,6 +82,7 @@ impl<'a> Reader<'a> {
|
|||||||
3 => self.read_text_string_content(size_value),
|
3 => self.read_text_string_content(size_value),
|
||||||
4 => self.read_array_content(size_value, remaining_depth),
|
4 => self.read_array_content(size_value, remaining_depth),
|
||||||
5 => self.read_map_content(size_value, remaining_depth),
|
5 => self.read_map_content(size_value, remaining_depth),
|
||||||
|
6 => self.read_tagged_content(size_value, remaining_depth),
|
||||||
7 => self.decode_to_simple_value(size_value, additional_info),
|
7 => self.decode_to_simple_value(size_value, additional_info),
|
||||||
_ => Err(DecoderError::UnsupportedMajorType),
|
_ => Err(DecoderError::UnsupportedMajorType),
|
||||||
}
|
}
|
||||||
@@ -187,6 +190,15 @@ impl<'a> Reader<'a> {
|
|||||||
Ok(cbor_map_collection!(value_map))
|
Ok(cbor_map_collection!(value_map))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_tagged_content(
|
||||||
|
&mut self,
|
||||||
|
tag_value: u64,
|
||||||
|
remaining_depth: i8,
|
||||||
|
) -> Result<Value, DecoderError> {
|
||||||
|
let inner_value = self.decode_complete_data_item(remaining_depth - 1)?;
|
||||||
|
Ok(cbor_tagged!(tag_value, inner_value))
|
||||||
|
}
|
||||||
|
|
||||||
fn decode_to_simple_value(
|
fn decode_to_simple_value(
|
||||||
&self,
|
&self,
|
||||||
size_value: u64,
|
size_value: u64,
|
||||||
@@ -546,6 +558,35 @@ mod test {
|
|||||||
assert_eq!(read(&test_cbor), Err(DecoderError::ExtranousData));
|
assert_eq!(read(&test_cbor), Err(DecoderError::ExtranousData));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_read_tagged() {
|
||||||
|
let cases = vec![
|
||||||
|
(cbor_tagged!(6, cbor_int!(0x42)), vec![0xc6, 0x18, 0x42]),
|
||||||
|
(cbor_tagged!(1, cbor_true!()), vec![0xc1, 0xf5]),
|
||||||
|
(
|
||||||
|
cbor_tagged!(
|
||||||
|
1000,
|
||||||
|
cbor_map! {
|
||||||
|
"a" => 1,
|
||||||
|
"b" => cbor_array![2, 3],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
vec![
|
||||||
|
0xd9, 0x03, 0xe8, 0xa2, // map of 2 pairs
|
||||||
|
0x61, 0x61, // "a"
|
||||||
|
0x01, 0x61, 0x62, // "b"
|
||||||
|
0x82, // array with 2 elements
|
||||||
|
0x02, 0x03,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
];
|
||||||
|
for (value, mut cbor) in cases {
|
||||||
|
assert_eq!(read(&cbor), Ok(value));
|
||||||
|
cbor.push(0x01);
|
||||||
|
assert_eq!(read(&cbor), Err(DecoderError::ExtranousData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_read_integer_out_of_range() {
|
fn test_read_integer_out_of_range() {
|
||||||
let cases = vec![
|
let cases = vec![
|
||||||
@@ -779,20 +820,4 @@ mod test {
|
|||||||
assert_eq!(read(&cbor), Err(DecoderError::IncompleteCborData));
|
assert_eq!(read(&cbor), Err(DecoderError::IncompleteCborData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_read_unsupported_major_type() {
|
|
||||||
let cases = vec![
|
|
||||||
vec![0xC0],
|
|
||||||
vec![0xD8, 0xFF],
|
|
||||||
// multi-dimensional array example using tags
|
|
||||||
vec![
|
|
||||||
0x82, 0x82, 0x02, 0x03, 0xd8, 0x41, 0x4a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
|
|
||||||
0x03, 0x00, 0x04, 0x00, 0x05,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
for cbor in cases {
|
|
||||||
assert_eq!(read(&cbor), Err(DecoderError::UnsupportedMajorType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
//! Types for expressing CBOR values.
|
//! Types for expressing CBOR values.
|
||||||
|
|
||||||
use super::writer::write;
|
use super::writer::write;
|
||||||
|
use alloc::boxed::Box;
|
||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
@@ -34,7 +35,8 @@ pub enum Value {
|
|||||||
Array(Vec<Value>),
|
Array(Vec<Value>),
|
||||||
/// Map of key-value pairs.
|
/// Map of key-value pairs.
|
||||||
Map(Vec<(Value, Value)>),
|
Map(Vec<(Value, Value)>),
|
||||||
// TAG is omitted
|
/// Tagged value.
|
||||||
|
Tag(u64, Box<Value>),
|
||||||
/// Simple value.
|
/// Simple value.
|
||||||
Simple(SimpleValue),
|
Simple(SimpleValue),
|
||||||
}
|
}
|
||||||
@@ -100,6 +102,7 @@ impl Value {
|
|||||||
Value::TextString(_) => 3,
|
Value::TextString(_) => 3,
|
||||||
Value::Array(_) => 4,
|
Value::Array(_) => 4,
|
||||||
Value::Map(_) => 5,
|
Value::Map(_) => 5,
|
||||||
|
Value::Tag(_, _) => 6,
|
||||||
Value::Simple(_) => 7,
|
Value::Simple(_) => 7,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,7 +111,7 @@ impl Value {
|
|||||||
impl Ord for Value {
|
impl Ord for Value {
|
||||||
fn cmp(&self, other: &Value) -> Ordering {
|
fn cmp(&self, other: &Value) -> Ordering {
|
||||||
use super::values::Value::{
|
use super::values::Value::{
|
||||||
Array, ByteString, Map, Negative, Simple, TextString, Unsigned,
|
Array, ByteString, Map, Negative, Simple, Tag, TextString, Unsigned,
|
||||||
};
|
};
|
||||||
let self_type_value = self.type_label();
|
let self_type_value = self.type_label();
|
||||||
let other_type_value = other.type_label();
|
let other_type_value = other.type_label();
|
||||||
@@ -122,6 +125,7 @@ impl Ord for Value {
|
|||||||
(TextString(t1), TextString(t2)) => t1.len().cmp(&t2.len()).then(t1.cmp(t2)),
|
(TextString(t1), TextString(t2)) => t1.len().cmp(&t2.len()).then(t1.cmp(t2)),
|
||||||
(Array(a1), Array(a2)) if a1.len() != a2.len() => a1.len().cmp(&a2.len()),
|
(Array(a1), Array(a2)) if a1.len() != a2.len() => a1.len().cmp(&a2.len()),
|
||||||
(Map(m1), Map(m2)) if m1.len() != m2.len() => m1.len().cmp(&m2.len()),
|
(Map(m1), Map(m2)) if m1.len() != m2.len() => m1.len().cmp(&m2.len()),
|
||||||
|
(Tag(t1, v1), Tag(t2, v2)) => t1.cmp(t2).then(v1.cmp(v2)),
|
||||||
(Simple(s1), Simple(s2)) => s1.cmp(s2),
|
(Simple(s1), Simple(s2)) => s1.cmp(s2),
|
||||||
(v1, v2) => {
|
(v1, v2) => {
|
||||||
// This case could handle all of the above as well. Checking individually is faster.
|
// This case could handle all of the above as well. Checking individually is faster.
|
||||||
@@ -258,7 +262,7 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{cbor_array, cbor_bool, cbor_bytes, cbor_int, cbor_map, cbor_text};
|
use crate::{cbor_array, cbor_bool, cbor_bytes, cbor_int, cbor_map, cbor_tagged, cbor_text};
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -315,12 +319,17 @@ mod test {
|
|||||||
assert!(cbor_int!(-1) < cbor_text!("s"));
|
assert!(cbor_int!(-1) < cbor_text!("s"));
|
||||||
assert!(cbor_int!(-1) < cbor_array![]);
|
assert!(cbor_int!(-1) < cbor_array![]);
|
||||||
assert!(cbor_int!(-1) < cbor_map! {});
|
assert!(cbor_int!(-1) < cbor_map! {});
|
||||||
|
assert!(cbor_int!(-1) < cbor_tagged!(1, cbor_text!("s")));
|
||||||
assert!(cbor_int!(-1) < cbor_bool!(false));
|
assert!(cbor_int!(-1) < cbor_bool!(false));
|
||||||
assert!(cbor_bytes!(vec![0x00]) < cbor_array![]);
|
assert!(cbor_bytes!(vec![0x00]) < cbor_array![]);
|
||||||
assert!(cbor_bytes!(vec![0x00]) < cbor_map! {});
|
assert!(cbor_bytes!(vec![0x00]) < cbor_map! {});
|
||||||
assert!(cbor_bytes!(vec![0x00]) < cbor_bool!(false));
|
assert!(cbor_bytes!(vec![0x00]) < cbor_bool!(false));
|
||||||
|
assert!(cbor_bytes!(vec![0x00]) < cbor_tagged!(1, cbor_text!("s")));
|
||||||
assert!(cbor_text!("s") < cbor_map! {});
|
assert!(cbor_text!("s") < cbor_map! {});
|
||||||
assert!(cbor_text!("s") < cbor_bool!(false));
|
assert!(cbor_text!("s") < cbor_bool!(false));
|
||||||
|
assert!(cbor_text!("s") < cbor_tagged!(1, cbor_text!("s")));
|
||||||
assert!(cbor_array![] < cbor_bool!(false));
|
assert!(cbor_array![] < cbor_bool!(false));
|
||||||
|
assert!(cbor_tagged!(1, cbor_text!("s")) < cbor_tagged!(2, cbor_int!(0)));
|
||||||
|
assert!(cbor_tagged!(1, cbor_text!("s")) < cbor_bool!(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,12 @@ impl<'a> Writer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Value::Tag(tag, inner_value) => {
|
||||||
|
self.start_item(type_label, tag);
|
||||||
|
if !self.encode_cbor(*inner_value, remaining_depth - 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Value::Simple(simple_value) => self.start_item(type_label, simple_value as u64),
|
Value::Simple(simple_value) => self.start_item(type_label, simple_value as u64),
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
@@ -103,7 +109,7 @@ mod test {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
cbor_array, cbor_array_vec, cbor_bytes, cbor_false, cbor_int, cbor_map, cbor_null,
|
cbor_array, cbor_array_vec, cbor_bytes, cbor_false, cbor_int, cbor_map, cbor_null,
|
||||||
cbor_text, cbor_true, cbor_undefined,
|
cbor_tagged, cbor_text, cbor_true, cbor_undefined,
|
||||||
};
|
};
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
|
|
||||||
@@ -396,6 +402,33 @@ mod test {
|
|||||||
assert_eq!(write_return(value_map), Some(expected_cbor));
|
assert_eq!(write_return(value_map), Some(expected_cbor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_write_tagged() {
|
||||||
|
let cases = vec![
|
||||||
|
(cbor_tagged!(6, cbor_int!(0x42)), vec![0xc6, 0x18, 0x42]),
|
||||||
|
(cbor_tagged!(1, cbor_true!()), vec![0xc1, 0xf5]),
|
||||||
|
(
|
||||||
|
cbor_tagged!(
|
||||||
|
1000,
|
||||||
|
cbor_map! {
|
||||||
|
"a" => 1,
|
||||||
|
"b" => cbor_array![2, 3],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
vec![
|
||||||
|
0xd9, 0x03, 0xe8, 0xa2, // map of 2 pairs
|
||||||
|
0x61, 0x61, // "a"
|
||||||
|
0x01, 0x61, 0x62, // "b"
|
||||||
|
0x82, // array with 2 elements
|
||||||
|
0x02, 0x03,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
];
|
||||||
|
for (value, correct_cbor) in cases {
|
||||||
|
assert_eq!(write_return(value), Some(correct_cbor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_write_simple() {
|
fn test_write_simple() {
|
||||||
let cases = vec![
|
let cases = vec![
|
||||||
|
|||||||
Reference in New Issue
Block a user