1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! A [serde](https://serde.rs)-enabled implementation of the **JSONX** format.
//!
//! JSONX is a superset of JSON that relaxes the syntax and adds a handful of
//! typed value constructors. Concretely, on top of JSON it supports:
//!
//! * **Unquoted object keys** matching `^[A-Za-z_][0-9A-Za-z_]*$`.
//! * **Trailing commas** after the last array/object element.
//! * **Typed constructors** written as `type(value)`:
//! * sized integers: `int8`, `int16`, `int32`, `int64`, `uint8`, `uint16`,
//! `uint32`, `uint64`, and the machine-width `int` / `uint`;
//! * `datetime("2017-12-25T15:00:00Z")` (RFC 3339);
//! * `ip("192.168.1.2")` / `ip("::1")`;
//! * `ipport("192.168.1.2:65000")` / `ipport("[::1]:65000")`;
//! * `bytes("YWJjZA==")` (standard Base64).
//!
//! Plain JSON numbers always decode to an `f64`, exactly as in the reference
//! implementation; the constructors above are how you get a typed integer or
//! one of the extended types.
//!
//! # Quick start
//!
//! Work with arbitrary documents via [`Value`]:
//!
//! ```
//! let value: jsonx::Value = jsonx::from_str("{ id: int(7), tags: [\"a\", \"b\",] }").unwrap();
//! assert_eq!(value.get("id"), Some(&jsonx::Value::Int(7)));
//!
//! let text = jsonx::to_string(&value).unwrap();
//! assert_eq!(text, r#"{id:int(7),tags:["a","b"]}"#);
//! ```
//!
//! Or derive `Serialize`/`Deserialize` on your own types. Rust integer types
//! map to the matching JSONX sized integers, and plain `f64`s stay bare:
//!
//! ```
//! #[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug)]
//! struct Server {
//! name: String,
//! port: u16,
//! weight: i32,
//! }
//!
//! let server = Server { name: "db".into(), port: 5432, weight: -1 };
//! let text = jsonx::to_string(&server).unwrap();
//! assert_eq!(text, r#"{name:"db",port:uint16(5432),weight:int32(-1)}"#);
//! assert_eq!(jsonx::from_str::<Server>(&text).unwrap(), server);
//! ```
//!
//! # Extended types
//!
//! For the non-integer extended types, the most ergonomic option is the wrapper
//! types in this crate — [`Bytes`], [`Int`], [`Uint`], [`Ip`], [`IpPort`], and
//! [`Datetime`]. They need no attribute, and because they stay transparent in
//! other serde formats, the *same* struct also serializes cleanly to (say) TOML
//! or JSON, where they degrade to plain strings/integers:
//!
//! ```
//! use jsonx::{Ip, Datetime, DateTime};
//!
//! #[derive(serde::Serialize, serde::Deserialize, PartialEq, Debug)]
//! struct Peer {
//! addr: Ip,
//! seen: Datetime,
//! }
//!
//! let peer = Peer {
//! addr: Ip("10.0.0.1".parse().unwrap()),
//! seen: Datetime(DateTime::parse_from_rfc3339("2024-06-01T09:00:00Z").unwrap()),
//! };
//! let text = jsonx::to_string(&peer).unwrap();
//! assert_eq!(text, r#"{addr:ip("10.0.0.1"),seen:datetime("2024-06-01T09:00:00Z")}"#);
//! ```
//!
//! If you must keep a bare [`std::net`] address or [`DateTime`] field, the
//! [`ip`], [`ipport`], and [`datetime`] modules provide `#[serde(with = ...)]`
//! glue instead.
//!
//! # Extending JSONX with your own constructors
//!
//! JSONX is open: you can teach it a `type(value)` constructor for one of your
//! own types by implementing [`JsonxConstructor`]. See the [`constructor`]
//! module for the details.
//!
//! # Non-greedy decoding
//!
//! [`from_str_partial`] decodes a single value and tells you where it stopped,
//! so you can parse a stream of concatenated values.
pub use ;
pub use DateTime;
/// Derives [`JsonxConstructor`] plus the serde impls that wire it in, for a type
/// that implements [`Display`](std::fmt::Display) and [`FromStr`](std::str::FromStr).
///
/// The constructor name defaults to the type name lowercased; override it with
/// `#[jsonx(name = "...")]`. See the [`constructor`] module for details.
///
/// ```
/// use std::fmt;
/// use std::str::FromStr;
///
/// #[derive(jsonx::JsonxConstructor, Debug, PartialEq)]
/// #[jsonx(name = "semver")]
/// struct Version(u16, u16);
///
/// impl fmt::Display for Version {
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// write!(f, "{}.{}", self.0, self.1)
/// }
/// }
/// impl FromStr for Version {
/// type Err = String;
/// fn from_str(s: &str) -> Result<Self, String> {
/// let (a, b) = s.split_once('.').ok_or("expected MAJOR.MINOR")?;
/// Ok(Version(a.parse().map_err(|_| "bad major")?, b.parse().map_err(|_| "bad minor")?))
/// }
/// }
///
/// assert_eq!(jsonx::to_string(&Version(1, 4)).unwrap(), r#"semver("1.4")"#);
/// assert_eq!(jsonx::from_str::<Version>(r#"semver("1.4")"#).unwrap(), Version(1, 4));
/// ```
pub use JsonxConstructor;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;