serde_lite/
lib.rs

1//! This library provides a bit more lightweight implementation (compared to Serde)
2//! of general-purpose serialization and de-serialization. **The intention here is
3//! not to replace Serde completely** though. Serde does an amazing job and it
4//! wouldn't make much sense to compete with Serde in terms of
5//! serialization/de-serialization speed and the amount of memory used in runtime.
6//!
7//! We focus mainly on the one thing where Serde can be a pain in the... code :) -
8//! and it's the size of the resulting binary. Depending on the complexity of the
9//! types that you try to serialize/de-serialize, Serde can produce quite a lot of
10//! code. Plus there is also some monomorphization which may add even more code to
11//! your binary.
12//!
13//! In order to achieve it's goal, this library does some assumptions about the
14//! underlying format. It uses an intermediate data representation that is similar
15//! to JSON. The intermediate format can be then serialized/deserialized using
16//! Serde. This implies that this library will never be as fast as Serde itself.
17//!
18//! # Usage
19//!
20//! You can use this library as a drop-in replacement for Serde. There are
21//! `Serialize` and `Deserialize` traits that can be automatically derived and
22//! there are also some attributes (compatible with Serde), so all you really have
23//! to do is to put `serde-lite` instead of `serde` into your `Cargo.toml`.
24//!
25//! ## Serialization
26//!
27//! Here is a brief example of serialization into JSON:
28//! ```rust
29//! use serde_lite::Serialize;
30//! use serde_lite_derive::Serialize;
31//!
32//! #[derive(Serialize)]
33//! struct MyStruct {
34//!     field1: u32,
35//!     field2: String,
36//! }
37//!
38//! let instance = MyStruct {
39//!     field1: 10,
40//!     field2: String::from("Hello, World!"),
41//! };
42//!
43//! let intermediate = instance.serialize().unwrap();
44//! let json = serde_json::to_string_pretty(&intermediate).unwrap();
45//! ```
46//!
47//! ## De-serialization
48//!
49//! Here is a brief example of de-serialization from JSON:
50//! ```rust
51//! use serde_lite::Deserialize;
52//! use serde_lite_derive::Deserialize;
53//!
54//! #[derive(Deserialize)]
55//! struct MyStruct {
56//!     field1: u32,
57//!     field2: String,
58//! }
59//!
60//! let input = r#"{
61//!     "field1": 10,
62//!     "field2": "Hello, World!"
63//! }"#;
64//!
65//! let intermediate = serde_json::from_str(input).unwrap();
66//! let instance = MyStruct::deserialize(&intermediate).unwrap();
67//! ```
68//!
69//! ## Update
70//!
71//! Wait. What? Yes, this library has one more cool feature - partial updates.
72//! Simply derive `Update` the same way you'd derive `Deserialize`. Example:
73//! ```rust
74//! use serde_lite::{Deserialize, Update};
75//! use serde_lite_derive::{Deserialize, Update};
76//!
77//! #[derive(Deserialize, Update)]
78//! struct MyStruct {
79//!     field1: u32,
80//!     field2: String,
81//! }
82//!
83//! let mut instance = MyStruct {
84//!     field1: 10,
85//!     field2: String::new(),
86//! };
87//!
88//! let input = r#"{
89//!     "field2": "Hello, World!"
90//! }"#;
91//!
92//! let intermediate = serde_json::from_str(input).unwrap();
93//! let instance = instance.update(&intermediate).unwrap();
94//! ```
95//!
96//! This feature can be especially handy if you're constructing a REST API and
97//! you'd like to allow partial updates of your data.
98//!
99//! ## Supported attributes
100//!
101//! The library does not support all Serde attributes at this moment. Patches are
102//! definitely welcome. These attributes are supported:
103//!
104//! * Container attributes:
105//!     * `tag`
106//!     * `content`
107//! * Field attributes:
108//!     * `default`
109//!     * `flatten`
110//!     * `rename`
111//!     * `skip`
112//!     * `skip_serializing`
113//!     * `skip_serializing_if`
114//!     * `skip_deserializing`
115//!     * `serialize_with`
116//!     * `deserialize_with`
117//!     * `update_with`
118//! * Enum variant attributes:
119//!     * `rename`
120//!
121//! # When to use this library
122//!
123//! You can use this library whenever you need to serialize/de-serialize some
124//! complex types and the size of the resulting binary matters to you. It is also
125//! very useful in projects where you need to be able to partially update your data
126//! based on the user input (e.g. REST APIs).
127//!
128//! # When to avoid using this library
129//!
130//! If the only thing that matters to you is the runtime performance, you probably
131//! don't want to use this library. It also isn't very useful for
132//! serializing/de-serializing huge amount of data because it needs to be
133//! transformed into the intermediate representation at first. And, finally, this
134//! library can only be used with self-describing formats like JSON.
135
136mod deserialize;
137mod intermediate;
138mod map;
139mod serialize;
140mod update;
141
142use std::{
143    borrow::Cow,
144    collections::LinkedList,
145    fmt::{self, Display, Formatter},
146};
147
148#[cfg(feature = "derive")]
149pub use serde_lite_derive::{Deserialize, Serialize, Update};
150
151pub use crate::{
152    deserialize::Deserialize,
153    intermediate::{Intermediate, Number},
154    map::{Map, MapImpl},
155    serialize::Serialize,
156    update::Update,
157};
158
159/// Error.
160#[derive(Debug, Clone)]
161pub enum Error {
162    OutOfBounds,
163    UnsupportedConversion,
164    MissingField,
165    UnknownEnumVariant,
166    MissingEnumVariantContent,
167    InvalidValue(Cow<'static, str>),
168    NamedFieldErrors(ErrorList<NamedFieldError>),
169    UnnamedFieldErrors(ErrorList<UnnamedFieldError>),
170    Custom(Cow<'static, str>),
171}
172
173impl Error {
174    /// Create an invalid value error with a given expected type name.
175    #[inline]
176    pub fn invalid_value<T>(expected: T) -> Self
177    where
178        T: ToString,
179    {
180        Self::InvalidValue(Cow::Owned(expected.to_string()))
181    }
182
183    /// Create an invalid value error with a given expected type name.
184    #[inline]
185    pub const fn invalid_value_static(expected: &'static str) -> Self {
186        Self::InvalidValue(Cow::Borrowed(expected))
187    }
188
189    /// Create a custom error with a given error message.
190    #[inline]
191    pub fn custom<T>(msg: T) -> Self
192    where
193        T: ToString,
194    {
195        Self::Custom(Cow::Owned(msg.to_string()))
196    }
197
198    /// Create a custom error with a given error message.
199    #[inline]
200    pub const fn custom_static(msg: &'static str) -> Self {
201        Self::Custom(Cow::Borrowed(msg))
202    }
203}
204
205impl Display for Error {
206    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
207        match self {
208            Self::OutOfBounds => f.write_str("value is out of bounds"),
209            Self::UnsupportedConversion => f.write_str("conversion not supported"),
210            Self::MissingField => f.write_str("missing field"),
211            Self::UnknownEnumVariant => f.write_str("unknown enum variant"),
212            Self::MissingEnumVariantContent => f.write_str("missing enum variant content"),
213            Self::InvalidValue(expected) => write!(f, "invalid value ({} expected)", expected),
214            Self::NamedFieldErrors(errors) => {
215                write!(f, "field errors ({})", errors)
216            }
217            Self::UnnamedFieldErrors(errors) => {
218                write!(f, "field errors ({})", errors)
219            }
220            Self::Custom(msg) => f.write_str(msg),
221        }
222    }
223}
224
225impl std::error::Error for Error {}
226
227impl From<ErrorList<NamedFieldError>> for Error {
228    #[inline]
229    fn from(errors: ErrorList<NamedFieldError>) -> Self {
230        Self::NamedFieldErrors(errors)
231    }
232}
233
234impl From<NamedFieldError> for Error {
235    #[inline]
236    fn from(err: NamedFieldError) -> Self {
237        let mut errors = ErrorList::new();
238
239        errors.push(err);
240
241        Self::from(errors)
242    }
243}
244
245impl From<ErrorList<UnnamedFieldError>> for Error {
246    #[inline]
247    fn from(errors: ErrorList<UnnamedFieldError>) -> Self {
248        Self::UnnamedFieldErrors(errors)
249    }
250}
251
252impl From<UnnamedFieldError> for Error {
253    #[inline]
254    fn from(err: UnnamedFieldError) -> Self {
255        let mut errors = ErrorList::new();
256
257        errors.push(err);
258
259        Self::from(errors)
260    }
261}
262
263/// Error associated with a named field.
264#[derive(Debug, Clone)]
265pub struct NamedFieldError {
266    field: Cow<'static, str>,
267    error: Error,
268}
269
270impl NamedFieldError {
271    /// Create a new error for a given named field.
272    #[inline]
273    pub fn new<T>(field: T, error: Error) -> Self
274    where
275        T: ToString,
276    {
277        Self {
278            field: Cow::Owned(field.to_string()),
279            error,
280        }
281    }
282
283    /// Create a new error for a given named field.
284    #[inline]
285    pub const fn new_static(field: &'static str, error: Error) -> Self {
286        Self {
287            field: Cow::Borrowed(field),
288            error,
289        }
290    }
291
292    /// Get the name of the field.
293    #[inline]
294    pub fn field(&self) -> &str {
295        &self.field
296    }
297
298    /// Get the error.
299    #[inline]
300    pub fn error(&self) -> &Error {
301        &self.error
302    }
303
304    /// Take the error.
305    #[inline]
306    pub fn into_error(self) -> Error {
307        self.error
308    }
309}
310
311impl Display for NamedFieldError {
312    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
313        write!(f, "{}: {}", self.field, self.error)
314    }
315}
316
317impl std::error::Error for NamedFieldError {}
318
319/// Error associated with an unnamed field.
320#[derive(Debug, Clone)]
321pub struct UnnamedFieldError {
322    index: usize,
323    error: Error,
324}
325
326impl UnnamedFieldError {
327    /// Create a new error for a given field.
328    #[inline]
329    pub const fn new(field_index: usize, error: Error) -> Self {
330        Self {
331            index: field_index,
332            error,
333        }
334    }
335
336    /// Get index of the field.
337    #[inline]
338    pub fn field_index(&self) -> usize {
339        self.index
340    }
341
342    /// Get the error.
343    #[inline]
344    pub fn error(&self) -> &Error {
345        &self.error
346    }
347
348    /// Take the error.
349    #[inline]
350    pub fn into_error(self) -> Error {
351        self.error
352    }
353}
354
355impl Display for UnnamedFieldError {
356    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
357        write!(f, "{}: {}", self.index, self.error)
358    }
359}
360
361impl std::error::Error for UnnamedFieldError {}
362
363/// List of errors.
364#[derive(Debug, Clone)]
365pub struct ErrorList<T> {
366    inner: LinkedList<T>,
367}
368
369impl<T> ErrorList<T> {
370    /// Create a new error list.
371    #[inline]
372    pub const fn new() -> Self {
373        Self {
374            inner: LinkedList::new(),
375        }
376    }
377
378    /// Check if the list is empty.
379    #[inline]
380    pub fn is_empty(&self) -> bool {
381        self.inner.is_empty()
382    }
383
384    /// Get length of the list.
385    #[inline]
386    pub fn len(&self) -> usize {
387        self.inner.len()
388    }
389
390    /// Add a given error to the list.
391    #[inline]
392    pub fn push(&mut self, err: T) {
393        self.inner.push_back(err)
394    }
395
396    /// Append a given list of errors to the current one.
397    #[inline]
398    pub fn append(&mut self, mut other: Self) {
399        self.inner.append(&mut other.inner)
400    }
401
402    /// Iterate over the errors.
403    #[inline]
404    pub fn iter(&self) -> std::collections::linked_list::Iter<'_, T> {
405        self.inner.iter()
406    }
407}
408
409impl<T> Default for ErrorList<T> {
410    #[inline]
411    fn default() -> Self {
412        Self::new()
413    }
414}
415
416impl<'a, T> IntoIterator for &'a ErrorList<T> {
417    type Item = &'a T;
418    type IntoIter = std::collections::linked_list::Iter<'a, T>;
419
420    #[inline]
421    fn into_iter(self) -> Self::IntoIter {
422        self.inner.iter()
423    }
424}
425
426impl<T> IntoIterator for ErrorList<T> {
427    type Item = T;
428    type IntoIter = std::collections::linked_list::IntoIter<T>;
429
430    #[inline]
431    fn into_iter(self) -> Self::IntoIter {
432        self.inner.into_iter()
433    }
434}
435
436impl<T> Display for ErrorList<T>
437where
438    T: Display,
439{
440    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
441        let mut iter = self.iter();
442
443        if let Some(first) = iter.next() {
444            Display::fmt(first, f)?;
445        }
446
447        for err in iter {
448            write!(f, ", {}", err)?;
449        }
450
451        Ok(())
452    }
453}
454
455impl<T> std::error::Error for ErrorList<T> where T: std::error::Error {}