diff options
Diffstat (limited to 'vendor/ciborium/src/lib.rs')
-rw-r--r-- | vendor/ciborium/src/lib.rs | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/vendor/ciborium/src/lib.rs b/vendor/ciborium/src/lib.rs new file mode 100644 index 000000000..9696e5ffa --- /dev/null +++ b/vendor/ciborium/src/lib.rs @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! Welcome to Ciborium! +//! +//! Ciborium contains CBOR serialization and deserialization implementations for serde. +//! +//! # Quick Start +//! +//! You're probably looking for [`from_reader()`](crate::de::from_reader) +//! and [`into_writer()`](crate::ser::into_writer), which are +//! the main functions. Note that byte slices are also readers and writers and can be +//! passed to these functions just as streams can. +//! +//! For dynamic CBOR value creation/inspection, see [`Value`](crate::value::Value). +//! +//! # Design Decisions +//! +//! ## Always Serialize Numeric Values to the Smallest Size +//! +//! Although the CBOR specification has differing numeric widths, this is only +//! a form of compression on the wire and is not intended to directly +//! represent an "integer width" or "float width." Therefore, ciborium always +//! serializes numbers to the smallest possible lossless encoding. For example, +//! we serialize `1u128` as a single byte (`01`). Likewise, we will also freely +//! decode that single byte into a `u128`. +//! +//! While there is some minor performance cost for this, there are several +//! reasons for this choice. First, the specification seems to imply it by +//! using a separate bit for the sign. Second, the specification requires +//! that implementations handle leading zeroes; a liberal reading of which +//! implies a requirement for lossless coercion. Third, dynamic languages like +//! Python have no notion of "integer width," making this is a practical +//! choice for maximizing wire compatibility with those languages. +//! +//! This coercion is **always** lossless. For floats, this implies that we +//! only coerce to a smaller size if coercion back to the original size has +//! the same raw bits as the original. +//! +//! ## Compatibility with Other Implementations +//! +//! The ciborium project follows the [Robustness Principle](https://en.wikipedia.org/wiki/Robustness_principle). +//! Therefore, we aim to be liberal in what we accept. This implies that we +//! aim to be wire-compatible with other implementations in decoding, but +//! not necessarily encoding. +//! +//! One notable example of this is that `serde_cbor` uses fixed-width encoding +//! of numbers and doesn't losslessly coerce. This implies that `ciborium` will +//! successfully decode `serde_cbor` encodings, but the opposite may not be the +//! case. +//! +//! ## Representing Map as a Sequence of Values +//! +//! Other serde parsers have generally taken the route of using `BTreeMap` or +//! `HashMap` to implement their encoding's underlying `Map` type. This crate +//! chooses to represent the `Map` type using `Vec<(Value, Value)>` instead. +//! +//! This decision was made because this type preserves the order of the pairs +//! on the wire. Further, for those that need the properties of `BTreeMap` or +//! `HashMap`, you can simply `collect()` the values into the respective type. +//! This provides maximum flexibility. +//! +//! ## Low-level Library +//! +//! The ciborium crate has the beginnings of a low-level library in the +//! (private) `basic` module. We may extend this to be more robust and expose +//! it for application consumption once we have it in a good state. If you'd +//! like to collaborate with us on that, please contact us. Alternatively, +//! we might fork this code into a separate crate with no serde dependency. +//! +//! ## Internal Types +//! +//! The ciborium crate contains a number of internal types that implement +//! useful serde traits. While these are not currently exposed, we might +//! choose to expose them in the future if there is demand. Generally, this +//! crate takes a conservative approach to exposing APIs to avoid breakage. +//! +//! ## Packed Encoding? +//! +//! Packed encoding uses numerical offsets to represent structure field names +//! and enum variant names. This can save significant space on the wire. +//! +//! While the authors of this crate like packed encoding, it should generally +//! be avoided because it can be fragile as it exposes invariants of your Rust +//! code to remote actors. We might consider adding this in the future. If you +//! are interested in this, please contact us. + +#![cfg_attr(not(feature = "std"), no_std)] +#![deny(missing_docs)] +#![deny(clippy::all)] +#![deny(clippy::cargo)] +#![allow(clippy::unit_arg)] + +extern crate alloc; + +pub mod de; +pub mod ser; +pub mod tag; +pub mod value; + +// Re-export the [items recommended by serde](https://serde.rs/conventions.html). +#[doc(inline)] +pub use crate::de::from_reader; + +#[doc(inline)] +pub use crate::ser::into_writer; + +#[doc(inline)] +pub use crate::value::Value; + +/// Build a `Value` conveniently. +/// +/// The syntax should be intuitive if you are familiar with JSON. You can also +/// inline simple Rust expressions, including custom values that implement +/// `serde::Serialize`. Note that this macro returns `Result<Value, Error>`, +/// so you should handle the error appropriately. +/// +/// ``` +/// use ciborium::cbor; +/// +/// let value = cbor!({ +/// "code" => 415, +/// "message" => null, +/// "continue" => false, +/// "extra" => { "numbers" => [8.2341e+4, 0.251425] }, +/// }).unwrap(); +/// ``` +#[macro_export] +macro_rules! cbor { + (@map {$($key:expr => $val:expr),*} $(,)?) => {{ + $crate::value::Value::Map(vec![ + $( + (cbor!( $key )?, cbor!( $val )?) + ),* + ]) + }}; + + (@map {$($key:expr => $val:expr),*} { $($nkey:tt)* } => $($next:tt)*) => { + cbor!( + @map + { $($key => $val),* } + cbor!({ $($nkey)* })? => + $($next)* + ) + }; + + (@map {$($key:expr => $val:expr),*} [ $($nkey:tt)* ] => $($next:tt)*) => { + cbor!( + @map + { $($key => $val),* } + cbor!([ $($nkey)* ])? => + $($next)* + ) + }; + + (@map {$($key:expr => $val:expr),*} $nkey:expr => { $($nval:tt)* }, $($next:tt)*) => { + cbor!( + @map + { $($key => $val,)* $nkey => cbor!({ $($nval)* })? } + $($next)* + ) + }; + + (@map {$($key:expr => $val:expr),*} $nkey:expr => [ $($nval:tt)* ], $($next:tt)*) => { + cbor!( + @map + { $($key => $val,)* $nkey => cbor!([ $($nval)* ])? } + $($next)* + ) + }; + + (@map {$($key:expr => $val:expr),*} $nkey:expr => $nval:expr, $($next:tt)*) => { + cbor!( + @map + { $($key => $val,)* $nkey => cbor!($nval)? } + $($next)* + ) + }; + + (@seq [$($val:expr),*] $(,)?) => { + $crate::value::Value::Array( + vec![$( cbor!($val)? ),*] + ) + }; + + (@seq [$($val:expr),*] { $($item:tt)* }, $($next:tt)*) => { + cbor!( + @seq + [ $($val,)* cbor!({ $($item)* })? ] + $($next)* + ) + }; + + (@seq [$($val:expr),*] [ $($item:tt)* ], $($next:tt)*) => { + cbor!( + @seq + [ $($val,)* cbor!([ $($item)* ])? ] + $($next)* + ) + }; + + (@seq [$($val:expr),*] $item:expr, $($next:tt)*) => { + cbor!( + @seq + [ $($val,)* $item ] + $($next)* + ) + }; + + ({ $($next:tt)* }) => {(||{ + ::core::result::Result::<_, $crate::value::Error>::from(Ok(cbor!(@map {} $($next)* ,))) + })()}; + + ([ $($next:tt)* ]) => {(||{ + ::core::result::Result::<_, $crate::value::Error>::from(Ok(cbor!(@seq [] $($next)* ,))) + })()}; + + ($val:expr) => {{ + #[allow(unused_imports)] + use $crate::value::Value::Null as null; + $crate::value::Value::serialized(&$val) + }}; +} |