CBOR API changes (#639)
* adds extract_* functions to CBOR library * hides Value implementation details * CBOR API fixes * README adapted to API changes
This commit is contained in:
@@ -13,41 +13,26 @@ This crate implements Concise Binary Object Representation (CBOR) from [RFC
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
// Build a CBOR object with various different types included. Note that this
|
||||
// Build a CBOR object with the crate's convenience macros. Note that this
|
||||
// object is not built in canonical order.
|
||||
let manual_object = Value::Map(vec![
|
||||
(
|
||||
Value::Unsigned(1),
|
||||
Value::Array(vec![Value::Unsigned(2), Value::Unsigned(3)]),
|
||||
),
|
||||
(
|
||||
Value::TextString("tstr".to_owned()),
|
||||
Value::ByteString(vec![1, 2, 3]),
|
||||
),
|
||||
(Value::Negative(-2), Value::Simple(SimpleValue::NullValue)),
|
||||
(Value::Unsigned(3), Value::Simple(SimpleValue::TrueValue)),
|
||||
]);
|
||||
|
||||
// Build the same object using the crate's convenience macros.
|
||||
let macro_object = cbor_map! {
|
||||
let map_object = cbor_map! {
|
||||
1 => cbor_array![2, 3],
|
||||
"tstr" => cbor_bytes!(vec![1, 2, 3]),
|
||||
-2 => cbor_null!(),
|
||||
3 => cbor_true!(),
|
||||
};
|
||||
|
||||
assert_eq!(manual_object, macro_object);
|
||||
println!("Object {:?}", manual_object);
|
||||
println!("Object {:?}", map_object);
|
||||
|
||||
// Serialize to bytes.
|
||||
let mut manual_data = vec![];
|
||||
sk_cbor::writer::write(manual_object, &mut manual_data);
|
||||
let hex_manual_data = hexify(&manual_data);
|
||||
let mut map_data = vec![];
|
||||
sk_cbor::writer::write(map_object, &mut map_data).unwrap();
|
||||
let hex_map_data = hex::encode(&map_data);
|
||||
|
||||
// Serialized version is in canonical order.
|
||||
println!("Serializes to {}", hex_manual_data);
|
||||
println!("Serializes to {}", hex_map_data);
|
||||
assert_eq!(
|
||||
hex_manual_data,
|
||||
hex_map_data,
|
||||
concat!(
|
||||
"a4", // 4-map
|
||||
"01", // int(1) =>
|
||||
@@ -63,7 +48,7 @@ fn main() {
|
||||
|
||||
// Convert back to an object. This is different than the original object,
|
||||
// because the map is now in canonical order.
|
||||
let recovered_object = sk_cbor::reader::read(&manual_data).unwrap();
|
||||
let recovered_object = sk_cbor::reader::read(&map_data).unwrap();
|
||||
println!("Deserializes to {:?}", recovered_object);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use sk_cbor::values::{SimpleValue, Value};
|
||||
use sk_cbor::values::Value;
|
||||
use sk_cbor::{cbor_array, cbor_bytes, cbor_map, cbor_null, cbor_true};
|
||||
|
||||
fn hexify(data: &[u8]) -> String {
|
||||
@@ -32,17 +32,14 @@ fn hexify(data: &[u8]) -> String {
|
||||
fn main() {
|
||||
// Build a CBOR object with various different types included. Note that this
|
||||
// object is not built in canonical order.
|
||||
let manual_object = Value::Map(vec![
|
||||
let manual_object = Value::map(vec![
|
||||
(
|
||||
Value::Unsigned(1),
|
||||
Value::Array(vec![Value::Unsigned(2), Value::Unsigned(3)]),
|
||||
Value::from(1),
|
||||
Value::array(vec![Value::from(2), Value::from(3)]),
|
||||
),
|
||||
(
|
||||
Value::TextString("tstr".to_owned()),
|
||||
Value::ByteString(vec![1, 2, 3]),
|
||||
),
|
||||
(Value::Negative(-2), Value::Simple(SimpleValue::NullValue)),
|
||||
(Value::Unsigned(3), Value::Simple(SimpleValue::TrueValue)),
|
||||
(Value::from("tstr".to_owned()), Value::from(vec![1, 2, 3])),
|
||||
(Value::from(-2), Value::null_value()),
|
||||
(Value::from(3), Value::bool_value(true)),
|
||||
]);
|
||||
|
||||
// Build the same object using the crate's convenience macros.
|
||||
|
||||
@@ -22,5 +22,5 @@ pub mod values;
|
||||
pub mod writer;
|
||||
|
||||
pub use self::reader::read;
|
||||
pub use self::values::{SimpleValue, Value};
|
||||
pub use self::values::Value;
|
||||
pub use self::writer::write;
|
||||
|
||||
@@ -139,9 +139,12 @@ macro_rules! assert_sorted_keys {
|
||||
///
|
||||
/// Keys and values are expressions and converted into CBOR Keys and Values.
|
||||
/// The syntax for these pairs is `key_expression => value_expression,`.
|
||||
/// Duplicate keys will lead to invalid CBOR, i.e. writing these values fails.
|
||||
/// Keys do not have to be sorted.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// You may not call this function with identical keys in its argument.
|
||||
///
|
||||
/// Example usage:
|
||||
///
|
||||
/// ```rust
|
||||
@@ -168,7 +171,7 @@ macro_rules! cbor_map {
|
||||
$(
|
||||
_map.push(($key.into_cbor_value(), $value.into_cbor_value()));
|
||||
)*
|
||||
$crate::values::Value::Map(_map)
|
||||
$crate::values::Value::map(_map)
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -214,7 +217,7 @@ macro_rules! cbor_map_options {
|
||||
}
|
||||
}
|
||||
)*
|
||||
$crate::values::Value::Map(_map)
|
||||
$crate::values::Value::map(_map)
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -223,7 +226,7 @@ macro_rules! cbor_map_options {
|
||||
#[macro_export]
|
||||
macro_rules! cbor_map_collection {
|
||||
( $tree:expr ) => {{
|
||||
$crate::values::Value::from($tree)
|
||||
$crate::values::Value::map($tree)
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -250,7 +253,7 @@ macro_rules! cbor_array {
|
||||
// The import is unused if the list is empty.
|
||||
#[allow(unused_imports)]
|
||||
use $crate::values::IntoCborValue;
|
||||
$crate::values::Value::Array(vec![ $( $value.into_cbor_value(), )* ])
|
||||
$crate::values::Value::array(vec![ $( $value.into_cbor_value(), )* ])
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -260,7 +263,7 @@ macro_rules! cbor_array {
|
||||
macro_rules! cbor_array_vec {
|
||||
( $vec:expr ) => {{
|
||||
use $crate::values::IntoCborValue;
|
||||
$crate::values::Value::Array($vec.into_iter().map(|x| x.into_cbor_value()).collect())
|
||||
$crate::values::Value::array($vec.into_iter().map(|x| x.into_cbor_value()).collect())
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -268,7 +271,7 @@ macro_rules! cbor_array_vec {
|
||||
#[macro_export]
|
||||
macro_rules! cbor_true {
|
||||
( ) => {
|
||||
$crate::values::Value::Simple($crate::values::SimpleValue::TrueValue)
|
||||
$crate::values::Value::bool_value(true)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -276,7 +279,7 @@ macro_rules! cbor_true {
|
||||
#[macro_export]
|
||||
macro_rules! cbor_false {
|
||||
( ) => {
|
||||
$crate::values::Value::Simple($crate::values::SimpleValue::FalseValue)
|
||||
$crate::values::Value::bool_value(false)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -284,7 +287,7 @@ macro_rules! cbor_false {
|
||||
#[macro_export]
|
||||
macro_rules! cbor_null {
|
||||
( ) => {
|
||||
$crate::values::Value::Simple($crate::values::SimpleValue::NullValue)
|
||||
$crate::values::Value::null_value()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -292,7 +295,7 @@ macro_rules! cbor_null {
|
||||
#[macro_export]
|
||||
macro_rules! cbor_undefined {
|
||||
( ) => {
|
||||
$crate::values::Value::Simple($crate::values::SimpleValue::Undefined)
|
||||
$crate::values::Value::undefined()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -308,7 +311,7 @@ macro_rules! cbor_bool {
|
||||
#[macro_export]
|
||||
macro_rules! cbor_unsigned {
|
||||
( $x:expr ) => {
|
||||
$crate::values::Value::Unsigned($x)
|
||||
$crate::values::Value::unsigned($x as u64)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -316,7 +319,7 @@ macro_rules! cbor_unsigned {
|
||||
#[macro_export]
|
||||
macro_rules! cbor_int {
|
||||
( $x:expr ) => {
|
||||
$crate::values::Value::integer($x)
|
||||
$crate::values::Value::integer($x as i64)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -324,7 +327,7 @@ macro_rules! cbor_int {
|
||||
#[macro_export]
|
||||
macro_rules! cbor_text {
|
||||
( $x:expr ) => {
|
||||
$crate::values::Value::TextString($x.into())
|
||||
$crate::values::Value::text_string($x.into())
|
||||
};
|
||||
}
|
||||
|
||||
@@ -332,7 +335,7 @@ macro_rules! cbor_text {
|
||||
#[macro_export]
|
||||
macro_rules! cbor_bytes {
|
||||
( $x:expr ) => {
|
||||
$crate::values::Value::ByteString($x)
|
||||
$crate::values::Value::byte_string($x)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -340,7 +343,7 @@ macro_rules! cbor_bytes {
|
||||
#[macro_export]
|
||||
macro_rules! cbor_tagged {
|
||||
( $t:expr, $x: expr ) => {
|
||||
$crate::values::Value::Tag($t, ::alloc::boxed::Box::new($x))
|
||||
$crate::values::Value::tag($t, $x)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -362,41 +365,41 @@ macro_rules! cbor_bytes_lit {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::super::values::{SimpleValue, Value};
|
||||
use super::super::values::Value;
|
||||
use alloc::string::String;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[test]
|
||||
fn test_cbor_simple_values() {
|
||||
assert_eq!(cbor_true!(), Value::Simple(SimpleValue::TrueValue));
|
||||
assert_eq!(cbor_false!(), Value::Simple(SimpleValue::FalseValue));
|
||||
assert_eq!(cbor_null!(), Value::Simple(SimpleValue::NullValue));
|
||||
assert_eq!(cbor_undefined!(), Value::Simple(SimpleValue::Undefined));
|
||||
assert_eq!(cbor_true!(), Value::bool_value(true));
|
||||
assert_eq!(cbor_false!(), Value::bool_value(false));
|
||||
assert_eq!(cbor_null!(), Value::null_value());
|
||||
assert_eq!(cbor_undefined!(), Value::undefined());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_bool() {
|
||||
assert_eq!(cbor_bool!(true), Value::Simple(SimpleValue::TrueValue));
|
||||
assert_eq!(cbor_bool!(false), Value::Simple(SimpleValue::FalseValue));
|
||||
assert_eq!(cbor_bool!(true), Value::bool_value(true));
|
||||
assert_eq!(cbor_bool!(false), Value::bool_value(false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_int_unsigned() {
|
||||
assert_eq!(cbor_int!(0), Value::Unsigned(0));
|
||||
assert_eq!(cbor_int!(1), Value::Unsigned(1));
|
||||
assert_eq!(cbor_int!(123456), Value::Unsigned(123456));
|
||||
assert_eq!(cbor_int!(0), Value::from(0));
|
||||
assert_eq!(cbor_int!(1), Value::from(1));
|
||||
assert_eq!(cbor_int!(123456), Value::from(123456));
|
||||
assert_eq!(
|
||||
cbor_int!(core::i64::MAX),
|
||||
Value::Unsigned(core::i64::MAX as u64)
|
||||
Value::from(core::i64::MAX as u64)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_int_negative() {
|
||||
assert_eq!(cbor_int!(-1), Value::Negative(-1));
|
||||
assert_eq!(cbor_int!(-123456), Value::Negative(-123456));
|
||||
assert_eq!(cbor_int!(core::i64::MIN), Value::Negative(core::i64::MIN));
|
||||
assert_eq!(cbor_int!(-1), Value::from(-1));
|
||||
assert_eq!(cbor_int!(-123456), Value::from(-123456));
|
||||
assert_eq!(cbor_int!(core::i64::MIN), Value::from(core::i64::MIN));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -413,17 +416,17 @@ mod test {
|
||||
core::i64::MAX,
|
||||
core::u64::MAX,
|
||||
];
|
||||
let b = Value::Array(vec![
|
||||
Value::Negative(core::i64::MIN),
|
||||
Value::Negative(core::i32::MIN as i64),
|
||||
Value::Negative(-123456),
|
||||
Value::Negative(-1),
|
||||
Value::Unsigned(0),
|
||||
Value::Unsigned(1),
|
||||
Value::Unsigned(123456),
|
||||
Value::Unsigned(core::i32::MAX as u64),
|
||||
Value::Unsigned(core::i64::MAX as u64),
|
||||
Value::Unsigned(core::u64::MAX),
|
||||
let b = Value::array(vec![
|
||||
Value::from(core::i64::MIN),
|
||||
Value::from(core::i32::MIN as i64),
|
||||
Value::from(-123456),
|
||||
Value::from(-1),
|
||||
Value::from(0),
|
||||
Value::from(1),
|
||||
Value::from(123456),
|
||||
Value::from(core::i32::MAX as u64),
|
||||
Value::from(core::i64::MAX as u64),
|
||||
Value::from(core::u64::MAX),
|
||||
]);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
@@ -442,22 +445,17 @@ mod test {
|
||||
cbor_map! {},
|
||||
cbor_map! {2 => 3},
|
||||
];
|
||||
let b = Value::Array(vec![
|
||||
Value::Negative(-123),
|
||||
Value::Unsigned(456),
|
||||
Value::Simple(SimpleValue::TrueValue),
|
||||
Value::Simple(SimpleValue::NullValue),
|
||||
Value::TextString(String::from("foo")),
|
||||
Value::ByteString(b"bar".to_vec()),
|
||||
Value::Array(Vec::new()),
|
||||
Value::Array(vec![Value::Unsigned(0), Value::Unsigned(1)]),
|
||||
Value::Map(Vec::new()),
|
||||
Value::Map(
|
||||
[(Value::Unsigned(2), Value::Unsigned(3))]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
),
|
||||
let b = Value::array(vec![
|
||||
Value::from(-123),
|
||||
Value::from(456),
|
||||
Value::bool_value(true),
|
||||
Value::null_value(),
|
||||
Value::from(String::from("foo")),
|
||||
Value::from(b"bar".to_vec()),
|
||||
Value::array(Vec::new()),
|
||||
Value::array(vec![Value::from(0), Value::from(1)]),
|
||||
Value::map(Vec::new()),
|
||||
Value::map([(Value::from(2), Value::from(3))].iter().cloned().collect()),
|
||||
]);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
@@ -465,18 +463,18 @@ mod test {
|
||||
#[test]
|
||||
fn test_cbor_array_vec_empty() {
|
||||
let a = cbor_array_vec!(Vec::<bool>::new());
|
||||
let b = Value::Array(Vec::new());
|
||||
let b = Value::array(Vec::new());
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_array_vec_int() {
|
||||
let a = cbor_array_vec!(vec![1, 2, 3, 4]);
|
||||
let b = Value::Array(vec![
|
||||
Value::Unsigned(1),
|
||||
Value::Unsigned(2),
|
||||
Value::Unsigned(3),
|
||||
Value::Unsigned(4),
|
||||
let b = Value::array(vec![
|
||||
Value::from(1),
|
||||
Value::from(2),
|
||||
Value::from(3),
|
||||
Value::from(4),
|
||||
]);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
@@ -484,10 +482,10 @@ mod test {
|
||||
#[test]
|
||||
fn test_cbor_array_vec_text() {
|
||||
let a = cbor_array_vec!(vec!["a", "b", "c"]);
|
||||
let b = Value::Array(vec![
|
||||
Value::TextString(String::from("a")),
|
||||
Value::TextString(String::from("b")),
|
||||
Value::TextString(String::from("c")),
|
||||
let b = Value::array(vec![
|
||||
Value::from(String::from("a")),
|
||||
Value::from(String::from("b")),
|
||||
Value::from(String::from("c")),
|
||||
]);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
@@ -495,10 +493,10 @@ mod test {
|
||||
#[test]
|
||||
fn test_cbor_array_vec_bytes() {
|
||||
let a = cbor_array_vec!(vec![b"a", b"b", b"c"]);
|
||||
let b = Value::Array(vec![
|
||||
Value::ByteString(b"a".to_vec()),
|
||||
Value::ByteString(b"b".to_vec()),
|
||||
Value::ByteString(b"c".to_vec()),
|
||||
let b = Value::array(vec![
|
||||
Value::from(b"a".to_vec()),
|
||||
Value::from(b"b".to_vec()),
|
||||
Value::from(b"c".to_vec()),
|
||||
]);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
@@ -506,46 +504,35 @@ mod test {
|
||||
#[test]
|
||||
fn test_cbor_map() {
|
||||
let a = cbor_map! {
|
||||
-1 => -23,
|
||||
4 => 56,
|
||||
"foo" => true,
|
||||
b"bar" => cbor_null!(),
|
||||
5 => "foo",
|
||||
6 => b"bar",
|
||||
7 => cbor_array![],
|
||||
8 => cbor_array![0, 1],
|
||||
9 => cbor_map!{},
|
||||
10 => cbor_map!{2 => 3},
|
||||
-1 => -23,
|
||||
b"bar" => cbor_null!(),
|
||||
"foo" => true,
|
||||
};
|
||||
let b = Value::Map(
|
||||
let b = Value::map(
|
||||
[
|
||||
(Value::Negative(-1), Value::Negative(-23)),
|
||||
(Value::Unsigned(4), Value::Unsigned(56)),
|
||||
(Value::from(4), Value::from(56)),
|
||||
(Value::from(5), Value::from(String::from("foo"))),
|
||||
(Value::from(6), Value::from(b"bar".to_vec())),
|
||||
(Value::from(7), Value::array(Vec::new())),
|
||||
(
|
||||
Value::TextString(String::from("foo")),
|
||||
Value::Simple(SimpleValue::TrueValue),
|
||||
Value::from(8),
|
||||
Value::array(vec![Value::from(0), Value::from(1)]),
|
||||
),
|
||||
(Value::from(9), Value::map(Vec::new())),
|
||||
(
|
||||
Value::ByteString(b"bar".to_vec()),
|
||||
Value::Simple(SimpleValue::NullValue),
|
||||
),
|
||||
(Value::Unsigned(5), Value::TextString(String::from("foo"))),
|
||||
(Value::Unsigned(6), Value::ByteString(b"bar".to_vec())),
|
||||
(Value::Unsigned(7), Value::Array(Vec::new())),
|
||||
(
|
||||
Value::Unsigned(8),
|
||||
Value::Array(vec![Value::Unsigned(0), Value::Unsigned(1)]),
|
||||
),
|
||||
(Value::Unsigned(9), Value::Map(Vec::new())),
|
||||
(
|
||||
Value::Unsigned(10),
|
||||
Value::Map(
|
||||
[(Value::Unsigned(2), Value::Unsigned(3))]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
),
|
||||
Value::from(10),
|
||||
Value::map([(Value::from(2), Value::from(3))].iter().cloned().collect()),
|
||||
),
|
||||
(Value::from(-1), Value::from(-23)),
|
||||
(Value::from(b"bar".to_vec()), Value::null_value()),
|
||||
(Value::from(String::from("foo")), Value::bool_value(true)),
|
||||
]
|
||||
.iter()
|
||||
.cloned()
|
||||
@@ -557,54 +544,43 @@ mod test {
|
||||
#[test]
|
||||
fn test_cbor_map_options() {
|
||||
let a = cbor_map_options! {
|
||||
-1 => -23,
|
||||
4 => Some(56),
|
||||
11 => None::<String>,
|
||||
"foo" => true,
|
||||
12 => None::<&str>,
|
||||
b"bar" => Some(cbor_null!()),
|
||||
13 => None::<Vec<u8>>,
|
||||
5 => "foo",
|
||||
14 => None::<&[u8]>,
|
||||
6 => Some(b"bar" as &[u8]),
|
||||
15 => None::<bool>,
|
||||
7 => cbor_array![],
|
||||
16 => None::<i32>,
|
||||
8 => Some(cbor_array![0, 1]),
|
||||
17 => None::<i64>,
|
||||
9 => cbor_map!{},
|
||||
18 => None::<u64>,
|
||||
10 => Some(cbor_map!{2 => 3}),
|
||||
11 => None::<String>,
|
||||
12 => None::<&str>,
|
||||
13 => None::<Vec<u8>>,
|
||||
14 => None::<&[u8]>,
|
||||
15 => None::<bool>,
|
||||
16 => None::<i32>,
|
||||
17 => None::<i64>,
|
||||
18 => None::<u64>,
|
||||
-1 => -23,
|
||||
b"bar" => Some(cbor_null!()),
|
||||
"foo" => true,
|
||||
};
|
||||
let b = Value::Map(
|
||||
let b = Value::map(
|
||||
[
|
||||
(Value::Negative(-1), Value::Negative(-23)),
|
||||
(Value::Unsigned(4), Value::Unsigned(56)),
|
||||
(Value::from(4), Value::from(56)),
|
||||
(Value::from(5), Value::from(String::from("foo"))),
|
||||
(Value::from(6), Value::from(b"bar".to_vec())),
|
||||
(Value::from(7), Value::array(Vec::new())),
|
||||
(
|
||||
Value::TextString(String::from("foo")),
|
||||
Value::Simple(SimpleValue::TrueValue),
|
||||
Value::from(8),
|
||||
Value::array(vec![Value::from(0), Value::from(1)]),
|
||||
),
|
||||
(Value::from(9), Value::map(Vec::new())),
|
||||
(
|
||||
Value::ByteString(b"bar".to_vec()),
|
||||
Value::Simple(SimpleValue::NullValue),
|
||||
),
|
||||
(Value::Unsigned(5), Value::TextString(String::from("foo"))),
|
||||
(Value::Unsigned(6), Value::ByteString(b"bar".to_vec())),
|
||||
(Value::Unsigned(7), Value::Array(Vec::new())),
|
||||
(
|
||||
Value::Unsigned(8),
|
||||
Value::Array(vec![Value::Unsigned(0), Value::Unsigned(1)]),
|
||||
),
|
||||
(Value::Unsigned(9), Value::Map(Vec::new())),
|
||||
(
|
||||
Value::Unsigned(10),
|
||||
Value::Map(
|
||||
[(Value::Unsigned(2), Value::Unsigned(3))]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
),
|
||||
Value::from(10),
|
||||
Value::map([(Value::from(2), Value::from(3))].iter().cloned().collect()),
|
||||
),
|
||||
(Value::from(-1), Value::from(-23)),
|
||||
(Value::from(b"bar".to_vec()), Value::null_value()),
|
||||
(Value::from(String::from("foo")), Value::bool_value(true)),
|
||||
]
|
||||
.iter()
|
||||
.cloned()
|
||||
@@ -616,22 +592,19 @@ mod test {
|
||||
#[test]
|
||||
fn test_cbor_map_collection_empty() {
|
||||
let a = cbor_map_collection!(Vec::<(_, _)>::new());
|
||||
let b = Value::Map(Vec::new());
|
||||
let b = Value::map(Vec::new());
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cbor_map_collection_foo() {
|
||||
let a = cbor_map_collection!(vec![(Value::Unsigned(2), Value::Unsigned(3))]);
|
||||
let b = Value::Map(vec![(Value::Unsigned(2), Value::Unsigned(3))]);
|
||||
let a = cbor_map_collection!(vec![(Value::from(2), Value::from(3))]);
|
||||
let b = Value::map(vec![(Value::from(2), Value::from(3))]);
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
fn extract_map(cbor_value: Value) -> Vec<(Value, Value)> {
|
||||
match cbor_value {
|
||||
Value::Map(map) => map,
|
||||
_ => panic!("Expected CBOR map."),
|
||||
}
|
||||
cbor_value.extract_map().unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -721,4 +694,22 @@ mod test {
|
||||
assert_eq!(x4, Some(cbor_unsigned!(40)));
|
||||
assert_eq!(x5, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_destructure_unsorted_cbor_map() {
|
||||
let map = cbor_map! {
|
||||
2 => 20,
|
||||
1 => 10,
|
||||
};
|
||||
|
||||
destructure_cbor_map! {
|
||||
let {
|
||||
1 => x1,
|
||||
2 => x2,
|
||||
} = extract_map(map);
|
||||
}
|
||||
|
||||
assert_eq!(x1, Some(cbor_unsigned!(10)));
|
||||
assert_eq!(x2, Some(cbor_unsigned!(20)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
//! Functionality for deserializing CBOR data into values.
|
||||
|
||||
use super::values::{Constants, SimpleValue, Value};
|
||||
use super::values::{Constants, SimpleValue, Value, ValueImpl};
|
||||
use crate::{
|
||||
cbor_array_vec, cbor_bytes_lit, cbor_map_collection, cbor_tagged, cbor_text, cbor_unsigned,
|
||||
};
|
||||
@@ -144,7 +144,7 @@ impl<'a> Reader<'a> {
|
||||
if signed_size < 0 {
|
||||
Err(DecoderError::OutOfRangeIntegerValue)
|
||||
} else {
|
||||
Ok(Value::Negative(-(size_value as i64) - 1))
|
||||
Ok(Value(ValueImpl::Negative(-(size_value as i64) - 1)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ impl<'a> Reader<'a> {
|
||||
return Err(DecoderError::UnsupportedFloatingPointValue);
|
||||
}
|
||||
match SimpleValue::from_integer(size_value) {
|
||||
Some(simple_value) => Ok(Value::Simple(simple_value)),
|
||||
Some(simple_value) => Ok(Value(ValueImpl::Simple(simple_value))),
|
||||
None => Err(DecoderError::UnsupportedSimpleValue),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,13 @@ use alloc::string::{String, ToString};
|
||||
use alloc::vec::Vec;
|
||||
use core::cmp::Ordering;
|
||||
|
||||
/// The CBOR data structure.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Value(pub(crate) ValueImpl);
|
||||
|
||||
/// Possible CBOR values.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Value {
|
||||
pub(crate) enum ValueImpl {
|
||||
/// Unsigned integer value (uint).
|
||||
Unsigned(u64),
|
||||
/// Signed integer value (nint). Only 63 bits of information are used here.
|
||||
@@ -42,7 +46,7 @@ pub enum Value {
|
||||
|
||||
/// Specific simple CBOR values.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum SimpleValue {
|
||||
pub(crate) enum SimpleValue {
|
||||
FalseValue = 20,
|
||||
TrueValue = 21,
|
||||
NullValue = 22,
|
||||
@@ -71,45 +75,177 @@ impl Constants {
|
||||
}
|
||||
|
||||
impl Value {
|
||||
/// Creates a CBOR unsigned value.
|
||||
pub fn unsigned(int: u64) -> Value {
|
||||
Value(ValueImpl::Unsigned(int))
|
||||
}
|
||||
|
||||
/// Create an appropriate CBOR integer value (uint/nint).
|
||||
/// For simplicity, this only takes i64. Construct directly for the last bit.
|
||||
pub fn integer(int: i64) -> Value {
|
||||
if int >= 0 {
|
||||
Value::Unsigned(int as u64)
|
||||
Value(ValueImpl::Unsigned(int as u64))
|
||||
} else {
|
||||
Value::Negative(int)
|
||||
Value(ValueImpl::Negative(int))
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a CBOR byte string value.
|
||||
pub fn byte_string(bytes: Vec<u8>) -> Value {
|
||||
Value(ValueImpl::ByteString(bytes))
|
||||
}
|
||||
|
||||
/// Creates a CBOR text string value.
|
||||
pub fn text_string(text: String) -> Value {
|
||||
Value(ValueImpl::TextString(text))
|
||||
}
|
||||
|
||||
/// Create a CBOR array value.
|
||||
pub fn array(a: Vec<Value>) -> Value {
|
||||
Value(ValueImpl::Array(a))
|
||||
}
|
||||
|
||||
/// Create a CBOR map value.
|
||||
///
|
||||
/// Keys do not have to be sorted.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// You may not call this function with identical keys in its argument.
|
||||
pub fn map(mut m: Vec<(Value, Value)>) -> Value {
|
||||
m.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
let map_len = m.len();
|
||||
m.dedup_by(|a, b| a.0.eq(&b.0));
|
||||
if map_len != m.len() {
|
||||
panic!();
|
||||
}
|
||||
Value(ValueImpl::Map(m))
|
||||
}
|
||||
|
||||
/// Create a CBOR tagged value.
|
||||
pub fn tag(int: u64, value: Value) -> Value {
|
||||
Value(ValueImpl::Tag(int, Box::new(value)))
|
||||
}
|
||||
|
||||
/// Create a CBOR boolean simple value.
|
||||
pub fn bool_value(b: bool) -> Value {
|
||||
if b {
|
||||
Value::Simple(SimpleValue::TrueValue)
|
||||
Value(ValueImpl::Simple(SimpleValue::TrueValue))
|
||||
} else {
|
||||
Value::Simple(SimpleValue::FalseValue)
|
||||
Value(ValueImpl::Simple(SimpleValue::FalseValue))
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the major type for the [`Value`].
|
||||
pub fn type_label(&self) -> u8 {
|
||||
// TODO use enum discriminant instead when stable
|
||||
// https://github.com/rust-lang/rust/issues/60553
|
||||
/// Creates a null value.
|
||||
pub fn null_value() -> Value {
|
||||
Value(ValueImpl::Simple(SimpleValue::NullValue))
|
||||
}
|
||||
|
||||
/// Creates an undefined value.
|
||||
pub fn undefined() -> Value {
|
||||
Value(ValueImpl::Simple(SimpleValue::Undefined))
|
||||
}
|
||||
|
||||
pub fn extract_unsigned(self) -> Option<u64> {
|
||||
match self {
|
||||
Value::Unsigned(_) => 0,
|
||||
Value::Negative(_) => 1,
|
||||
Value::ByteString(_) => 2,
|
||||
Value::TextString(_) => 3,
|
||||
Value::Array(_) => 4,
|
||||
Value::Map(_) => 5,
|
||||
Value::Tag(_, _) => 6,
|
||||
Value::Simple(_) => 7,
|
||||
Value(ValueImpl::Unsigned(unsigned)) => Some(unsigned),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_integer(self) -> Option<i64> {
|
||||
match self {
|
||||
Value(ValueImpl::Unsigned(unsigned)) => {
|
||||
if unsigned <= core::i64::MAX as u64 {
|
||||
Some(unsigned as i64)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Value(ValueImpl::Negative(signed)) => Some(signed),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_byte_string(self) -> Option<Vec<u8>> {
|
||||
match self {
|
||||
Value(ValueImpl::ByteString(byte_string)) => Some(byte_string),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_text_string(self) -> Option<String> {
|
||||
match self {
|
||||
Value(ValueImpl::TextString(text_string)) => Some(text_string),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_array(self) -> Option<Vec<Value>> {
|
||||
match self {
|
||||
Value(ValueImpl::Array(array)) => Some(array),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_map(self) -> Option<Vec<(Value, Value)>> {
|
||||
match self {
|
||||
Value(ValueImpl::Map(map)) => Some(map),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_tag(self) -> Option<(u64, Value)> {
|
||||
match self {
|
||||
Value(ValueImpl::Tag(tag, value)) => Some((tag, *value)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_bool(self) -> Option<bool> {
|
||||
match self {
|
||||
Value(ValueImpl::Simple(SimpleValue::FalseValue)) => Some(false),
|
||||
Value(ValueImpl::Simple(SimpleValue::TrueValue)) => Some(true),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_null(self) -> Option<()> {
|
||||
match self {
|
||||
Value(ValueImpl::Simple(SimpleValue::NullValue)) => Some(()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_undefined(self) -> Option<()> {
|
||||
match self {
|
||||
Value(ValueImpl::Simple(SimpleValue::Undefined)) => Some(()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Value {
|
||||
fn cmp(&self, other: &Value) -> Ordering {
|
||||
use super::values::Value::{
|
||||
impl ValueImpl {
|
||||
/// Return the major type for the [`ValueImpl`].
|
||||
pub fn type_label(&self) -> u8 {
|
||||
// TODO use enum discriminant instead when stable
|
||||
// https://github.com/rust-lang/rust/issues/60553
|
||||
match self {
|
||||
ValueImpl::Unsigned(_) => 0,
|
||||
ValueImpl::Negative(_) => 1,
|
||||
ValueImpl::ByteString(_) => 2,
|
||||
ValueImpl::TextString(_) => 3,
|
||||
ValueImpl::Array(_) => 4,
|
||||
ValueImpl::Map(_) => 5,
|
||||
ValueImpl::Tag(_, _) => 6,
|
||||
ValueImpl::Simple(_) => 7,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for ValueImpl {
|
||||
fn cmp(&self, other: &ValueImpl) -> Ordering {
|
||||
use super::values::ValueImpl::{
|
||||
Array, ByteString, Map, Negative, Simple, Tag, TextString, Unsigned,
|
||||
};
|
||||
let self_type_value = self.type_label();
|
||||
@@ -156,16 +292,16 @@ impl Ord for Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Value {
|
||||
fn partial_cmp(&self, other: &Value) -> Option<Ordering> {
|
||||
impl PartialOrd for ValueImpl {
|
||||
fn partial_cmp(&self, other: &ValueImpl) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Value {}
|
||||
impl Eq for ValueImpl {}
|
||||
|
||||
impl PartialEq for Value {
|
||||
fn eq(&self, other: &Value) -> bool {
|
||||
impl PartialEq for ValueImpl {
|
||||
fn eq(&self, other: &ValueImpl) -> bool {
|
||||
self.cmp(other) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
@@ -184,8 +320,26 @@ impl SimpleValue {
|
||||
}
|
||||
|
||||
impl From<u64> for Value {
|
||||
fn from(unsigned: u64) -> Self {
|
||||
Value::Unsigned(unsigned)
|
||||
fn from(u: u64) -> Self {
|
||||
Value::unsigned(u)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Value {
|
||||
fn from(u: u32) -> Self {
|
||||
Value::unsigned(u as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for Value {
|
||||
fn from(u: u16) -> Self {
|
||||
Value::unsigned(u as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for Value {
|
||||
fn from(u: u8) -> Self {
|
||||
Value::unsigned(u as u64)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,39 +355,57 @@ impl From<i32> for Value {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i16> for Value {
|
||||
fn from(i: i16) -> Self {
|
||||
Value::integer(i as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i8> for Value {
|
||||
fn from(i: i8) -> Self {
|
||||
Value::integer(i as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for Value {
|
||||
fn from(bytes: Vec<u8>) -> Self {
|
||||
Value::ByteString(bytes)
|
||||
Value(ValueImpl::ByteString(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8]> for Value {
|
||||
fn from(bytes: &[u8]) -> Self {
|
||||
Value::ByteString(bytes.to_vec())
|
||||
Value(ValueImpl::ByteString(bytes.to_vec()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8; 0]> for Value {
|
||||
fn from(bytes: &[u8; 0]) -> Self {
|
||||
Value(ValueImpl::ByteString(bytes.to_vec()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Value {
|
||||
fn from(text: String) -> Self {
|
||||
Value::TextString(text)
|
||||
Value(ValueImpl::TextString(text))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Value {
|
||||
fn from(text: &str) -> Self {
|
||||
Value::TextString(text.to_string())
|
||||
Value(ValueImpl::TextString(text.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<Value>> for Value {
|
||||
fn from(array: Vec<Value>) -> Self {
|
||||
Value::Array(array)
|
||||
Value(ValueImpl::Array(array))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<(Value, Value)>> for Value {
|
||||
fn from(map: Vec<(Value, Value)>) -> Self {
|
||||
Value::Map(map)
|
||||
Value::map(map)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,9 +457,209 @@ where
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::{cbor_array, cbor_bool, cbor_bytes, cbor_int, cbor_map, cbor_tagged, cbor_text};
|
||||
use crate::{
|
||||
cbor_array, cbor_bool, cbor_bytes, cbor_bytes_lit, cbor_int, cbor_map, cbor_null,
|
||||
cbor_tagged, cbor_text, cbor_undefined, cbor_unsigned,
|
||||
};
|
||||
use alloc::vec;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_duplicate_map_key() {
|
||||
let _map = cbor_map! {
|
||||
0 => "a",
|
||||
-1 => "c",
|
||||
b"a" => "e",
|
||||
"c" => "g",
|
||||
0 => "b",
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_unsigned() {
|
||||
assert_eq!(cbor_int!(1).extract_unsigned(), Some(1));
|
||||
assert_eq!(cbor_int!(-1).extract_unsigned(), None);
|
||||
assert_eq!(cbor_bytes!(vec![]).extract_unsigned(), None);
|
||||
assert_eq!(cbor_text!("").extract_unsigned(), None);
|
||||
assert_eq!(cbor_array![].extract_unsigned(), None);
|
||||
assert_eq!(cbor_map! {}.extract_unsigned(), None);
|
||||
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_unsigned(), None);
|
||||
assert_eq!(cbor_bool!(false).extract_unsigned(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_unsigned_limits() {
|
||||
assert_eq!(
|
||||
cbor_unsigned!(core::u64::MAX).extract_unsigned(),
|
||||
Some(core::u64::MAX)
|
||||
);
|
||||
assert_eq!(
|
||||
cbor_unsigned!((core::i64::MAX as u64) + 1).extract_unsigned(),
|
||||
Some((core::i64::MAX as u64) + 1)
|
||||
);
|
||||
assert_eq!(
|
||||
cbor_int!(core::i64::MAX).extract_unsigned(),
|
||||
Some(core::i64::MAX as u64)
|
||||
);
|
||||
assert_eq!(cbor_int!(123).extract_unsigned(), Some(123));
|
||||
assert_eq!(cbor_int!(0).extract_unsigned(), Some(0));
|
||||
assert_eq!(cbor_int!(-123).extract_unsigned(), None);
|
||||
assert_eq!(cbor_int!(core::i64::MIN).extract_unsigned(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_integer() {
|
||||
assert_eq!(cbor_int!(1).extract_integer(), Some(1));
|
||||
assert_eq!(cbor_int!(-1).extract_integer(), Some(-1));
|
||||
assert_eq!(cbor_bytes!(vec![]).extract_integer(), None);
|
||||
assert_eq!(cbor_text!("").extract_integer(), None);
|
||||
assert_eq!(cbor_array![].extract_integer(), None);
|
||||
assert_eq!(cbor_map! {}.extract_integer(), None);
|
||||
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_integer(), None);
|
||||
assert_eq!(cbor_bool!(false).extract_integer(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_integer_limits() {
|
||||
assert_eq!(cbor_unsigned!(core::u64::MAX).extract_integer(), None);
|
||||
assert_eq!(
|
||||
cbor_unsigned!((core::i64::MAX as u64) + 1).extract_integer(),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
cbor_int!(core::i64::MAX).extract_integer(),
|
||||
Some(core::i64::MAX)
|
||||
);
|
||||
assert_eq!(cbor_int!(123).extract_integer(), Some(123));
|
||||
assert_eq!(cbor_int!(0).extract_integer(), Some(0));
|
||||
assert_eq!(cbor_int!(-123).extract_integer(), Some(-123));
|
||||
assert_eq!(
|
||||
cbor_int!(core::i64::MIN).extract_integer(),
|
||||
Some(core::i64::MIN)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_byte_string() {
|
||||
assert_eq!(cbor_int!(1).extract_byte_string(), None);
|
||||
assert_eq!(cbor_int!(-1).extract_byte_string(), None);
|
||||
assert_eq!(cbor_bytes!(vec![]).extract_byte_string(), Some(Vec::new()));
|
||||
assert_eq!(
|
||||
cbor_bytes_lit!(b"bar").extract_byte_string(),
|
||||
Some(b"bar".to_vec())
|
||||
);
|
||||
assert_eq!(cbor_text!("").extract_byte_string(), None);
|
||||
assert_eq!(cbor_array![].extract_byte_string(), None);
|
||||
assert_eq!(cbor_map! {}.extract_byte_string(), None);
|
||||
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_byte_string(), None);
|
||||
assert_eq!(cbor_bool!(false).extract_byte_string(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_text_string() {
|
||||
assert_eq!(cbor_int!(1).extract_text_string(), None);
|
||||
assert_eq!(cbor_int!(-1).extract_text_string(), None);
|
||||
assert_eq!(cbor_bytes!(vec![]).extract_text_string(), None);
|
||||
assert_eq!(cbor_text!("").extract_text_string(), Some(String::new()));
|
||||
assert_eq!(cbor_text!("s").extract_text_string(), Some("s".to_string()));
|
||||
assert_eq!(cbor_array![].extract_text_string(), None);
|
||||
assert_eq!(cbor_map! {}.extract_text_string(), None);
|
||||
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_text_string(), None);
|
||||
assert_eq!(cbor_bool!(false).extract_text_string(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_array() {
|
||||
assert_eq!(cbor_int!(1).extract_array(), None);
|
||||
assert_eq!(cbor_int!(-1).extract_array(), None);
|
||||
assert_eq!(cbor_bytes!(vec![]).extract_array(), None);
|
||||
assert_eq!(cbor_text!("").extract_array(), None);
|
||||
assert_eq!(cbor_array![].extract_array(), Some(Vec::new()));
|
||||
assert_eq!(
|
||||
cbor_array![cbor_int!(1)].extract_array(),
|
||||
Some(vec![cbor_int!(1)])
|
||||
);
|
||||
assert_eq!(cbor_map! {}.extract_array(), None);
|
||||
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_array(), None);
|
||||
assert_eq!(cbor_bool!(false).extract_array(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_map() {
|
||||
assert_eq!(cbor_int!(1).extract_map(), None);
|
||||
assert_eq!(cbor_int!(-1).extract_map(), None);
|
||||
assert_eq!(cbor_bytes!(vec![]).extract_map(), None);
|
||||
assert_eq!(cbor_text!("").extract_map(), None);
|
||||
assert_eq!(cbor_array![].extract_map(), None);
|
||||
assert_eq!(cbor_map! {}.extract_map(), Some(Vec::new()));
|
||||
assert_eq!(
|
||||
cbor_map! {0 => 1}.extract_map(),
|
||||
Some(vec![(cbor_int!(0), cbor_int!(1))])
|
||||
);
|
||||
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_map(), None);
|
||||
assert_eq!(cbor_bool!(false).extract_map(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_tag() {
|
||||
assert_eq!(cbor_int!(1).extract_tag(), None);
|
||||
assert_eq!(cbor_int!(-1).extract_tag(), None);
|
||||
assert_eq!(cbor_bytes!(vec![]).extract_tag(), None);
|
||||
assert_eq!(cbor_text!("").extract_tag(), None);
|
||||
assert_eq!(cbor_array![].extract_tag(), None);
|
||||
assert_eq!(cbor_map! {}.extract_tag(), None);
|
||||
assert_eq!(
|
||||
cbor_tagged!(1, cbor_text!("s")).extract_tag(),
|
||||
Some((1, cbor_text!("s")))
|
||||
);
|
||||
assert_eq!(cbor_bool!(false).extract_tag(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_bool() {
|
||||
assert_eq!(cbor_int!(1).extract_bool(), None);
|
||||
assert_eq!(cbor_int!(-1).extract_bool(), None);
|
||||
assert_eq!(cbor_bytes!(vec![]).extract_bool(), None);
|
||||
assert_eq!(cbor_text!("").extract_bool(), None);
|
||||
assert_eq!(cbor_array![].extract_bool(), None);
|
||||
assert_eq!(cbor_map! {}.extract_bool(), None);
|
||||
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_bool(), None);
|
||||
assert_eq!(cbor_bool!(false).extract_bool(), Some(false));
|
||||
assert_eq!(cbor_bool!(true).extract_bool(), Some(true));
|
||||
assert_eq!(cbor_null!().extract_bool(), None);
|
||||
assert_eq!(cbor_undefined!().extract_bool(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_null() {
|
||||
assert_eq!(cbor_int!(1).extract_null(), None);
|
||||
assert_eq!(cbor_int!(-1).extract_null(), None);
|
||||
assert_eq!(cbor_bytes!(vec![]).extract_null(), None);
|
||||
assert_eq!(cbor_text!("").extract_null(), None);
|
||||
assert_eq!(cbor_array![].extract_null(), None);
|
||||
assert_eq!(cbor_map! {}.extract_null(), None);
|
||||
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_null(), None);
|
||||
assert_eq!(cbor_bool!(false).extract_null(), None);
|
||||
assert_eq!(cbor_bool!(true).extract_null(), None);
|
||||
assert_eq!(cbor_null!().extract_null(), Some(()));
|
||||
assert_eq!(cbor_undefined!().extract_null(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extract_undefined() {
|
||||
assert_eq!(cbor_int!(1).extract_undefined(), None);
|
||||
assert_eq!(cbor_int!(-1).extract_undefined(), None);
|
||||
assert_eq!(cbor_bytes!(vec![]).extract_undefined(), None);
|
||||
assert_eq!(cbor_text!("").extract_undefined(), None);
|
||||
assert_eq!(cbor_array![].extract_undefined(), None);
|
||||
assert_eq!(cbor_map! {}.extract_undefined(), None);
|
||||
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_undefined(), None);
|
||||
assert_eq!(cbor_bool!(false).extract_undefined(), None);
|
||||
assert_eq!(cbor_bool!(true).extract_undefined(), None);
|
||||
assert_eq!(cbor_null!().extract_undefined(), None);
|
||||
assert_eq!(cbor_undefined!().extract_undefined(), Some(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_value_ordering() {
|
||||
assert!(cbor_int!(0) < cbor_int!(23));
|
||||
@@ -329,12 +701,12 @@ mod test {
|
||||
assert!(cbor_map! {"" => 0} < cbor_map! {cbor_array![] => 0});
|
||||
assert!(cbor_map! {cbor_array![] => 0} < cbor_map! {cbor_map!{} => 0});
|
||||
assert!(cbor_map! {cbor_map!{} => 0} < cbor_map! {false => 0});
|
||||
assert!(cbor_map! {false => 0} < cbor_map! {0 => 0, 0 => 0});
|
||||
assert!(cbor_map! {false => 0} < cbor_map! {0 => 0, 1 => 0});
|
||||
assert!(cbor_map! {0 => 0} < cbor_tagged!(2, cbor_int!(0)));
|
||||
assert!(cbor_map! {0 => 0, 0 => 0} < cbor_bool!(false));
|
||||
assert!(cbor_map! {0 => 0, 1 => 0} < cbor_bool!(false));
|
||||
assert!(cbor_bool!(false) < cbor_bool!(true));
|
||||
assert!(cbor_bool!(true) < Value::Simple(SimpleValue::NullValue));
|
||||
assert!(Value::Simple(SimpleValue::NullValue) < Value::Simple(SimpleValue::Undefined));
|
||||
assert!(cbor_bool!(true) < cbor_null!());
|
||||
assert!(cbor_null!() < cbor_undefined!());
|
||||
assert!(cbor_tagged!(1, cbor_text!("s")) < cbor_tagged!(2, cbor_int!(0)));
|
||||
assert!(cbor_int!(1) < cbor_int!(-1));
|
||||
assert!(cbor_int!(1) < cbor_bytes!(vec![0x00]));
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
//! Functionality for serializing CBOR values into bytes.
|
||||
|
||||
use super::values::{Constants, Value};
|
||||
use super::values::{Constants, Value, ValueImpl};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
/// Possible errors from a serialization operation.
|
||||
@@ -60,42 +60,36 @@ impl<'a> Writer<'a> {
|
||||
if remaining_depth.map_or(false, |d| d < 0) {
|
||||
return Err(EncoderError::TooMuchNesting);
|
||||
}
|
||||
let type_label = value.type_label();
|
||||
match value {
|
||||
Value::Unsigned(unsigned) => self.start_item(type_label, unsigned),
|
||||
Value::Negative(negative) => self.start_item(type_label, -(negative + 1) as u64),
|
||||
Value::ByteString(byte_string) => {
|
||||
let type_label = value.0.type_label();
|
||||
match value.0 {
|
||||
ValueImpl::Unsigned(unsigned) => self.start_item(type_label, unsigned),
|
||||
ValueImpl::Negative(negative) => self.start_item(type_label, -(negative + 1) as u64),
|
||||
ValueImpl::ByteString(byte_string) => {
|
||||
self.start_item(type_label, byte_string.len() as u64);
|
||||
self.encoded_cbor.extend(byte_string);
|
||||
}
|
||||
Value::TextString(text_string) => {
|
||||
ValueImpl::TextString(text_string) => {
|
||||
self.start_item(type_label, text_string.len() as u64);
|
||||
self.encoded_cbor.extend(text_string.into_bytes());
|
||||
}
|
||||
Value::Array(array) => {
|
||||
ValueImpl::Array(array) => {
|
||||
self.start_item(type_label, array.len() as u64);
|
||||
for el in array {
|
||||
self.encode_cbor(el, remaining_depth.map(|d| d - 1))?;
|
||||
}
|
||||
}
|
||||
Value::Map(mut map) => {
|
||||
map.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
let map_len = map.len();
|
||||
map.dedup_by(|a, b| a.0.eq(&b.0));
|
||||
if map_len != map.len() {
|
||||
return Err(EncoderError::DuplicateMapKey);
|
||||
}
|
||||
self.start_item(type_label, map_len as u64);
|
||||
ValueImpl::Map(map) => {
|
||||
self.start_item(type_label, map.len() as u64);
|
||||
for (k, v) in map {
|
||||
self.encode_cbor(k, remaining_depth.map(|d| d - 1))?;
|
||||
self.encode_cbor(v, remaining_depth.map(|d| d - 1))?;
|
||||
}
|
||||
}
|
||||
Value::Tag(tag, inner_value) => {
|
||||
ValueImpl::Tag(tag, inner_value) => {
|
||||
self.start_item(type_label, tag);
|
||||
self.encode_cbor(*inner_value, remaining_depth.map(|d| d - 1))?;
|
||||
}
|
||||
Value::Simple(simple_value) => self.start_item(type_label, simple_value as u64),
|
||||
ValueImpl::Simple(simple_value) => self.start_item(type_label, simple_value as u64),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -342,42 +336,6 @@ mod test {
|
||||
assert_eq!(write_return(sorted_map), write_return(unsorted_map));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_write_map_duplicates() {
|
||||
let duplicate0 = cbor_map! {
|
||||
0 => "a",
|
||||
-1 => "c",
|
||||
b"a" => "e",
|
||||
"c" => "g",
|
||||
0 => "b",
|
||||
};
|
||||
assert_eq!(write_return(duplicate0), None);
|
||||
let duplicate1 = cbor_map! {
|
||||
0 => "a",
|
||||
-1 => "c",
|
||||
b"a" => "e",
|
||||
"c" => "g",
|
||||
-1 => "d",
|
||||
};
|
||||
assert_eq!(write_return(duplicate1), None);
|
||||
let duplicate2 = cbor_map! {
|
||||
0 => "a",
|
||||
-1 => "c",
|
||||
b"a" => "e",
|
||||
"c" => "g",
|
||||
b"a" => "f",
|
||||
};
|
||||
assert_eq!(write_return(duplicate2), None);
|
||||
let duplicate3 = cbor_map! {
|
||||
0 => "a",
|
||||
-1 => "c",
|
||||
b"a" => "e",
|
||||
"c" => "g",
|
||||
"c" => "h",
|
||||
};
|
||||
assert_eq!(write_return(duplicate3), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_write_map_with_array() {
|
||||
let value_map = cbor_map! {
|
||||
|
||||
@@ -365,17 +365,11 @@ impl From<StoreError> for Error {
|
||||
}
|
||||
|
||||
fn extract_byte_string(cbor_value: cbor::Value) -> Result<Vec<u8>, Error> {
|
||||
match cbor_value {
|
||||
cbor::Value::ByteString(byte_string) => Ok(byte_string),
|
||||
_ => Err(Error),
|
||||
}
|
||||
cbor_value.extract_byte_string().ok_or(Error)
|
||||
}
|
||||
|
||||
fn extract_map(cbor_value: cbor::Value) -> Result<Vec<(cbor::Value, cbor::Value)>, Error> {
|
||||
match cbor_value {
|
||||
cbor::Value::Map(map) => Ok(map),
|
||||
_ => Err(Error),
|
||||
}
|
||||
cbor_value.extract_map().ok_or(Error)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1153,63 +1153,38 @@ impl From<CredentialManagementSubCommandParameters> for cbor::Value {
|
||||
}
|
||||
}
|
||||
|
||||
fn ok_or_cbor_type<T>(value_option: Option<T>) -> Result<T, Ctap2StatusCode> {
|
||||
value_option.ok_or(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
|
||||
}
|
||||
|
||||
pub fn extract_unsigned(cbor_value: cbor::Value) -> Result<u64, Ctap2StatusCode> {
|
||||
match cbor_value {
|
||||
cbor::Value::Unsigned(unsigned) => Ok(unsigned),
|
||||
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
|
||||
}
|
||||
ok_or_cbor_type(cbor_value.extract_unsigned())
|
||||
}
|
||||
|
||||
pub fn extract_integer(cbor_value: cbor::Value) -> Result<i64, Ctap2StatusCode> {
|
||||
match cbor_value {
|
||||
cbor::Value::Unsigned(unsigned) => {
|
||||
if unsigned <= core::i64::MAX as u64 {
|
||||
Ok(unsigned as i64)
|
||||
} else {
|
||||
Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE)
|
||||
}
|
||||
}
|
||||
cbor::Value::Negative(signed) => Ok(signed),
|
||||
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
|
||||
}
|
||||
ok_or_cbor_type(cbor_value.extract_integer())
|
||||
}
|
||||
|
||||
pub fn extract_byte_string(cbor_value: cbor::Value) -> Result<Vec<u8>, Ctap2StatusCode> {
|
||||
match cbor_value {
|
||||
cbor::Value::ByteString(byte_string) => Ok(byte_string),
|
||||
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
|
||||
}
|
||||
ok_or_cbor_type(cbor_value.extract_byte_string())
|
||||
}
|
||||
|
||||
pub fn extract_text_string(cbor_value: cbor::Value) -> Result<String, Ctap2StatusCode> {
|
||||
match cbor_value {
|
||||
cbor::Value::TextString(text_string) => Ok(text_string),
|
||||
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
|
||||
}
|
||||
ok_or_cbor_type(cbor_value.extract_text_string())
|
||||
}
|
||||
|
||||
pub fn extract_array(cbor_value: cbor::Value) -> Result<Vec<cbor::Value>, Ctap2StatusCode> {
|
||||
match cbor_value {
|
||||
cbor::Value::Array(array) => Ok(array),
|
||||
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
|
||||
}
|
||||
ok_or_cbor_type(cbor_value.extract_array())
|
||||
}
|
||||
|
||||
pub fn extract_map(
|
||||
cbor_value: cbor::Value,
|
||||
) -> Result<Vec<(cbor::Value, cbor::Value)>, Ctap2StatusCode> {
|
||||
match cbor_value {
|
||||
cbor::Value::Map(map) => Ok(map),
|
||||
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
|
||||
}
|
||||
ok_or_cbor_type(cbor_value.extract_map())
|
||||
}
|
||||
|
||||
pub fn extract_bool(cbor_value: cbor::Value) -> Result<bool, Ctap2StatusCode> {
|
||||
match cbor_value {
|
||||
cbor::Value::Simple(cbor::SimpleValue::FalseValue) => Ok(false),
|
||||
cbor::Value::Simple(cbor::SimpleValue::TrueValue) => Ok(true),
|
||||
_ => Err(Ctap2StatusCode::CTAP2_ERR_CBOR_UNEXPECTED_TYPE),
|
||||
}
|
||||
ok_or_cbor_type(cbor_value.extract_bool())
|
||||
}
|
||||
|
||||
pub fn ok_or_missing<T>(value_option: Option<T>) -> Result<T, Ctap2StatusCode> {
|
||||
|
||||
Reference in New Issue
Block a user