Skip to main content

deser_json/
lib.rs

1//! Parse and serialize JSON compatible with deser.
2//!
3//! This library is very bare bones at this point and not at all optimized.  It is
4//! based on microserde which in turn is based on miniserde to achieve the most
5//! minimal implementation of a serializer and serializer.
6//!
7//! ```rust
8//! let vec: Vec<u64> = deser_json::from_str("[1, 2, 3, 4]").unwrap();
9//! let json = deser_json::to_string(&vec).unwrap();
10//! assert_eq!(json, "[1,2,3,4]");
11//! ```
12//!
13//! Besides strings, JSON can also be parsed from byte slices with
14//! [`from_slice`].  In that case the input is validated as UTF-8 while it is
15//! parsed rather than upfront:
16//!
17//! ```rust
18//! let vec: Vec<String> = deser_json::from_slice(b"[\"a\", \"b\"]").unwrap();
19//! assert_eq!(vec, ["a", "b"]);
20//! assert!(deser_json::from_slice::<String>(b"\"\xff\"").is_err());
21//! ```
22//!
23//! Integers that do not fit into 64 bits as well as the well-known
24//! [`BigInt`](deser_core::ext::BigInt), [`Decimal`](deser_core::ext::Decimal) and
25//! [`Number`](deser_core::ext::Number) types are written as JSON numbers.  Other
26//! well-known types (such as date-times and UUIDs) are written as strings.
27//! JSON has no bytes, they are written as base64 strings by default and
28//! types that expect bytes accept strings and arrays of integers (see
29//! [bytes](deser_core::adapters#bytes), the format can be configured in the
30//! [`Context`](deser_core::Context) with a [`BytesFormat`](deser_core::BytesFormat)).  Floats
31//! are written with the shortest text that reads back as the same value of
32//! their precision (`0.1f32` as `0.1`, not `0.10000000149011612`), floats
33//! that are infinite or NaN as `null`.
34//!
35//! When parsing, floats whose text cannot be recovered from their value as
36//! `f64` (like `0.10` or `1e5`) and integers that do not fit into 128 bits
37//! are passed on as [`Number`](deser_core::ext::Number) which carries the text of
38//! the number and its value as `f64`.  Types like `f64` get the value, types
39//! which deserialize decimal numbers exactly (like
40//! [`Decimal`](deser_core::ext::Decimal)) use the text.  See
41//! [`DeserializerConfig::set_exact_numbers`].
42//!
43//! Strings without escape sequences are borrowed from the input, so types
44//! can borrow them:
45//!
46//! ```rust
47//! #[derive(deser::Deserialize)]
48//! struct User<'a> {
49//!     name: &'a str,
50//! }
51//!
52//! let user: User = deser_json::from_str(r#"{"name": "Peter"}"#).unwrap();
53//! assert_eq!(user.name, "Peter");
54//! ```
55//!
56//! # Raw Values
57//!
58//! [`RawJson`] holds the JSON text of a value.  The JSON of values that are
59//! deserialized from JSON is kept as it is: it's validated but not
60//! deserialized, which is faster, and written out again unchanged.  With
61//! the [`Borrowed`](deser_core::adapters::Borrowed) adapter the text is
62//! borrowed from the input:
63//!
64//! ```rust
65//! use std::collections::BTreeMap;
66//! use deser::adapters::Borrowed;
67//! use deser_json::RawJson;
68//!
69//! #[derive(deser::Deserialize, deser::Serialize)]
70//! struct Envelope<'a> {
71//!     kind: String,
72//!     #[deser(as = Borrowed)]
73//!     payload: RawJson<'a>,
74//! }
75//!
76//! let input = r#"{"kind": "point", "payload": {"x": 1.50, "y": 2}}"#;
77//! let envelope: Envelope = deser_json::from_str(input).unwrap();
78//! assert_eq!(envelope.payload.get(), r#"{"x": 1.50, "y": 2}"#);
79//!
80//! // deserialized later, once it's known what it is
81//! let point: BTreeMap<String, f64> = envelope.payload.deserialize().unwrap();
82//! assert_eq!(point["x"], 1.5);
83//!
84//! // and written out again unchanged
85//! assert_eq!(
86//!     deser_json::to_string(&envelope).unwrap(),
87//!     r#"{"kind":"point","payload":{"x": 1.50, "y": 2}}"#
88//! );
89//! ```
90//!
91//! The text is only kept for values in places where the type is known
92//! before the value starts: fields of derived structs, standard containers,
93//! `Option` and `Box`.  Everywhere else (like the fields of untagged enums)
94//! and for values of other formats (including the other JSON dialects) the
95//! value is encoded as JSON.  Other formats serialize the value a
96//! [`RawJson`] holds.  See [`Raw`](deser_core::ext::Raw) for more
97//! information.
98//!
99//! # Pretty Printing
100//!
101//! By default the output is compact.  [`SerializerConfig::set_pretty`] indents
102//! it and writes spaces after separators:
103//!
104//! ```rust
105//! use deser_json::{Indent, SerializerConfig};
106//!
107//! const PRETTY: SerializerConfig =
108//!     SerializerConfig::builder().pretty(Indent::Spaces(2)).build();
109//! let json = PRETTY.to_string(&vec![vec![1, 2]]).unwrap();
110//! assert_eq!(json, "[\n  [\n    1,\n    2\n  ]\n]");
111//! ```
112//!
113//! Indentation and spaces can also be configured on their own with
114//! [`SerializerConfig::set_indent`] and [`SerializerConfig::set_compact`].  Maps
115//! and sequences with the [`Layout::Compact`](deser_core::hints::Layout) hint
116//! are written on a single line in indented output, short ones that only
117//! contain scalars can be too (see [`SerializerConfig::set_inline`]).
118//!
119//! # JSON Lines
120//!
121//! By default only whitespace may follow a value.  What may follow is
122//! controlled by [`DeserializerConfig::set_trailing`] (see [`Trailing`]).  With
123//! [`Trailing::Newline`] a [`Deserializer`] reads
124//! [JSON Lines](https://jsonlines.org/) (also known as NDJSON) one by one:
125//!
126//! ```rust
127//! use deser_json::{Deserializer, DeserializerConfig, Trailing};
128//!
129//! let config = DeserializerConfig::builder().trailing(Trailing::Newline).build();
130//! let mut de = Deserializer::from_str_with_config("[1, 2]\n[3]\n", config);
131//! let lines = de.iter::<Vec<u32>>().collect::<Result<Vec<_>, _>>().unwrap();
132//! assert_eq!(lines, [vec![1, 2], vec![3]]);
133//! ```
134//!
135//! Errors only discard their line, so the remaining lines can still be
136//! read.  [`Trailing::Stop`] stops after the value without looking at what
137//! follows.  JSON Lines are written with a [`Serializer`] and
138//! [`SerializerConfig::set_trailing`]:
139//!
140//! ```rust
141//! use deser_json::{Serializer, SerializerConfig, Trailing};
142//!
143//! const LINES: SerializerConfig =
144//!     SerializerConfig::builder().trailing(Trailing::Newline).build();
145//! let mut serializer = Serializer::with_config(LINES);
146//! for value in [vec![1, 2], vec![3]] {
147//!     serializer.serialize(&value).unwrap();
148//! }
149//! assert_eq!(serializer.finish(), "[1,2]\n[3]\n");
150//! ```
151//!
152//! # Streams
153//!
154//! Values are read from a [`Read`](std::io::Read) with [`from_reader`]
155//! and written to a [`Write`](std::io::Write) with [`to_writer`].  To read
156//! or write more than one value (for instance JSON Lines from a socket) the
157//! configurations create readers and writers of
158//! [`deser::io`](deser_core::io) ([`DeserializerConfig::reader`] and
159//! [`SerializerConfig::writer`]).  How values are separated depends on the
160//! `trailing` setting of the configurations (see [`Trailing`]).  The reader
161//! only buffers until a value is complete:
162//!
163//! ```rust
164//! # #[cfg(feature = "io")] {
165//! use std::collections::BTreeMap;
166//! use deser_json::{DeserializerConfig, SerializerConfig, Trailing};
167//!
168//! const READ_LINES: DeserializerConfig =
169//!     DeserializerConfig::builder().trailing(Trailing::Newline).build();
170//! const WRITE_LINES: SerializerConfig =
171//!     SerializerConfig::builder().trailing(Trailing::Newline).build();
172//!
173//! let input = &b"{\"id\": 1}\n{\"id\": 2}\n"[..];
174//! let mut reader = READ_LINES.reader(input);
175//! let mut writer = WRITE_LINES.writer(Vec::new());
176//! while let Some(value) = reader.read::<BTreeMap<String, u32>>().unwrap() {
177//!     writer.write(&value).unwrap();
178//! }
179//! assert_eq!(writer.into_inner(), b"{\"id\":1}\n{\"id\":2}\n");
180//! # }
181//! ```
182//!
183//! The stream serializer ([`Serializer`]) and the stream deserializer
184//! ([`StreamDeserializer`]) do not do IO themselves (see
185//! [`deser::stream`](deser_core::stream)), they also work with other kinds
186//! of IO (for instance async runtimes with `deser-tokio`) and without the
187//! standard library.
188//!
189//! # Features
190//!
191//! * `io` (enabled by default): reading and writing streams of the
192//!   standard library, see [streams](#streams).  Requires `std`.
193//! * `speedups` (enabled by default): uses
194//!   [`simdutf8`](https://docs.rs/simdutf8) to validate UTF-8 when parsing
195//!   byte slices.
196//! * `std` (enabled by default): uses the standard library.  Without it
197//!   this crate only needs `alloc` (see [`no_std`](https://docs.rs/deser/latest/deser/#no_std)).
198#![doc(html_logo_url = "https://raw.githubusercontent.com/mitsuhiko/deser/main/artwork/logo.svg")]
199#![cfg_attr(not(any(feature = "std", test)), no_std)]
200
201extern crate alloc;
202
203mod buf;
204mod escape;
205mod pretty;
206mod ser;
207mod trailing;
208
209// These are generated from `deser-template-json`.
210mod copy;
211mod de;
212mod parser;
213mod raw;
214mod scan;
215mod stream;
216
217pub use self::de::{
218    Deserializer, DeserializerConfig, DeserializerConfigBuilder, Iter, from_slice, from_str,
219};
220pub use self::raw::{Json, RawJson};
221#[cfg(feature = "io")]
222pub use self::ser::to_writer;
223pub use self::ser::{
224    Indent, InlinePolicy, Serializer, SerializerConfig, SerializerConfigBuilder, to_string,
225};
226pub use self::stream::StreamDeserializer;
227#[cfg(feature = "io")]
228pub use self::stream::from_reader;
229pub use self::trailing::Trailing;