serde_amqp 0.5.2

A serde implementation of AMQP1.0 protocol.
Documentation
#![cfg_attr(docsrs, feature(doc_cfg))]
#![deny(missing_docs, missing_debug_implementations)]

//! A serde implementation of AMQP1.0 protocol and the primitive types.
//!
//! - [Documentation](https://docs.rs/serde_amqp)
//! - [Changelog](https://github.com/minghuaw/fe2o3-amqp/blob/main/serde_amqp/Changelog.md)
//!
//! # Serializing and deserializing data structures
//!
//! Any type that implement `serde::Serialize` and `serde::Deserialize` trait can be
//! serialized/deserialized with the following convenience functions
//!
//! Serialization:
//!
//! - [`to_vec`]
//! - [`serialized_size`]
//!
//! Deserialization:
//!
//! - [`from_slice`]
//! - [`from_reader`]
//!
//! # Primitive types
//!
//! All primitive types defined in AMQP1.0 protocol can be found in mod [primitives].
//!
//! # Described types
//!
//! AMQP1.0 specification allows annotating any AMQP type with a [`descriptor::Descriptor`], thus
//! creating a described type. Though this can be constructed using [`described::Described`] and
//! [`Value`], a much easier way to define a custom described type is to use the custom
//! [`SerializeComposite`] and [`DeserializeComposite`] derive macros. Please be aware that the
//! `"derive"` feature flag must be enabled.
//!
//! You can read more about how to use the derive macros in the corresponding
//! [section](#serializecomposite-and-deserializecomposite).
//!
//! # Untyped AMQP1.0 values
//!
//! Untyped AMQP1.0 values can be constructed as well as serialized/deserialized using [`Value`].
//!
//! ```rust
//! use serde_amqp::{
//!     SerializeComposite, DeserializeComposite, Value, to_vec, from_slice,
//!     described::Described, descriptor::Descriptor,
//! };
//!
//! #[derive(Debug, SerializeComposite, DeserializeComposite)]
//! #[amqp_contract(code = "0x00:0x13", encoding = "list")]
//! struct Foo(Option<bool>, Option<i32>);
//!
//! let foo = Foo(Some(true), Some(3));
//! let buf = to_vec(&foo).unwrap();
//! let value: Value = from_slice(&buf).unwrap();
//! let expected = Value::from(
//!     Described {
//!         descriptor: Descriptor::Code(0x13),
//!         value: Value::List(vec![
//!             Value::Bool(true),
//!             Value::Int(3)
//!         ])
//!     }
//! );
//! assert_eq!(value, expected);
//! ```
//!
//! Types that implements `serde::Serialize` and `serde::Deserialize` traits can also be converted
//! into/from [`Value`] using the [`to_value`] and [`from_value`] functions.
//!
//! # **WARNING** `enum`
//!
//! `enum` in serde data model can be categorized as below.
//!
//! ```rust
//! use serde::{Serialize, Deserialize};
//!
//! #[derive(Serialize, Deserialize)]
//! enum Enumeration {
//!     UnitVariant,
//!     NewTypeVariant(u32),
//!     TupleVariant(bool, u64, String),
//!     StructVariant { id: u32, is_true: bool },
//! }
//! ```
//!
//! AMQP1.0 protocol doesn't natively support `NewTypeVariant`, `TupleVariant` or `StructVariant`.
//! For the sake of completeness, serialization and deserialization for these variants are
//! implemented as follows:
//!
//! - `NewTypeVariant` is encoded/decoded as a map of one key-value pair with the variant index
//! being the key and the single wrapped field being the value.
//! - `TupleVariant` is encoded/decoded as a map of one key-value pair with the varant index being
//! the key and a list of the fields being the value.
//! - `StructVariant` is encoded/decoded as a map of one key-value pair with the variant index being
//! the key and a list of the fields being the value.
//!
//! # Feature flag
//!
//! ```toml
//! default = []
//! ```
//!
//! | Feature | Description |
//! |---------|-------------|
//! |`"derive"`| enables [`SerializeComposite` and `DeserializeComposite`](#serializecomposite-and-deserializecomposite) |
//! |`"extensions"`| enables `extensions` mod (see [Extensions](#extensions)), added since "0.4.5" |
//! |`"time"`| enables conversion of `Timestamp` from/to `time::Duration` and `time::OffsetDateTime`, added since "0.5.1" |
//! |`"chrono"`| enables conversion of `Timestamp` from/to `chrono::Duration` and `chrono::DateTime`, added since "0.5.1" |
//! |`"uuid"`| enables conversion of `Uuid` from/to `uuid::Uuid`, added since "0.5.1" |
//!
//! ## `SerializeComposite` and `DeserializeComposite`
//!
//! The macro provides three types of encodings:
//!
//! 1. `"list"`: The struct will be serialized as a described list. A described list is an AMQP1.0
//!    list with its descriptor prepended to the list itself. The deserialization will take either
//!    the `"list"` or the `"map"` encoded values.
//! 2. `"map"`: The struct will be serialized as a described map. A described map is an AMQP1.0 map
//!    with its descriptor prepended to the map. The deserialization will take either the `"list"`
//!    or the `"map"` encoded values.
//! 3. `"basic"`: The struct must be a thin wrapper (containing only one field) over another
//!    serializable/deserializable type. The inner struct will be serialized/deserialized with the
//!    descriptor prepended to the struct.
//!
//! ### Details with the `"list"` encoding
//!
//! Optinal fields
//!
//! If a field is not marked with `"mandatory"` in the specification, the field can be an `Option`.
//! During serialization, the optional fields may be skipped completely or encoded as an AMQP1.0
//! `null` primitive (`0x40`). During deserialization, an AMQP1.0 `null` primitive or an empty field
//! will be decoded as a `None`.
//!
//! Fields with default values:
//!
//! For fields that have default values defined in the specification, the field type must implement
//! both the `Default` and `PartialEq` trait. During serialization, if the field is equal to the
//! default value of the field type, the field will be either ignored completely or encoded as an
//! AMQP1.0 `null` primitive (`0x40`). During deserialization, an AMQP1.0 `null` primitive or an
//! empty field will be decoded as the default value of the type.
//!
//! ## Example of the derive macros
//!
//! The `"list"` encoding will encode the `Attach` struct as a described list (a descriptor followed
//! by a list of the fields).
//!
//! ```rust, ignore
//! /// 2.7.3 Attach
//! /// Attach a link to a session.
//! /// <type name="attach" class="composite" source="list" provides="frame">
//! ///     <descriptor name="amqp:attach:list" code="0x00000000:0x00000012"/>
//! #[derive(Debug, DeserializeComposite, SerializeComposite)]
//! #[amqp_contract(
//!     name = "amqp:attach:list",
//!     code = "0x0000_0000:0x0000_0012",
//!     encoding = "list",
//!     rename_all = "kebab-case"
//! )]
//! pub struct Attach {
//!     /// <field name="name" type="string" mandatory="true"/>
//!     pub name: String,
//!
//!     /// <field name="handle" type="handle" mandatory="true"/>
//!     pub handle: Handle,
//!
//!     /// <field name="role" type="role" mandatory="true"/>
//!     pub role: Role,
//!
//!     /// <field name="snd-settle-mode" type="sender-settle-mode" default="mixed"/>
//!     #[amqp_contract(default)]
//!     pub snd_settle_mode: SenderSettleMode,
//!
//!     /// <field name="rcv-settle-mode" type="receiver-settle-mode" default="first"/>
//!     #[amqp_contract(default)]
//!     pub rcv_settle_mode: ReceiverSettleMode,
//!
//!     /// <field name="source" type="*" requires="source"/>
//!     pub source: Option<Source>,
//!
//!     /// <field name="target" type="*" requires="target"/>
//!     pub target: Option<Target>,
//!
//!     /// <field name="unsettled" type="map"/>
//!     pub unsettled: Option<BTreeMap<DeliveryTag, DeliveryState>>,
//!
//!     /// <field name="incomplete-unsettled" type="boolean" default="false"/>
//!     #[amqp_contract(default)]
//!     pub incomplete_unsettled: Boolean,
//!
//!     /// <field name="initial-delivery-count" type="sequence-no"/>
//!     pub initial_delivery_count: Option<SequenceNo>,
//!
//!     /// <field name="max-message-size" type="ulong"/>
//!     pub max_message_size: Option<ULong>,
//!
//!     /// <field name="offered-capabilities" type="symbol" multiple="true"/>
//!     pub offered_capabilities: Option<Array<Symbol>>,
//!
//!     /// <field name="desired-capabilities" type="symbol" multiple="true"/>
//!     pub desired_capabilities: Option<Array<Symbol>>,
//!
//!     /// <field name="properties" type="fields"/>
//!     pub properties: Option<Fields>,
//! }
//! ```
//!
//! ```rust,ignore
//! /// 3.2.5 Application Properties
//! /// <type name="application-properties" class="restricted" source="map" provides="section">
//! ///     <descriptor name="amqp:application-properties:map" code="0x00000000:0x00000074"/>
//! /// </type>
//! #[derive(Debug, Clone, SerializeComposite, DeserializeComposite)]
//! #[amqp_contract(
//!     name = "amqp:application-properties:map",
//!     code = "0x0000_0000:0x0000_0074",
//!     encoding = "basic"
//! )]
//! pub struct ApplicationProperties(pub OrderedMap<String, SimpleValue>);
//! ```
//!
//! ## Extensions
//!
//! The following type(s) are provided in the `extensions` mod and require the `extensions` feature
//!
//! 1. `TransparentVec` - a thin wrapper around `Vec` that is serialized/deserialized as a sequence
//!    of elements `Vec` is treated as an AMQP `List` in the core spec

// Public mods
pub mod de;
pub mod described;
pub mod descriptor;
pub mod error;
pub mod fixed_width;
pub mod format_code;
pub mod primitives;
pub mod read;
pub mod ser;
pub mod value;
pub mod size_ser;

#[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
#[cfg(feature = "extensions")]
pub mod extensions;

// Private mod but is used by derive macros
// This is to avoid accidental misuse
#[doc(hidden)]
#[path = "constants.rs"]
pub mod __constants;

// Private mods
mod util;

// experimental
mod format;

pub use serde;

pub use de::{from_reader, from_slice};
pub use error::Error;
pub use ser::to_vec;
pub use value::{de::from_value, ser::to_value, Value};
pub use size_ser::serialized_size;

#[cfg(feature = "derive")]
pub mod macros;
#[cfg(feature = "derive")]
pub use macros::{DeserializeComposite, SerializeComposite};