serde_json_pythonic/
lib.rs

1//! # Serde JSON
2//!
3//! JSON is a ubiquitous open-standard format that uses human-readable text to
4//! transmit data objects consisting of key-value pairs.
5//!
6//! ```json
7//! {
8//!     "name": "John Doe",
9//!     "age": 43,
10//!     "address": {
11//!         "street": "10 Downing Street",
12//!         "city": "London"
13//!     },
14//!     "phones": [
15//!         "+44 1234567",
16//!         "+44 2345678"
17//!     ]
18//! }
19//! ```
20//!
21//! There are three common ways that you might find yourself needing to work
22//! with JSON data in Rust.
23//!
24//!  - **As text data.** An unprocessed string of JSON data that you receive on
25//!    an HTTP endpoint, read from a file, or prepare to send to a remote
26//!    server.
27//!  - **As an untyped or loosely typed representation.** Maybe you want to
28//!    check that some JSON data is valid before passing it on, but without
29//!    knowing the structure of what it contains. Or you want to do very basic
30//!    manipulations like insert a key in a particular spot.
31//!  - **As a strongly typed Rust data structure.** When you expect all or most
32//!    of your data to conform to a particular structure and want to get real
33//!    work done without JSON's loosey-goosey nature tripping you up.
34//!
35//! Serde JSON provides efficient, flexible, safe ways of converting data
36//! between each of these representations.
37//!
38//! # Operating on untyped JSON values
39//!
40//! Any valid JSON data can be manipulated in the following recursive enum
41//! representation. This data structure is [`serde_json_pythonic::Value`][value].
42//!
43//! ```
44//! # use serde_json_pythonic::{Number, Map};
45//! #
46//! # #[allow(dead_code)]
47//! enum Value {
48//!     Null,
49//!     Bool(bool),
50//!     Number(Number),
51//!     String(String),
52//!     Array(Vec<Value>),
53//!     Object(Map<String, Value>),
54//! }
55//! ```
56//!
57//! A string of JSON data can be parsed into a `serde_json_pythonic::Value` by the
58//! [`serde_json_pythonic::from_str`][from_str] function. There is also
59//! [`from_slice`][from_slice] for parsing from a byte slice &[u8] and
60//! [`from_reader`][from_reader] for parsing from any `io::Read` like a File or
61//! a TCP stream.
62//!
63//! ```
64//! use serde_json_pythonic::{Result, Value};
65//!
66//! fn untyped_example() -> Result<()> {
67//!     // Some JSON input data as a &str. Maybe this comes from the user.
68//!     let data = r#"
69//!         {
70//!             "name": "John Doe",
71//!             "age": 43,
72//!             "phones": [
73//!                 "+44 1234567",
74//!                 "+44 2345678"
75//!             ]
76//!         }"#;
77//!
78//!     // Parse the string of data into serde_json_pythonic::Value.
79//!     let v: Value = serde_json_pythonic::from_str(data)?;
80//!
81//!     // Access parts of the data by indexing with square brackets.
82//!     println!("Please call {} at the number {}", v["name"], v["phones"][0]);
83//!
84//!     Ok(())
85//! }
86//! #
87//! # fn main() {
88//! #     untyped_example().unwrap();
89//! # }
90//! ```
91//!
92//! The result of square bracket indexing like `v["name"]` is a borrow of the
93//! data at that index, so the type is `&Value`. A JSON map can be indexed with
94//! string keys, while a JSON array can be indexed with integer keys. If the
95//! type of the data is not right for the type with which it is being indexed,
96//! or if a map does not contain the key being indexed, or if the index into a
97//! vector is out of bounds, the returned element is `Value::Null`.
98//!
99//! When a `Value` is printed, it is printed as a JSON string. So in the code
100//! above, the output looks like `Please call "John Doe" at the number "+44
101//! 1234567"`. The quotation marks appear because `v["name"]` is a `&Value`
102//! containing a JSON string and its JSON representation is `"John Doe"`.
103//! Printing as a plain string without quotation marks involves converting from
104//! a JSON string to a Rust string with [`as_str()`] or avoiding the use of
105//! `Value` as described in the following section.
106//!
107//! [`as_str()`]: crate::Value::as_str
108//!
109//! The `Value` representation is sufficient for very basic tasks but can be
110//! tedious to work with for anything more significant. Error handling is
111//! verbose to implement correctly, for example imagine trying to detect the
112//! presence of unrecognized fields in the input data. The compiler is powerless
113//! to help you when you make a mistake, for example imagine typoing `v["name"]`
114//! as `v["nmae"]` in one of the dozens of places it is used in your code.
115//!
116//! # Parsing JSON as strongly typed data structures
117//!
118//! Serde provides a powerful way of mapping JSON data into Rust data structures
119//! largely automatically.
120//!
121//! ```
122//! use serde::{Deserialize, Serialize};
123//! use serde_json_pythonic::Result;
124//!
125//! #[derive(Serialize, Deserialize)]
126//! struct Person {
127//!     name: String,
128//!     age: u8,
129//!     phones: Vec<String>,
130//! }
131//!
132//! fn typed_example() -> Result<()> {
133//!     // Some JSON input data as a &str. Maybe this comes from the user.
134//!     let data = r#"
135//!         {
136//!             "name": "John Doe",
137//!             "age": 43,
138//!             "phones": [
139//!                 "+44 1234567",
140//!                 "+44 2345678"
141//!             ]
142//!         }"#;
143//!
144//!     // Parse the string of data into a Person object. This is exactly the
145//!     // same function as the one that produced serde_json_pythonic::Value above, but
146//!     // now we are asking it for a Person as output.
147//!     let p: Person = serde_json_pythonic::from_str(data)?;
148//!
149//!     // Do things just like with any other Rust data structure.
150//!     println!("Please call {} at the number {}", p.name, p.phones[0]);
151//!
152//!     Ok(())
153//! }
154//! #
155//! # fn main() {
156//! #     typed_example().unwrap();
157//! # }
158//! ```
159//!
160//! This is the same `serde_json_pythonic::from_str` function as before, but this time we
161//! assign the return value to a variable of type `Person` so Serde will
162//! automatically interpret the input data as a `Person` and produce informative
163//! error messages if the layout does not conform to what a `Person` is expected
164//! to look like.
165//!
166//! Any type that implements Serde's `Deserialize` trait can be deserialized
167//! this way. This includes built-in Rust standard library types like `Vec<T>`
168//! and `HashMap<K, V>`, as well as any structs or enums annotated with
169//! `#[derive(Deserialize)]`.
170//!
171//! Once we have `p` of type `Person`, our IDE and the Rust compiler can help us
172//! use it correctly like they do for any other Rust code. The IDE can
173//! autocomplete field names to prevent typos, which was impossible in the
174//! `serde_json_pythonic::Value` representation. And the Rust compiler can check that
175//! when we write `p.phones[0]`, then `p.phones` is guaranteed to be a
176//! `Vec<String>` so indexing into it makes sense and produces a `String`.
177//!
178//! # Constructing JSON values
179//!
180//! Serde JSON provides a [`json!` macro][macro] to build `serde_json_pythonic::Value`
181//! objects with very natural JSON syntax.
182//!
183//! ```
184//! use serde_json_pythonic::json;
185//!
186//! fn main() {
187//!     // The type of `john` is `serde_json_pythonic::Value`
188//!     let john = json!({
189//!         "name": "John Doe",
190//!         "age": 43,
191//!         "phones": [
192//!             "+44 1234567",
193//!             "+44 2345678"
194//!         ]
195//!     });
196//!
197//!     println!("first phone number: {}", john["phones"][0]);
198//!
199//!     // Convert to a string of JSON and print it out
200//!     println!("{}", john.to_string());
201//! }
202//! ```
203//!
204//! The `Value::to_string()` function converts a `serde_json_pythonic::Value` into a
205//! `String` of JSON text.
206//!
207//! One neat thing about the `json!` macro is that variables and expressions can
208//! be interpolated directly into the JSON value as you are building it. Serde
209//! will check at compile time that the value you are interpolating is able to
210//! be represented as JSON.
211//!
212//! ```
213//! # use serde_json_pythonic::json;
214//! #
215//! # fn random_phone() -> u16 { 0 }
216//! #
217//! let full_name = "John Doe";
218//! let age_last_year = 42;
219//!
220//! // The type of `john` is `serde_json_pythonic::Value`
221//! let john = json!({
222//!     "name": full_name,
223//!     "age": age_last_year + 1,
224//!     "phones": [
225//!         format!("+44 {}", random_phone())
226//!     ]
227//! });
228//! ```
229//!
230//! This is amazingly convenient, but we have the problem we had before with
231//! `Value`: the IDE and Rust compiler cannot help us if we get it wrong. Serde
232//! JSON provides a better way of serializing strongly-typed data structures
233//! into JSON text.
234//!
235//! # Creating JSON by serializing data structures
236//!
237//! A data structure can be converted to a JSON string by
238//! [`serde_json_pythonic::to_string`][to_string]. There is also
239//! [`serde_json_pythonic::to_vec`][to_vec] which serializes to a `Vec<u8>` and
240//! [`serde_json_pythonic::to_writer`][to_writer] which serializes to any `io::Write`
241//! such as a File or a TCP stream.
242//!
243//! ```
244//! use serde::{Deserialize, Serialize};
245//! use serde_json_pythonic::Result;
246//!
247//! #[derive(Serialize, Deserialize)]
248//! struct Address {
249//!     street: String,
250//!     city: String,
251//! }
252//!
253//! fn print_an_address() -> Result<()> {
254//!     // Some data structure.
255//!     let address = Address {
256//!         street: "10 Downing Street".to_owned(),
257//!         city: "London".to_owned(),
258//!     };
259//!
260//!     // Serialize it to a JSON string.
261//!     let j = serde_json_pythonic::to_string(&address)?;
262//!
263//!     // Print, write to a file, or send to an HTTP server.
264//!     println!("{}", j);
265//!
266//!     Ok(())
267//! }
268//! #
269//! # fn main() {
270//! #     print_an_address().unwrap();
271//! # }
272//! ```
273//!
274//! Any type that implements Serde's `Serialize` trait can be serialized this
275//! way. This includes built-in Rust standard library types like `Vec<T>` and
276//! `HashMap<K, V>`, as well as any structs or enums annotated with
277//! `#[derive(Serialize)]`.
278//!
279//! # No-std support
280//!
281//! As long as there is a memory allocator, it is possible to use serde_json_pythonic
282//! without the rest of the Rust standard library. Disable the default "std"
283//! feature and enable the "alloc" feature:
284//!
285//! ```toml
286//! [dependencies]
287//! serde_json_pythonic = { version = "1.0", default-features = false, features = ["alloc"] }
288//! ```
289//!
290//! For JSON support in Serde without a memory allocator, please see the
291//! [`serde-json-core`] crate.
292//!
293//! [value]: crate::value::Value
294//! [from_str]: crate::de::from_str
295//! [from_slice]: crate::de::from_slice
296//! [from_reader]: crate::de::from_reader
297//! [to_string]: crate::ser::to_string
298//! [to_vec]: crate::ser::to_vec
299//! [to_writer]: crate::ser::to_writer
300//! [macro]: crate::json
301//! [`serde-json-core`]: https://github.com/rust-embedded-community/serde-json-core
302
303#![doc(html_root_url = "https://docs.rs/serde_json_pythonic/0.1.2")]
304// Ignored clippy lints
305#![allow(
306    clippy::collapsible_else_if,
307    clippy::comparison_chain,
308    clippy::deprecated_cfg_attr,
309    clippy::doc_markdown,
310    clippy::excessive_precision,
311    clippy::explicit_auto_deref,
312    clippy::float_cmp,
313    clippy::manual_range_contains,
314    clippy::match_like_matches_macro,
315    clippy::match_single_binding,
316    clippy::needless_doctest_main,
317    clippy::needless_late_init,
318    // clippy bug: https://github.com/rust-lang/rust-clippy/issues/8366
319    clippy::ptr_arg,
320    clippy::return_self_not_must_use,
321    clippy::transmute_ptr_to_ptr,
322    clippy::unnecessary_wraps,
323    // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
324    clippy::unnested_or_patterns,
325)]
326// Ignored clippy_pedantic lints
327#![allow(
328    // buggy
329    clippy::iter_not_returning_iterator, // https://github.com/rust-lang/rust-clippy/issues/8285
330    // Deserializer::from_str, into_iter
331    clippy::should_implement_trait,
332    // integer and float ser/de requires these sorts of casts
333    clippy::cast_possible_truncation,
334    clippy::cast_possible_wrap,
335    clippy::cast_precision_loss,
336    clippy::cast_sign_loss,
337    // correctly used
338    clippy::enum_glob_use,
339    clippy::if_not_else,
340    clippy::integer_division,
341    clippy::let_underscore_untyped,
342    clippy::map_err_ignore,
343    clippy::match_same_arms,
344    clippy::similar_names,
345    clippy::unused_self,
346    clippy::wildcard_imports,
347    // things are often more readable this way
348    clippy::cast_lossless,
349    clippy::module_name_repetitions,
350    clippy::redundant_else,
351    clippy::shadow_unrelated,
352    clippy::single_match_else,
353    clippy::too_many_lines,
354    clippy::unreadable_literal,
355    clippy::unseparated_literal_suffix,
356    clippy::use_self,
357    clippy::zero_prefixed_literal,
358    // we support older compilers
359    clippy::checked_conversions,
360    clippy::mem_replace_with_default,
361    // noisy
362    clippy::missing_errors_doc,
363    clippy::must_use_candidate,
364)]
365#![allow(non_upper_case_globals)]
366#![deny(missing_docs)]
367#![cfg_attr(not(feature = "std"), no_std)]
368#![cfg_attr(docsrs, feature(doc_cfg))]
369
370extern crate alloc;
371
372#[cfg(feature = "std")]
373#[doc(inline)]
374pub use crate::de::from_reader;
375#[doc(inline)]
376pub use crate::de::{from_slice, from_str, Deserializer, StreamDeserializer};
377#[doc(inline)]
378pub use crate::error::{Error, Result};
379#[doc(inline)]
380pub use crate::ser::{
381    to_string, to_string_pretty, to_string_pythonic, to_vec, to_vec_pretty, to_vec_pythonic,
382};
383#[cfg(feature = "std")]
384#[doc(inline)]
385pub use crate::ser::{to_writer, to_writer_pretty, to_writer_pythonic, Serializer};
386#[doc(inline)]
387pub use crate::value::{from_value, to_value, Map, Number, Value};
388
389// We only use our own error type; no need for From conversions provided by the
390// standard library's try! macro. This reduces lines of LLVM IR by 4%.
391macro_rules! tri {
392    ($e:expr $(,)?) => {
393        match $e {
394            core::result::Result::Ok(val) => val,
395            core::result::Result::Err(err) => return core::result::Result::Err(err),
396        }
397    };
398}
399
400#[macro_use]
401mod macros;
402
403pub mod de;
404pub mod error;
405pub mod map;
406#[cfg(feature = "std")]
407#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
408pub mod ser;
409#[cfg(not(feature = "std"))]
410mod ser;
411pub mod value;
412
413mod features_check;
414
415mod io;
416#[cfg(feature = "std")]
417mod iter;
418#[cfg(feature = "float_roundtrip")]
419mod lexical;
420mod number;
421mod read;
422
423#[cfg(feature = "raw_value")]
424mod raw;