jzon/
lib.rs

1//! ![](https://raw.githubusercontent.com/maciejhirsz/json-rust/master/json-rust-logo-small.png)
2//!
3//! # json-rust
4//!
5//! Parse and serialize [JSON](http://json.org/) with ease.
6//!
7//! **[Changelog](https://github.com/maciejhirsz/json-rust/releases) -**
8//! **[Complete Documentation](https://docs.rs/json/) -**
9//! **[Cargo](https://crates.io/crates/json) -**
10//! **[Repository](https://github.com/maciejhirsz/json-rust)**
11//!
12//! ## Why?
13//!
14//! JSON is a very loose format where anything goes - arrays can hold mixed
15//! types, object keys can change types between API calls or not include
16//! some keys under some conditions. Mapping that to idiomatic Rust structs
17//! introduces friction.
18//!
19//! This crate intends to avoid that friction.
20//!
21//! ```rust
22//! # #[macro_use] extern crate jzon;
23//! # fn main() {
24//! let parsed = jzon::parse(r#"
25//!
26//! {
27//!     "code": 200,
28//!     "success": true,
29//!     "payload": {
30//!         "features": [
31//!             "awesome",
32//!             "easyAPI",
33//!             "lowLearningCurve"
34//!         ]
35//!     }
36//! }
37//!
38//! "#).unwrap();
39//!
40//! let instantiated = object!{
41//!     // quotes on keys are optional
42//!     "code": 200,
43//!     success: true,
44//!     payload: {
45//!         features: [
46//!             "awesome",
47//!             "easyAPI",
48//!             "lowLearningCurve"
49//!         ]
50//!     }
51//! };
52//!
53//! assert_eq!(parsed, instantiated);
54//! # }
55//! ```
56//!
57//! ## First class citizen
58//!
59//! Using macros and indexing, it's easy to work with the data.
60//!
61//! ```rust
62//! # #[macro_use] extern crate jzon;
63//! # fn main() {
64//! let mut data = object!{
65//!     foo: false,
66//!     bar: null,
67//!     answer: 42,
68//!     list: [null, "world", true]
69//! };
70//!
71//! // Partial equality is implemented for most raw types:
72//! assert!(data["foo"] == false);
73//!
74//! // And it's type aware, `null` and `false` are different values:
75//! assert!(data["bar"] != false);
76//!
77//! // But you can use any Rust number types:
78//! assert!(data["answer"] == 42);
79//! assert!(data["answer"] == 42.0);
80//! assert!(data["answer"] == 42isize);
81//!
82//! // Access nested structures, arrays and objects:
83//! assert!(data["list"][0].is_null());
84//! assert!(data["list"][1] == "world");
85//! assert!(data["list"][2] == true);
86//!
87//! // Error resilient - accessing properties that don't exist yield null:
88//! assert!(data["this"]["does"]["not"]["exist"].is_null());
89//!
90//! // Mutate by assigning:
91//! data["list"][0] = "Hello".into();
92//!
93//! // Use the `dump` method to serialize the data:
94//! assert_eq!(data.dump(), r#"{"foo":false,"bar":null,"answer":42,"list":["Hello","world",true]}"#);
95//!
96//! // Or pretty print it out:
97//! println!("{:#}", data);
98//! # }
99//! ```
100//!
101//! ## Serialize with `jzon::stringify(value)`
102//!
103//! Primitives:
104//!
105//! ```
106//! // str slices
107//! assert_eq!(jzon::stringify("foobar"), "\"foobar\"");
108//!
109//! // Owned strings
110//! assert_eq!(jzon::stringify("foobar".to_string()), "\"foobar\"");
111//!
112//! // Any number types
113//! assert_eq!(jzon::stringify(42), "42");
114//!
115//! // Booleans
116//! assert_eq!(jzon::stringify(true), "true");
117//! assert_eq!(jzon::stringify(false), "false");
118//! ```
119//!
120//! Explicit `null` type `jzon::Null`:
121//!
122//! ```
123//! assert_eq!(jzon::stringify(jzon::Null), "null");
124//! ```
125//!
126//! Optional types:
127//!
128//! ```
129//! let value: Option<String> = Some("foo".to_string());
130//! assert_eq!(jzon::stringify(value), "\"foo\"");
131//!
132//! let no_value: Option<String> = None;
133//! assert_eq!(jzon::stringify(no_value), "null");
134//! ```
135//!
136//! Vector:
137//!
138//! ```
139//! let data = vec![1,2,3];
140//! assert_eq!(jzon::stringify(data), "[1,2,3]");
141//! ```
142//!
143//! Vector with optional values:
144//!
145//! ```
146//! let data = vec![Some(1), None, Some(2), None, Some(3)];
147//! assert_eq!(jzon::stringify(data), "[1,null,2,null,3]");
148//! ```
149//!
150//! Pushing to arrays:
151//!
152//! ```
153//! let mut data = jzon::JsonValue::new_array();
154//!
155//! data.push(10);
156//! data.push("foo");
157//! data.push(false);
158//!
159//! assert_eq!(data.dump(), r#"[10,"foo",false]"#);
160//! ```
161//!
162//! Putting fields on objects:
163//!
164//! ```
165//! let mut data = jzon::JsonValue::new_object();
166//!
167//! data["answer"] = 42.into();
168//! data["foo"] = "bar".into();
169//!
170//! assert_eq!(data.dump(), r#"{"answer":42,"foo":"bar"}"#);
171//! ```
172//!
173//! `array!` macro:
174//!
175//! ```
176//! # #[macro_use] extern crate jzon;
177//! # fn main() {
178//! let data = array!["foo", "bar", 100, true, null];
179//! assert_eq!(data.dump(), r#"["foo","bar",100,true,null]"#);
180//! # }
181//! ```
182//!
183//! `object!` macro:
184//!
185//! ```
186//! # #[macro_use] extern crate jzon;
187//! # fn main() {
188//! let data = object!{
189//!     name: "John Doe",
190//!     age: 30,
191//!     canJSON: true
192//! };
193//! assert_eq!(
194//!     data.dump(),
195//!     r#"{"name":"John Doe","age":30,"canJSON":true}"#
196//! );
197//! # }
198//! ```
199
200use std::result;
201
202pub mod codegen;
203mod parser;
204mod value;
205mod error;
206mod util;
207
208pub mod short;
209pub mod object;
210pub mod number;
211
212pub use error::Error;
213pub use value::JsonValue;
214pub use value::JsonValue::Null;
215
216/// Result type used by this crate.
217///
218///
219/// *Note:* Since 0.9.0 the old `JsonResult` type is deprecated. Always use
220/// `jzon::Result` instead.
221pub type Result<T> = result::Result<T, Error>;
222
223pub mod iterators {
224    /// Iterator over members of `JsonValue::Array`.
225    pub type Members<'a> = ::std::slice::Iter<'a, super::JsonValue>;
226
227    /// Mutable iterator over members of `JsonValue::Array`.
228    pub type MembersMut<'a> = ::std::slice::IterMut<'a, super::JsonValue>;
229
230    /// Iterator over key value pairs of `JsonValue::Object`.
231    pub type Entries<'a> = super::object::Iter<'a>;
232
233    /// Mutable iterator over key value pairs of `JsonValue::Object`.
234    pub type EntriesMut<'a> = super::object::IterMut<'a>;
235}
236
237#[deprecated(since="0.9.0", note="use `jzon::Error` instead")]
238pub use Error as JsonError;
239
240#[deprecated(since="0.9.0", note="use `jzon::Result` instead")]
241pub use crate::Result as JsonResult;
242
243pub use parser::parse;
244
245pub type Array = Vec<JsonValue>;
246
247/// Convenience for `JsonValue::from(value)`
248pub fn from<T>(value: T) -> JsonValue where T: Into<JsonValue> {
249    value.into()
250}
251
252/// Pretty prints out the value as JSON string.
253pub fn stringify<T>(root: T) -> String where T: Into<JsonValue> {
254    let root: JsonValue = root.into();
255    root.dump()
256}
257
258/// Pretty prints out the value as JSON string. Second argument is a
259/// number of spaces to indent new blocks with.
260pub fn stringify_pretty<T>(root: T, spaces: u16) -> String where T: Into<JsonValue> {
261    let root: JsonValue = root.into();
262    root.pretty(spaces)
263}
264
265/// Helper macro for creating instances of `JsonValue::Array`.
266///
267/// ```
268/// # #[macro_use] extern crate jzon;
269/// # fn main() {
270/// let data = array!["foo", 42, false];
271///
272/// assert_eq!(data[0], "foo");
273/// assert_eq!(data[1], 42);
274/// assert_eq!(data[2], false);
275///
276/// assert_eq!(data.dump(), r#"["foo",42,false]"#);
277/// # }
278/// ```
279#[macro_export]
280macro_rules! array {
281    [] => ($crate::JsonValue::new_array());
282
283    // Handles for token tree items
284    [@ITEM($( $i:expr, )*) $item:tt, $( $cont:tt )+] => {
285        $crate::array!(
286            @ITEM($( $i, )* $crate::value!($item), )
287            $( $cont )*
288        )
289    };
290    (@ITEM($( $i:expr, )*) $item:tt,) => ({
291        $crate::array!(@END $( $i, )* $crate::value!($item), )
292    });
293    (@ITEM($( $i:expr, )*) $item:tt) => ({
294        $crate::array!(@END $( $i, )* $crate::value!($item), )
295    });
296
297    // Handles for expression items
298    [@ITEM($( $i:expr, )*) $item:expr, $( $cont:tt )+] => {
299        $crate::array!(
300            @ITEM($( $i, )* $crate::value!($item), )
301            $( $cont )*
302        )
303    };
304    (@ITEM($( $i:expr, )*) $item:expr,) => ({
305        $crate::array!(@END $( $i, )* $crate::value!($item), )
306    });
307    (@ITEM($( $i:expr, )*) $item:expr) => ({
308        $crate::array!(@END $( $i, )* $crate::value!($item), )
309    });
310
311    // Construct the actual array
312    (@END $( $i:expr, )*) => ({
313        let size = 0 $( + {let _ = &$i; 1} )*;
314        let mut array = Vec::with_capacity(size);
315
316        $(
317            array.push($i.into());
318        )*
319
320        $crate::JsonValue::Array(array)
321    });
322
323    // Entry point to the macro
324    ($( $cont:tt )+) => {
325        $crate::array!(@ITEM() $($cont)*)
326    };
327}
328
329#[macro_export]
330/// Helper crate for converting types into `JsonValue`. It's used
331/// internally by the `object!` and `array!` macros.
332macro_rules! value {
333    ( null ) => { $crate::Null };
334    ( [$( $token:tt )*] ) => {
335        // 10
336        $crate::array![ $( $token )* ]
337    };
338    ( {$( $token:tt )*} ) => {
339        $crate::object!{ $( $token )* }
340    };
341    { $value:expr } => { $value };
342}
343
344/// Helper macro for creating instances of `JsonValue::Object`.
345///
346/// ```
347/// # #[macro_use] extern crate jzon;
348/// # fn main() {
349/// let data = object!{
350///     foo: 42,
351///     bar: false,
352/// };
353///
354/// assert_eq!(data["foo"], 42);
355/// assert_eq!(data["bar"], false);
356///
357/// assert_eq!(data.dump(), r#"{"foo":42,"bar":false}"#);
358/// # }
359/// ```
360#[macro_export]
361macro_rules! object {
362    // Empty object.
363    {} => ($crate::JsonValue::new_object());
364
365    // Handles for different types of keys
366    (@ENTRY($( $k:expr => $v:expr, )*) $key:ident: $( $cont:tt )*) => {
367        $crate::object!(@ENTRY($( $k => $v, )*) stringify!($key) => $($cont)*)
368    };
369    (@ENTRY($( $k:expr => $v:expr, )*) $key:literal: $( $cont:tt )*) => {
370        $crate::object!(@ENTRY($( $k => $v, )*) $key => $($cont)*)
371    };
372    (@ENTRY($( $k:expr => $v:expr, )*) [$key:expr]: $( $cont:tt )*) => {
373        $crate::object!(@ENTRY($( $k => $v, )*) $key => $($cont)*)
374    };
375
376    // Handles for token tree values
377    (@ENTRY($( $k:expr => $v:expr, )*) $key:expr => $value:tt, $( $cont:tt )+) => {
378        $crate::object!(
379            @ENTRY($( $k => $v, )* $key => $crate::value!($value), )
380            $( $cont )*
381        )
382    };
383    (@ENTRY($( $k:expr => $v:expr, )*) $key:expr => $value:tt,) => ({
384        $crate::object!(@END $( $k => $v, )* $key => $crate::value!($value), )
385    });
386    (@ENTRY($( $k:expr => $v:expr, )*) $key:expr => $value:tt) => ({
387        $crate::object!(@END $( $k => $v, )* $key => $crate::value!($value), )
388    });
389
390    // Handles for expression values
391    (@ENTRY($( $k:expr => $v:expr, )*) $key:expr => $value:expr, $( $cont:tt )+) => {
392        $crate::object!(
393            @ENTRY($( $k => $v, )* $key => $crate::value!($value), )
394            $( $cont )*
395        )
396    };
397    (@ENTRY($( $k:expr => $v:expr, )*) $key:expr => $value:expr,) => ({
398        $crate::object!(@END $( $k => $v, )* $key => $crate::value!($value), )
399    });
400
401    (@ENTRY($( $k:expr => $v:expr, )*) $key:expr => $value:expr) => ({
402        $crate::object!(@END $( $k => $v, )* $key => $crate::value!($value), )
403    });
404
405    // Construct the actual object
406    (@END $( $k:expr => $v:expr, )*) => ({
407        let size = 0 $( + {let _ = &$k; 1} )*;
408        let mut object = $crate::object::Object::with_capacity(size);
409
410        $(
411            object.insert($k, $v.into());
412        )*
413
414        $crate::JsonValue::Object(object)
415    });
416
417    // Entry point to the macro
418    ($key:tt: $( $cont:tt )+) => {
419        $crate::object!(@ENTRY() $key: $($cont)*)
420    };
421
422    // Legacy macro
423    ($( $k:expr => $v:expr, )*) => {
424        $crate::object!(@END $( $k => $crate::value!($v), )*)
425    };
426    ($( $k:expr => $v:expr ),*) => {
427        $crate::object!(@END $( $k => $crate::value!($v), )*)
428    };
429}