1pub mod arena;
137pub mod canonical;
138pub mod decode;
139pub mod encode;
140pub mod error;
141pub mod num;
142pub mod options;
143pub mod text;
144
145use std::io::{BufRead, Read, Write};
146
147pub use crate::error::{Error, ErrorKind, ErrorStage, Location};
148pub use crate::options::{
149 DecodeOptions, Delimiter, EncodeOptions, ExpandPaths, Indent, KeyFolding,
150};
151pub use canonical::{encode_canonical, CanonicalProfile};
152use serde::de::DeserializeOwned;
153use serde::Serialize;
154pub use serde_json::Value;
155
156pub type Result<T> = std::result::Result<T, Error>;
157
158pub fn to_string<T: Serialize>(value: &T) -> Result<String> {
159 to_string_with_options(value, &EncodeOptions::default())
160}
161
162pub fn to_string_with_options<T: Serialize>(value: &T, options: &EncodeOptions) -> Result<String> {
163 encode::to_string(value, options)
164}
165
166pub fn to_string_into<T: Serialize>(value: &T, out: &mut String) -> Result<()> {
167 to_string_into_with_options(value, &EncodeOptions::default(), out)
168}
169
170pub fn to_string_into_with_options<T: Serialize>(
171 value: &T,
172 options: &EncodeOptions,
173 out: &mut String,
174) -> Result<()> {
175 encode::to_string_into(value, options, out)
176}
177
178pub fn to_string_from_json_str(input: &str) -> Result<String> {
179 to_string_from_json_str_with_options(input, &EncodeOptions::default())
180}
181
182pub fn to_string_from_json_str_with_options(
183 input: &str,
184 options: &EncodeOptions,
185) -> Result<String> {
186 encode::to_string_from_json_str(input, options)
187}
188
189pub fn to_vec<T: Serialize>(value: &T) -> Result<Vec<u8>> {
190 to_vec_with_options(value, &EncodeOptions::default())
191}
192
193pub fn to_vec_with_options<T: Serialize>(value: &T, options: &EncodeOptions) -> Result<Vec<u8>> {
194 encode::to_vec(value, options)
195}
196
197pub fn to_writer<T: Serialize, W: Write>(writer: W, value: &T) -> Result<()> {
198 to_writer_with_options(writer, value, &EncodeOptions::default())
199}
200
201pub fn to_writer_with_options<T: Serialize, W: Write>(
202 writer: W,
203 value: &T,
204 options: &EncodeOptions,
205) -> Result<()> {
206 encode::to_writer(writer, value, options)
207}
208
209pub fn from_str<T: DeserializeOwned>(input: &str) -> Result<T> {
210 from_str_with_options(input, &DecodeOptions::default())
211}
212
213pub fn from_str_with_options<T: DeserializeOwned>(
214 input: &str,
215 options: &DecodeOptions,
216) -> Result<T> {
217 decode::from_str(input, options)
218}
219
220#[cfg(feature = "parallel")]
221pub fn from_str_parallel<T: DeserializeOwned + Send>(input: &str) -> Result<Vec<T>> {
222 from_str_parallel_with_options(input, &DecodeOptions::default())
223}
224
225#[cfg(feature = "parallel")]
226pub fn from_str_parallel_with_options<T: DeserializeOwned + Send>(
227 input: &str,
228 options: &DecodeOptions,
229) -> Result<Vec<T>> {
230 decode::from_str_parallel(input, options)
231}
232
233pub fn from_slice<T: DeserializeOwned>(input: &[u8]) -> Result<T> {
234 from_slice_with_options(input, &DecodeOptions::default())
235}
236
237pub fn from_slice_with_options<T: DeserializeOwned>(
238 input: &[u8],
239 options: &DecodeOptions,
240) -> Result<T> {
241 decode::from_slice(input, options)
242}
243
244pub fn from_reader<T: DeserializeOwned, R: Read>(reader: R) -> Result<T> {
252 from_reader_with_options(reader, &DecodeOptions::default())
253}
254
255pub fn from_reader_with_options<T: DeserializeOwned, R: Read>(
262 reader: R,
263 options: &DecodeOptions,
264) -> Result<T> {
265 decode::from_reader(reader, options)
266}
267
268pub fn from_reader_streaming<T: DeserializeOwned, R: BufRead>(reader: R) -> Result<T> {
269 from_reader_streaming_with_options(reader, &DecodeOptions::default())
270}
271
272pub fn from_reader_streaming_with_options<T: DeserializeOwned, R: BufRead>(
273 reader: R,
274 options: &DecodeOptions,
275) -> Result<T> {
276 decode::from_reader_streaming(reader, options)
277}
278
279pub fn decode_to_value(input: &str) -> Result<Value> {
280 decode_to_value_with_options(input, &DecodeOptions::default())
281}
282
283pub fn decode_to_value_with_options(input: &str, options: &DecodeOptions) -> Result<Value> {
284 let value = decode::from_str_value(input, options)?;
285 Ok(canonicalize_numbers(value))
286}
287
288pub fn decode_to_value_auto<S: AsRef<str>>(input: S) -> Result<Value> {
289 decode_to_value_auto_with_options(input, &DecodeOptions::default())
290}
291
292pub fn decode_to_value_auto_with_options<S: AsRef<str>>(
293 input: S,
294 options: &DecodeOptions,
295) -> Result<Value> {
296 let input = input.as_ref();
297 match detect_auto_kind(input) {
298 AutoDetectKind::Json | AutoDetectKind::Uncertain => {
299 match serde_json::from_str::<Value>(input) {
300 Ok(value) => Ok(canonicalize_numbers(value)),
301 Err(json_err) => match decode_to_value_with_options(input, options) {
302 Ok(value) => Ok(value),
303 Err(toon_err) => Err(auto_detect_error(json_err, toon_err)),
304 },
305 }
306 }
307 AutoDetectKind::Toon => match decode_to_value_with_options(input, options) {
308 Ok(value) => Ok(value),
309 Err(toon_err) => match serde_json::from_str::<Value>(input) {
310 Ok(value) => Ok(canonicalize_numbers(value)),
311 Err(json_err) => Err(auto_detect_error(json_err, toon_err)),
312 },
313 },
314 }
315}
316
317#[derive(Debug, Clone, Copy, PartialEq, Eq)]
318enum AutoDetectKind {
319 Json,
320 Toon,
321 Uncertain,
322}
323
324fn detect_auto_kind(input: &str) -> AutoDetectKind {
325 let first_non_ws = input.chars().find(|ch| !ch.is_whitespace());
326 let toon_key_pos = find_toon_key_token(input);
327 if let Some(ch) = first_non_ws {
328 if ch == '{' || ch == '[' {
329 if let Some(json_key_pos) = find_json_quoted_key(input) {
330 if toon_key_pos.is_none() || Some(json_key_pos) < toon_key_pos {
331 return AutoDetectKind::Json;
332 }
333 }
334 }
335 if ch.is_ascii_alphabetic() || ch == '_' {
336 return AutoDetectKind::Toon;
337 }
338 } else {
339 return AutoDetectKind::Uncertain;
340 }
341 if toon_key_pos.is_some() {
342 return AutoDetectKind::Toon;
343 }
344 AutoDetectKind::Uncertain
345}
346
347fn find_json_quoted_key(input: &str) -> Option<usize> {
348 let bytes = input.as_bytes();
349 let mut idx = 0;
350 while idx < bytes.len() {
351 if bytes[idx] == b'"' {
352 let start = idx;
353 idx += 1;
354 let mut escape = false;
355 while idx < bytes.len() {
356 let byte = bytes[idx];
357 if escape {
358 escape = false;
359 idx += 1;
360 continue;
361 }
362 if byte == b'\\' {
363 escape = true;
364 idx += 1;
365 continue;
366 }
367 if byte == b'"' {
368 idx += 1;
369 break;
370 }
371 idx += 1;
372 }
373 if idx >= bytes.len() {
374 break;
375 }
376 let mut lookahead = idx;
377 while lookahead < bytes.len()
378 && matches!(bytes[lookahead], b' ' | b'\t' | b'\r' | b'\n')
379 {
380 lookahead += 1;
381 }
382 if lookahead < bytes.len() && bytes[lookahead] == b':' {
383 return Some(start);
384 }
385 idx = lookahead;
386 continue;
387 }
388 idx += 1;
389 }
390 None
391}
392
393fn find_toon_key_token(input: &str) -> Option<usize> {
394 let mut offset = 0;
395 for line in input.split_terminator('\n') {
396 let bytes = line.as_bytes();
397 let mut idx = 0;
398 while idx < bytes.len() && matches!(bytes[idx], b' ' | b'\t' | b'\r') {
399 idx += 1;
400 }
401 if idx < bytes.len() && is_ident_start_byte(bytes[idx]) {
402 let start = offset + idx;
403 idx += 1;
404 while idx < bytes.len() && is_ident_continue_byte(bytes[idx]) {
405 idx += 1;
406 }
407 while idx < bytes.len() && matches!(bytes[idx], b' ' | b'\t') {
408 idx += 1;
409 }
410 if idx < bytes.len() && bytes[idx] == b':' {
411 return Some(start);
412 }
413 }
414 offset += line.len() + 1;
415 }
416 None
417}
418
419fn is_ident_start_byte(byte: u8) -> bool {
420 byte.is_ascii_alphabetic() || byte == b'_'
421}
422
423fn is_ident_continue_byte(byte: u8) -> bool {
424 byte.is_ascii_alphanumeric() || byte == b'_' || byte == b'.'
425}
426
427fn auto_detect_error(json_err: serde_json::Error, toon_err: Error) -> Error {
428 Error::decode(format!(
429 "input is neither valid JSON nor TOON: json error: {json_err}; toon error: {toon_err}"
430 ))
431}
432
433fn canonicalize_numbers(value: Value) -> Value {
434 match value {
435 Value::Array(items) => Value::Array(items.into_iter().map(canonicalize_numbers).collect()),
436 Value::Object(map) => {
437 let mapped = map
438 .into_iter()
439 .map(|(key, value)| (key, canonicalize_numbers(value)))
440 .collect();
441 Value::Object(mapped)
442 }
443 Value::Number(number) => {
444 let canonical = crate::num::number::format_json_number(&number);
445 match serde_json::from_str::<Value>(&canonical) {
446 Ok(Value::Number(number)) => Value::Number(number),
447 _ => Value::Number(number),
448 }
449 }
450 other => other,
451 }
452}
453
454pub fn validate_str(input: &str) -> Result<()> {
455 validate_str_with_options(input, &DecodeOptions::default())
456}
457
458pub fn validate_str_with_options(input: &str, options: &DecodeOptions) -> Result<()> {
459 decode::validate_str(input, options)
460}
461
462#[macro_export]
463macro_rules! toon {
485 (encode: $input:expr) => {
486 $crate::to_string(&$input)
487 };
488 (encode: $input:expr, $options:expr) => {
489 $crate::to_string_with_options(&$input, $options)
490 };
491 (encode_json: $input:expr) => {
492 $crate::to_string_from_json_str($input)
493 };
494 (encode_json: $input:expr, $options:expr) => {
495 $crate::to_string_from_json_str_with_options($input, $options)
496 };
497 ($input:expr) => {
498 $crate::decode_to_value_auto($input)
499 };
500 ($input:expr, $options:expr) => {
501 $crate::decode_to_value_auto_with_options($input, $options)
502 };
503}