1mod error;
29mod parser;
30mod traits;
31mod value;
32pub mod writer;
33
34pub use error::{JsonError, Result};
35pub use parser::JsonParser;
36pub use traits::{JsonDeserialize, JsonSerialize};
37pub use value::JsonValue;
38pub use writer::JsonWriter;
39
40pub use json_steroids_derive::{Json, JsonDeserialize, JsonSerialize};
42
43#[inline]
45pub fn to_string<T: JsonSerialize>(value: &T) -> String {
46 let mut writer = JsonWriter::new();
47 value.json_serialize(&mut writer);
48 writer.into_string()
49}
50
51#[inline]
53pub fn to_string_pretty<T: JsonSerialize>(value: &T) -> String {
54 let mut writer = JsonWriter::with_indent(2);
55 value.json_serialize(&mut writer);
56 writer.into_string()
57}
58
59#[inline]
61pub fn from_str<'de, T: JsonDeserialize<'de>>(s: &'de str) -> Result<T> {
62 let mut parser = JsonParser::new(s);
63 T::json_deserialize(&mut parser)
64}
65
66#[inline]
68pub fn from_bytes<'de, T: JsonDeserialize<'de>>(bytes: &'de [u8]) -> Result<T> {
69 let s = std::str::from_utf8(bytes).map_err(|_| JsonError::InvalidUtf8)?;
70 from_str(s)
71}
72
73#[inline]
75pub fn parse(s: &str) -> Result<JsonValue> {
76 let mut parser = JsonParser::new(s);
77 parser.parse_value()
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[derive(Debug, PartialEq, Json)]
85 struct SimpleStruct {
86 name: String,
87 value: i64,
88 active: bool,
89 }
90
91 #[derive(Debug, PartialEq, Json)]
92 struct NestedStruct {
93 id: u32,
94 data: SimpleStruct,
95 }
96
97 #[derive(Debug, PartialEq, Json)]
98 struct WithOption {
99 required: String,
100 optional: Option<i32>,
101 }
102
103 #[derive(Debug, PartialEq, Json)]
104 struct WithVec {
105 items: Vec<i32>,
106 }
107
108 #[derive(Debug, PartialEq, Json)]
109 enum Status {
110 Active,
111 Inactive,
112 Pending,
113 }
114
115 #[derive(Debug, PartialEq, Json)]
116 enum Message {
117 Text(String),
118 Number(i64),
119 Data { x: i32, y: i32 },
120 }
121
122 #[test]
123 fn test_simple_struct_roundtrip() {
124 let original = SimpleStruct {
125 name: "test".to_string(),
126 value: 42,
127 active: true,
128 };
129 let json = to_string(&original);
130 let parsed: SimpleStruct = from_str(&json).unwrap();
131 assert_eq!(original, parsed);
132 }
133
134 #[test]
135 fn test_nested_struct_roundtrip() {
136 let original = NestedStruct {
137 id: 1,
138 data: SimpleStruct {
139 name: "nested".to_string(),
140 value: 100,
141 active: false,
142 },
143 };
144 let json = to_string(&original);
145 let parsed: NestedStruct = from_str(&json).unwrap();
146 assert_eq!(original, parsed);
147 }
148
149 #[test]
150 fn test_option_some() {
151 let original = WithOption {
152 required: "hello".to_string(),
153 optional: Some(42),
154 };
155 let json = to_string(&original);
156 let parsed: WithOption = from_str(&json).unwrap();
157 assert_eq!(original, parsed);
158 }
159
160 #[test]
161 fn test_option_none() {
162 let original = WithOption {
163 required: "hello".to_string(),
164 optional: None,
165 };
166 let json = to_string(&original);
167 let parsed: WithOption = from_str(&json).unwrap();
168 assert_eq!(original, parsed);
169 }
170
171 #[test]
172 fn test_vec_roundtrip() {
173 let original = WithVec {
174 items: vec![1, 2, 3, 4, 5],
175 };
176 let json = to_string(&original);
177 let parsed: WithVec = from_str(&json).unwrap();
178 assert_eq!(original, parsed);
179 }
180
181 #[test]
182 fn test_unit_enum() {
183 let original = Status::Active;
184 let json = to_string(&original);
185 assert_eq!(json, r#""Active""#);
186 let parsed: Status = from_str(&json).unwrap();
187 assert_eq!(original, parsed);
188 }
189
190 #[test]
191 fn test_tuple_enum() {
192 let original = Message::Text("hello".to_string());
193 let json = to_string(&original);
194 let parsed: Message = from_str(&json).unwrap();
195 assert_eq!(original, parsed);
196 }
197
198 #[test]
199 fn test_struct_enum() {
200 let original = Message::Data { x: 10, y: 20 };
201 let json = to_string(&original);
202 let parsed: Message = from_str(&json).unwrap();
203 assert_eq!(original, parsed);
204 }
205
206 #[test]
207 fn test_primitives() {
208 assert_eq!(to_string(&42i32), "42");
209 assert_eq!(to_string(&3.14f64), "3.14");
210 assert_eq!(to_string(&true), "true");
211 assert_eq!(to_string(&"hello"), r#""hello""#);
212 }
213
214 #[test]
215 fn test_parse_primitives() {
216 assert_eq!(from_str::<i32>("42").unwrap(), 42);
217 assert_eq!(from_str::<f64>("3.14").unwrap(), 3.14);
218 assert_eq!(from_str::<bool>("true").unwrap(), true);
219 assert_eq!(from_str::<String>(r#""hello""#).unwrap(), "hello");
220 }
221
222 #[test]
223 fn test_escape_sequences() {
224 let s = "hello\nworld\t\"test\"\\path";
225 let json = to_string(&s);
226 let parsed: String = from_str(&json).unwrap();
227 assert_eq!(s, parsed);
228 }
229
230 #[test]
231 fn test_unicode() {
232 let s = "こんにちは 🦀 emoji";
233 let json = to_string(&s);
234 let parsed: String = from_str(&json).unwrap();
235 assert_eq!(s, parsed);
236 }
237
238 #[test]
239 fn test_dynamic_value() {
240 let json = r#"{"name": "test", "values": [1, 2, 3], "nested": {"a": true}}"#;
241 let value = parse(json).unwrap();
242
243 assert!(value.is_object());
244 assert_eq!(value["name"].as_str(), Some("test"));
245 assert!(value["values"].is_array());
246 assert_eq!(value["nested"]["a"].as_bool(), Some(true));
247 }
248
249 #[test]
250 fn test_pretty_print() {
251 let original = SimpleStruct {
252 name: "test".to_string(),
253 value: 42,
254 active: true,
255 };
256 let json = to_string_pretty(&original);
257 assert!(json.contains('\n'));
258 let parsed: SimpleStruct = from_str(&json).unwrap();
259 assert_eq!(original, parsed);
260 }
261}