1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
#![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" |
//! |`"chrono-preview"`| a temporary feature that removes the use of deprecated APIs in `chrono` crate |
//! |`"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
//!
//! A raw u64 can be used as the descriptor code in the macro attribute. This is useful for defining types
//! that are not strictly compliant.
//!
//! ```
//! use serde_amqp::macros::{SerializeComposite, DeserializeComposite};
//!
//! #[derive(Debug, Clone, SerializeComposite, DeserializeComposite)]
//! #[amqp_contract(
//! name = "amqp:application-properties:map",
//! code = "0x000_0000_0000_0007" ,
//! encoding = "list",
//! rename_all = "kebab-case"
//! )]
//! pub struct Foo {
//! pub bar: String,
//! }
//! ```
//!
//! 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 size_ser;
pub mod value;
#[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 size_ser::serialized_size;
pub use value::{de::from_value, ser::to_value, Value};
#[cfg(feature = "derive")]
pub mod macros;
#[cfg(feature = "derive")]
pub use macros::{DeserializeComposite, SerializeComposite};