Skip to main content

decoder/
lib.rs

1//! A decoder library for your types.
2//!
3//! When using [`serde`], your types become entangled with serialization logic due to the [`Serialize`] and [`Deserialize`] traits.
4//!
5//! This crate lets you decouple serialization logic by leveraging simple functions, at some performance cost:
6//!
7//! ```rust,no_run
8//! use decoder::{Map, Result, Value};
9//!
10//! struct Person {
11//!     name: String,
12//!     projects: Vec<Project>
13//! }
14//!
15//! struct Project {
16//!     name: String,
17//!     url: String,
18//! }
19//!
20//! impl Person {
21//!     fn decode(value: Value) -> Result<Self> {
22//!         use decoder::decode::{map, sequence, string};
23//!
24//!         let mut person = map(value)?;
25//!
26//!         Ok(Self {
27//!             name: person.required("name", string)?,
28//!             projects: person.required("projects", sequence(Project::decode))?,
29//!         })
30//!     }
31//!
32//!     fn encode(&self) -> Value {
33//!         use decoder::encode::{map, sequence, string};
34//!
35//!         map([
36//!             ("name", string(&self.name)),
37//!             ("projects", sequence(Project::encode, &self.projects)),
38//!         ])
39//!         .into()
40//!     }
41//! }
42//!
43//! impl Project {
44//!     fn decode(value: Value) -> Result<Self> {
45//!         use decoder::decode::{map, string};
46//!
47//!         let mut project = map(value)?;
48//!
49//!         Ok(Project {
50//!             name: project.required("name", string)?,
51//!             url: project.required("url", string)?
52//!         })
53//!     }
54//!
55//!     fn encode(&self) -> Value {
56//!         use decoder::encode::{map, string};
57//!
58//!         map([
59//!             ("name", string(&self.name)),
60//!             ("url", string(&self.url)),
61//!         ])
62//!         .into()
63//!     }
64//! }
65//!
66//! let person =
67//!    decoder::run(serde_json::from_str, Person::decode, "{ ... }").expect("Decode person");
68//!
69//! let _ = serde_json::to_string(&person.encode());
70//! ```
71//!
72//! You can try this crate if the [`serde`] way™ has become painful or it does not resonate with you.
73//!
74//! [`serde`]: https://serde.rs
75//! [`Serialize`]: https://docs.rs/serde/latest/serde/trait.Serialize.html
76//! [`Deserialize`]: https://docs.rs/serde/latest/serde/trait.Deserialize.html
77pub mod decode;
78pub mod encode;
79
80mod error;
81mod value;
82
83pub use error::Error;
84pub use value::{Map, Value};
85
86/// A decoding result.
87pub type Result<T> = std::result::Result<T, Error>;
88
89/// Some logic that turns a [`Value`] into some [`Output`](Self::Output).
90pub trait Decoder {
91    /// The output of the [`Decoder`].
92    type Output;
93
94    /// Runs the [`Decoder`].
95    fn run(&self, value: Value) -> Result<Self::Output>;
96}
97
98impl<F, T> Decoder for F
99where
100    F: Fn(Value) -> Result<T>,
101{
102    type Output = T;
103
104    fn run(&self, value: Value) -> Result<T> {
105        self(value)
106    }
107}
108
109/// Runs a [`Decoder`] using the given function to deserialize a [`Value`]
110/// from the given input.
111pub fn run<T, I, E>(
112    deserialize: impl Fn(I) -> std::result::Result<Value, E>,
113    decoder: impl Decoder<Output = T>,
114    input: I,
115) -> Result<T>
116where
117    E: std::error::Error + Send + Sync + 'static,
118{
119    decoder.run(deserialize(input).map_err(Error::deserializer)?)
120}