use crate::values::Value;
use alloc::vec;
use core::cmp::Ordering;
use core::iter::Peekable;
#[macro_export]
macro_rules! destructure_cbor_map {
( let { $( $key:expr => $variable:ident, )+ } = $map:expr; ) => {
#[cfg(test)]
$crate::assert_sorted_keys!($( $key, )+);
use $crate::values::{IntoCborValue, Value};
use $crate::macros::destructure_cbor_map_peek_value;
let mut it = $map.into_iter().peekable();
$(
let $variable: Option<Value> = destructure_cbor_map_peek_value(&mut it, $key.into_cbor_value());
)+
};
}
pub fn destructure_cbor_map_peek_value(
it: &mut Peekable<vec::IntoIter<(Value, Value)>>,
needle: Value,
) -> Option<Value> {
loop {
match it.peek() {
None => return None,
Some(item) => {
let key: &Value = &item.0;
match key.cmp(&needle) {
Ordering::Less => {
it.next();
}
Ordering::Equal => {
let value: Value = it.next().unwrap().1;
return Some(value);
}
Ordering::Greater => return None,
}
}
}
}
}
#[macro_export]
macro_rules! assert_sorted_keys {
( $key:expr, ) => {
};
( $key1:expr, $key2:expr, $( $keys:expr, )* ) => {
{
use $crate::values::{IntoCborValue, Value};
let k1: Value = $key1.into_cbor_value();
let k2: Value = $key2.into_cbor_value();
assert!(
k1 < k2,
"{:?} < {:?} failed. The destructure_cbor_map! macro requires keys in sorted order.",
k1,
k2,
);
}
$crate::assert_sorted_keys!($key2, $( $keys, )*);
};
}
#[macro_export]
macro_rules! cbor_map {
( $( $key:expr => $value:expr, )+ ) => {
cbor_map! ( $($key => $value),+ )
};
( $( $key:expr => $value:expr ),* ) => {
{
#[allow(unused_imports)]
use $crate::values::IntoCborValue;
let mut _map = ::alloc::vec::Vec::new();
$(
_map.push(($key.into_cbor_value(), $value.into_cbor_value()));
)*
$crate::values::Value::Map(_map)
}
};
}
#[macro_export]
macro_rules! cbor_map_options {
( $( $key:expr => $value:expr, )+ ) => {
cbor_map_options! ( $($key => $value),+ )
};
( $( $key:expr => $value:expr ),* ) => {
{
#[allow(unused_imports)]
use $crate::values::{IntoCborValue, IntoCborValueOption};
let mut _map = ::alloc::vec::Vec::<(_, $crate::values::Value)>::new();
$(
{
let opt: Option<$crate::values::Value> = $value.into_cbor_value_option();
if let Some(val) = opt {
_map.push(($key.into_cbor_value(), val));
}
}
)*
$crate::values::Value::Map(_map)
}
};
}
#[macro_export]
macro_rules! cbor_map_collection {
( $tree:expr ) => {{
$crate::values::Value::from($tree)
}};
}
#[macro_export]
macro_rules! cbor_array {
( $( $value:expr, )+ ) => {
cbor_array! ( $($value),+ )
};
( $( $value:expr ),* ) => {
{
#[allow(unused_imports)]
use $crate::values::IntoCborValue;
$crate::values::Value::Array(vec![ $( $value.into_cbor_value(), )* ])
}
};
}
#[macro_export]
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())
}};
}
#[macro_export]
macro_rules! cbor_true {
( ) => {
$crate::values::Value::Simple($crate::values::SimpleValue::TrueValue)
};
}
#[macro_export]
macro_rules! cbor_false {
( ) => {
$crate::values::Value::Simple($crate::values::SimpleValue::FalseValue)
};
}
#[macro_export]
macro_rules! cbor_null {
( ) => {
$crate::values::Value::Simple($crate::values::SimpleValue::NullValue)
};
}
#[macro_export]
macro_rules! cbor_undefined {
( ) => {
$crate::values::Value::Simple($crate::values::SimpleValue::Undefined)
};
}
#[macro_export]
macro_rules! cbor_bool {
( $x:expr ) => {
$crate::values::Value::bool_value($x)
};
}
#[macro_export]
macro_rules! cbor_unsigned {
( $x:expr ) => {
$crate::values::Value::Unsigned($x)
};
}
#[macro_export]
macro_rules! cbor_int {
( $x:expr ) => {
$crate::values::Value::integer($x)
};
}
#[macro_export]
macro_rules! cbor_text {
( $x:expr ) => {
$crate::values::Value::TextString($x.into())
};
}
#[macro_export]
macro_rules! cbor_bytes {
( $x:expr ) => {
$crate::values::Value::ByteString($x)
};
}
#[macro_export]
macro_rules! cbor_tagged {
( $t:expr, $x: expr ) => {
$crate::values::Value::Tag($t, ::alloc::boxed::Box::new($x))
};
}
#[macro_export]
macro_rules! cbor_bytes_lit {
( $x:expr ) => {
$crate::cbor_bytes!(($x as &[u8]).to_vec())
};
}
#[cfg(test)]
mod test {
use super::super::values::{SimpleValue, Value};
use alloc::{string::String, vec, 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));
}
#[test]
fn test_cbor_bool() {
assert_eq!(cbor_bool!(true), Value::Simple(SimpleValue::TrueValue));
assert_eq!(cbor_bool!(false), Value::Simple(SimpleValue::FalseValue));
}
#[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!(core::i64::MAX),
Value::Unsigned(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));
}
#[test]
fn test_cbor_int_literals() {
let a = cbor_array![
core::i64::MIN,
core::i32::MIN,
-123456,
-1,
0,
1,
123456,
core::i32::MAX,
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),
]);
assert_eq!(a, b);
}
#[test]
fn test_cbor_array() {
let a = cbor_array![
-123,
456,
true,
cbor_null!(),
"foo",
b"bar",
cbor_array![],
cbor_array![0, 1],
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(),
),
]);
assert_eq!(a, b);
}
#[test]
fn test_cbor_array_vec_empty() {
let a = cbor_array_vec!(Vec::<bool>::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),
]);
assert_eq!(a, b);
}
#[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")),
]);
assert_eq!(a, b);
}
#[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()),
]);
assert_eq!(a, b);
}
#[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},
};
let b = Value::Map(
[
(Value::Negative(-1), Value::Negative(-23)),
(Value::Unsigned(4), Value::Unsigned(56)),
(
Value::TextString(String::from("foo")),
Value::Simple(SimpleValue::TrueValue),
),
(
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(),
),
),
]
.iter()
.cloned()
.collect(),
);
assert_eq!(a, b);
}
#[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}),
};
let b = Value::Map(
[
(Value::Negative(-1), Value::Negative(-23)),
(Value::Unsigned(4), Value::Unsigned(56)),
(
Value::TextString(String::from("foo")),
Value::Simple(SimpleValue::TrueValue),
),
(
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(),
),
),
]
.iter()
.cloned()
.collect(),
);
assert_eq!(a, b);
}
#[test]
fn test_cbor_map_collection_empty() {
let a = cbor_map_collection!(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))]);
assert_eq!(a, b);
}
fn extract_map(cbor_value: Value) -> Vec<(Value, Value)> {
match cbor_value {
Value::Map(map) => map,
_ => panic!("Expected CBOR map."),
}
}
#[test]
fn test_destructure_cbor_map_simple() {
let map = cbor_map! {
1 => 10,
2 => 20,
};
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)));
}
#[test]
#[should_panic]
fn test_destructure_cbor_map_unsorted() {
let map = cbor_map! {
1 => 10,
2 => 20,
};
destructure_cbor_map! {
let {
2 => _x2,
1 => _x1,
} = extract_map(map);
}
}
#[test]
fn test_destructure_cbor_map_partial() {
let map = cbor_map! {
1 => 10,
2 => 20,
3 => 30,
4 => 40,
5 => 50,
6 => 60,
7 => 70,
8 => 80,
9 => 90,
};
destructure_cbor_map! {
let {
3 => x3,
7 => x7,
} = extract_map(map);
}
assert_eq!(x3, Some(cbor_unsigned!(30)));
assert_eq!(x7, Some(cbor_unsigned!(70)));
}
#[test]
fn test_destructure_cbor_map_missing() {
let map = cbor_map! {
1 => 10,
3 => 30,
4 => 40,
};
destructure_cbor_map! {
let {
0 => x0,
1 => x1,
2 => x2,
3 => x3,
4 => x4,
5 => x5,
} = extract_map(map);
}
assert_eq!(x0, None);
assert_eq!(x1, Some(cbor_unsigned!(10)));
assert_eq!(x2, None);
assert_eq!(x3, Some(cbor_unsigned!(30)));
assert_eq!(x4, Some(cbor_unsigned!(40)));
assert_eq!(x5, None);
}
}