/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ extern crate libc; use std::io; macro_rules! try_or { ($val:expr, $or:expr) => { match $val { Ok(v) => v, Err(e) => { #[allow(clippy::redundant_closure_call)] return $or(e); } } }; } pub trait Signed { fn is_negative(&self) -> bool; } impl Signed for i32 { fn is_negative(&self) -> bool { *self < 0 } } impl Signed for usize { fn is_negative(&self) -> bool { (*self as isize) < 0 } } #[cfg(all(target_os = "linux", not(test)))] pub fn from_unix_result(rv: T) -> io::Result { if rv.is_negative() { let errno = unsafe { *libc::__errno_location() }; Err(io::Error::from_raw_os_error(errno)) } else { Ok(rv) } } #[cfg(all(target_os = "freebsd", not(test)))] pub fn from_unix_result(rv: T) -> io::Result { if rv.is_negative() { let errno = unsafe { *libc::__error() }; Err(io::Error::from_raw_os_error(errno)) } else { Ok(rv) } } #[cfg(all(target_os = "openbsd", not(test)))] pub fn from_unix_result(rv: T) -> io::Result { if rv.is_negative() { Err(io::Error::last_os_error()) } else { Ok(rv) } } pub fn io_err(msg: &str) -> io::Error { io::Error::new(io::ErrorKind::Other, msg) } #[cfg(test)] pub fn decode_hex(s: &str) -> Vec { (0..s.len()) .step_by(2) .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap()) .collect() } /// Serialize a heterogeneous map with optional entries in the order they appear. /// /// The macro automatically calculates the number of entries to allocate in the /// map, and closes the map. Each key and value expression is evaluated only /// once. /// /// Arguments: /// - An expression of type [serde::Serializer]. This expression will be bound /// to a local variable and thus evaluated only once. /// - 0 to 10 (inclusive) entries of the form `$key => $value,`, where `$key` is /// any expression and `$value` is an expression of type [Option]. The /// entry will be included in the map if and only if the `$value` is [Some]. /// Each key and value expression is evaluated only once. /// - The 11th entry and forward instead needs to take the form `$ident: $key => /// $value,`, where `$ident` is an arbitrary identifier. These `$ident`s are /// needed in order to bind each `$value` as a local variable, in order to /// evaluate each expression only once. Recommended use is to simply set /// `$ident` to `v1`, `v2`, ..., or possibly some descriptive label. macro_rules! serialize_map_optional { ($s:expr, $k1:expr => $v1:expr $(,)?) => { serialize_map_optional!( @internal $s, v1: $k1 => $v1, ) }; ($s:expr, $k1:expr => $v1:expr, $k2:expr => $v2:expr $(,)?) => { serialize_map_optional!( @internal $s, v1: $k1 => $v1, v2: $k2 => $v2, ) }; ($s:expr, $k1:expr => $v1:expr, $k2:expr => $v2:expr, $k3:expr => $v3:expr $(,)?) => { serialize_map_optional!( @internal $s, v1: $k1 => $v1, v2: $k2 => $v2, v3: $k3 => $v3, ) }; ($s:expr, $k1:expr => $v1:expr, $k2:expr => $v2:expr, $k3:expr => $v3:expr, $k4:expr => $v4:expr $(,)?) => { serialize_map_optional!( @internal $s, v1: $k1 => $v1, v2: $k2 => $v2, v3: $k3 => $v3, v4: $k4 => $v4, ) }; ($s:expr, $k1:expr => $v1:expr, $k2:expr => $v2:expr, $k3:expr => $v3:expr, $k4:expr => $v4:expr, $k5:expr => $v5:expr $(,)?) => { serialize_map_optional!( @internal $s, v1: $k1 => $v1, v2: $k2 => $v2, v3: $k3 => $v3, v4: $k4 => $v4, v5: $k5 => $v5, ) }; ($s:expr, $k1:expr => $v1:expr, $k2:expr => $v2:expr, $k3:expr => $v3:expr, $k4:expr => $v4:expr, $k5:expr => $v5:expr, $k6:expr => $v6:expr $(,)?) => { serialize_map_optional!( @internal $s, v1: $k1 => $v1, v2: $k2 => $v2, v3: $k3 => $v3, v4: $k4 => $v4, v5: $k5 => $v5, v6: $k6 => $v6, ) }; ($s:expr, $k1:expr => $v1:expr, $k2:expr => $v2:expr, $k3:expr => $v3:expr, $k4:expr => $v4:expr, $k5:expr => $v5:expr, $k6:expr => $v6:expr, $k7:expr => $v7:expr $(,)?) => { serialize_map_optional!( @internal $s, v1: $k1 => $v1, v2: $k2 => $v2, v3: $k3 => $v3, v4: $k4 => $v4, v5: $k5 => $v5, v6: $k6 => $v6, v7: $k7 => $v7, ) }; ($s:expr, $k1:expr => $v1:expr, $k2:expr => $v2:expr, $k3:expr => $v3:expr, $k4:expr => $v4:expr, $k5:expr => $v5:expr, $k6:expr => $v6:expr, $k7:expr => $v7:expr, $k8:expr => $v8:expr $(,)?) => { serialize_map_optional!( @internal $s, v1: $k1 => $v1, v2: $k2 => $v2, v3: $k3 => $v3, v4: $k4 => $v4, v5: $k5 => $v5, v6: $k6 => $v6, v7: $k7 => $v7, v8: $k8 => $v8, ) }; ($s:expr, $k1:expr => $v1:expr, $k2:expr => $v2:expr, $k3:expr => $v3:expr, $k4:expr => $v4:expr, $k5:expr => $v5:expr, $k6:expr => $v6:expr, $k7:expr => $v7:expr, $k8:expr => $v8:expr, $k9:expr => $v9:expr $(,)?) => { serialize_map_optional!( @internal $s, v1: $k1 => $v1, v2: $k2 => $v2, v3: $k3 => $v3, v4: $k4 => $v4, v5: $k5 => $v5, v6: $k6 => $v6, v7: $k7 => $v7, v8: $k8 => $v8, v9: $k9 => $v9, ) }; ($s:expr, $k1:expr => $v1:expr, $k2:expr => $v2:expr, $k3:expr => $v3:expr, $k4:expr => $v4:expr, $k5:expr => $v5:expr, $k6:expr => $v6:expr, $k7:expr => $v7:expr, $k8:expr => $v8:expr, $k9:expr => $v9:expr, $ka:expr => $va:expr, $( $value_ident:ident : $key:expr => $value:expr , )*) => { serialize_map_optional!( @internal $s, v1: $k1 => $v1, v2: $k2 => $v2, v3: $k3 => $v3, v4: $k4 => $v4, v5: $k5 => $v5, v6: $k6 => $v6, v7: $k7 => $v7, v8: $k8 => $v8, v9: $k9 => $v9, va: $ka => $va, $( $value_ident : $key => $value , )* ) }; (@internal $serializer:expr, $( $value_ident:ident : $key:expr => $value:expr , )*) => { { let serializer = $serializer; $( let $value_ident = $value; )* let map_len = 0usize $(+ if ::core::option::Option::is_some(&$value_ident) { 1usize } else { 0usize })*; let mut map = ::serde::ser::Serializer::serialize_map(serializer, ::core::option::Option::Some(map_len))?; $( if let ::core::option::Option::Some(v) = $value_ident { ::serde::ser::SerializeMap::serialize_entry(&mut map, $key, &v)?; } )* ::serde::ser::SerializeMap::end(map) } }; } /// Serialize a heterogeneous map in the order that entries appear. /// /// The macro automatically calculates the number of entries to allocate in the /// map, and closes the map. /// /// Arguments: /// - An expression of type [serde::Serializer]. This expression will be bound /// to a local variable and thus evaluated only once. /// - 0 or more entries of the form `$key => $value,`, where `$key` and `$value` /// are both expressions. Each key and value expression is evaluated only /// once. macro_rules! serialize_map { (@count_entry $value:expr) => { () }; ( $serializer:expr, $( $key:expr => $value:expr , )* ) => { { let serializer = $serializer; const MAP_LEN: usize = [$( serialize_map!(@count_entry $value) ),*].len(); let mut map = ::serde::ser::Serializer::serialize_map(serializer, ::core::option::Option::Some(MAP_LEN))?; $( ::serde::ser::SerializeMap::serialize_entry(&mut map, $key, $value)?; )* ::serde::ser::SerializeMap::end(map) } }; } #[cfg(test)] mod tests { mod serialize_map_optional { //! Test cases generated using the following Python snippet: //! ```python //! from fido2 import cbor //! cbor._sort_keys = lambda entry: 0 # Disable canonical CBOR map sorting //! c = cbor.encode({ //! 0x00: "a", //! "a" : 0x01, //! ("b",) : ["c"], //! ("c", "d") : ["d", "e"], //! -0x04 : "e", //! 0xff : "f", //! 0xffff : "g", //! 0xffffff : "h", //! 0xffffffff : "i", //! 0xffffffffffffffff : "i", //! 0x0a : -1337, //! 0x0b : 0xffffffffffffffff, //! }) //! print(c.hex()) //! ``` use super::super::decode_hex; use serde::{Serialize, Serializer}; #[test] fn serialize_map_optional_1() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => Some("a"), ) } } assert_eq!(serde_cbor::to_vec(&Foo).unwrap(), decode_hex("a1006161")); } #[test] fn serialize_map_optional_2() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => Some("a"), &"a" => Some(0x01), ) } } assert_eq!( serde_cbor::to_vec(&Foo).unwrap(), decode_hex("a2006161616101") ); } #[test] fn serialize_map_optional_3() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => Some("a"), &"a" => Some(0x01), &["b"] => Some(["c"]), ) } } assert_eq!( serde_cbor::to_vec(&Foo).unwrap(), decode_hex("a3006161616101816162816163") ); } #[test] fn serialize_map_optional_4() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => Some("a"), &"a" => Some(0x01), &["b"] => Some(["c"]), &["c", "d"] => Some(["d", "e"]), ) } } assert_eq!( serde_cbor::to_vec(&Foo).unwrap(), decode_hex("a400616161610181616281616382616361648261646165") ); } #[test] fn serialize_map_optional_5() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => Some("a"), &"a" => Some(0x01), &["b"] => Some(["c"]), &["c", "d"] => Some(["d", "e"]), &-0x04 => Some("e"), ) } } assert_eq!( serde_cbor::to_vec(&Foo).unwrap(), decode_hex("a500616161610181616281616382616361648261646165236165") ); } #[test] fn serialize_map_optional_6() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => Some("a"), &"a" => Some(0x01), &["b"] => Some(["c"]), &["c", "d"] => Some(["d", "e"]), &-0x04 => Some("e"), &0xff => Some("f"), ) } } assert_eq!( serde_cbor::to_vec(&Foo).unwrap(), decode_hex("a60061616161018161628161638261636164826164616523616518ff6166") ); } #[test] fn serialize_map_optional_7() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => Some("a"), &"a" => Some(0x01), &["b"] => Some(["c"]), &["c", "d"] => Some(["d", "e"]), &-0x04 => Some("e"), &0xff => Some("f"), &0xffff => Some("g"), ) } } assert_eq!( serde_cbor::to_vec(&Foo).unwrap(), decode_hex( "a70061616161018161628161638261636164826164616523616518ff616619ffff6167" ) ); } #[test] fn serialize_map_optional_8() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => Some("a"), &"a" => Some(0x01), &["b"] => Some(["c"]), &["c", "d"] => Some(["d", "e"]), &-0x04 => Some("e"), &0xff => Some("f"), &0xffff => Some("g"), &0xffffff => Some("h"), ) } } assert_eq!( serde_cbor::to_vec(&Foo).unwrap(), decode_hex("a80061616161018161628161638261636164826164616523616518ff616619ffff61671a00ffffff6168") ); } #[test] fn serialize_map_optional_9() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => Some("a"), &"a" => Some(0x01), &["b"] => Some(["c"]), &["c", "d"] => Some(["d", "e"]), &-0x04 => Some("e"), &0xff => Some("f"), &0xffff => Some("g"), &0xffffff => Some("h"), &0xffffffffu32 => Some("i"), ) } } assert_eq!( serde_cbor::to_vec(&Foo).unwrap(), decode_hex("a90061616161018161628161638261636164826164616523616518ff616619ffff61671a00ffffff61681affffffff6169") ); } #[test] fn serialize_map_optional_10() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => Some("a"), &"a" => Some(0x01), &["b"] => Some(["c"]), &["c", "d"] => Some(["d", "e"]), &-0x04 => Some("e"), &0xff => Some("f"), &0xffff => Some("g"), &0xffffff => Some("h"), &0xffffffffu32 => Some("i"), &0xffffffffffffffffu64 => Some("i"), ) } } assert_eq!( serde_cbor::to_vec(&Foo).unwrap(), decode_hex("aa0061616161018161628161638261636164826164616523616518ff616619ffff61671a00ffffff61681affffffff61691bffffffffffffffff6169") ); } #[test] fn serialize_map_optional_11() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => Some("a"), &"a" => Some(0x01), &["b"] => Some(["c"]), &["c", "d"] => Some(["d", "e"]), &-0x04 => Some("e"), &0xff => Some("f"), &0xffff => Some("g"), &0xffffff => Some("h"), &0xffffffffu32 => Some("i"), &0xffffffffffffffffu64 => Some("i"), v1: &0x0a => Some(-1337), ) } } assert_eq!( serde_cbor::to_vec(&Foo).unwrap(), decode_hex("ab0061616161018161628161638261636164826164616523616518ff616619ffff61671a00ffffff61681affffffff61691bffffffffffffffff61690a390538") ); } #[test] fn serialize_map_optional_12() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => Some("a"), &"a" => Some(0x01), &["b"] => Some(["c"]), &["c", "d"] => Some(["d", "e"]), &-0x04 => Some("e"), &0xff => Some("f"), &0xffff => Some("g"), &0xffffff => Some("h"), &0xffffffffu32 => Some("i"), &0xffffffffffffffffu64 => Some("i"), v1: &0x0a => Some(-1337), v2: &0x0b => Some(0xffffffffffffffffu64), ) } } assert_eq!( serde_cbor::to_vec(&Foo).unwrap(), decode_hex("ac0061616161018161628161638261636164826164616523616518ff616619ffff61671a00ffffff61681affffffff61691bffffffffffffffff61690a3905380b1bffffffffffffffff") ); } #[test] fn serialize_map_optional_12_first_v1_absent() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => None::, &"a" => Some(0x01), &["b"] => Some(["c"]), &["c", "d"] => Some(["d", "e"]), &-0x04 => Some("e"), &0xff => Some("f"), &0xffff => Some("g"), &0xffffff => Some("h"), &0xffffffffu32 => Some("i"), &0xffffffffffffffffu64 => Some("i"), v1: &0x0a => Some(-1337), v2: &0x0b => Some(0xffffffffffffffffu64), ) } } assert_eq!( serde_cbor::to_vec(&Foo).unwrap(), decode_hex("ab6161018161628161638261636164826164616523616518ff616619ffff61671a00ffffff61681affffffff61691bffffffffffffffff61690a3905380b1bffffffffffffffff") ); } #[test] fn serialize_map_optional_12_second_v1_absent() { struct Foo; impl Serialize for Foo { fn serialize(&self, serializer: S) -> Result { serialize_map_optional!( serializer, &0x00 => Some("a"), &"a" => Some(0x01), &["b"] => Some(["c"]), &["c", "d"] => Some(["d", "e"]), &-0x04 => Some("e"), &0xff => Some("f"), &0xffff => Some("g"), &0xffffff => Some("h"), &0xffffffffu32 => Some("i"), &0xffffffffffffffffu64 => Some("i"), v1: &0x0a => None::, v2: &0x0b => Some(0xffffffffffffffffu64), ) } } assert_eq!( serde_cbor::to_vec(&Foo).unwrap(), decode_hex("ab0061616161018161628161638261636164826164616523616518ff616619ffff61671a00ffffff61681affffffff61691bffffffffffffffff61690b1bffffffffffffffff") ); } } }