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
#![deny(missing_docs, missing_debug_implementations)]

//! A serde implementation of AMQP1.0 protocol.
//!
//! # 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`]
//!
//! 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 = 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
//!
//! - `"derive"`: enables custom derive macros: `SerializeComposite` and `DeserializeComposite`.
//!
//! ## `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_0000_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_0000_0074,
//!     encoding = "basic"
//! )]
//! pub struct ApplicationProperties(pub BTreeMap<String, SimpleValue>);
//! ```

// 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;

// 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};

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