Skip to main content

toon/decode/
mod.rs

1pub mod decoders;
2pub mod event_builder;
3pub mod expand;
4pub mod parser;
5pub mod scanner;
6pub mod validation;
7
8#[cfg(feature = "async-stream")]
9mod async_decode;
10
11use crate::decode::decoders as decoder_impl;
12use crate::decode::event_builder::{build_node_from_events, node_to_json};
13use crate::decode::expand::expand_paths_safe;
14use crate::error::Result;
15use crate::options::{DecodeOptions, DecodeStreamOptions, ExpandPathsMode, resolve_decode_options};
16use crate::{JsonStreamEvent, JsonValue};
17
18#[cfg(feature = "async-stream")]
19pub use async_decode::{
20    AsyncDecodeStream, decode_stream_async, try_decode_async, try_decode_stream_async,
21};
22
23/// Try to decode a TOON string into a JSON value, returning a Result.
24///
25/// This is the fallible version of [`decode`]. Use this when you want to handle
26/// decoding errors gracefully instead of panicking.
27///
28/// # Errors
29///
30/// Returns an error if decoding fails due to malformed input or strict-mode validation errors.
31pub fn try_decode(input: &str, options: Option<DecodeOptions>) -> Result<JsonValue> {
32    let lines = input
33        .split('\n')
34        .map(std::string::ToString::to_string)
35        .collect::<Vec<_>>();
36    try_decode_from_lines(lines, options)
37}
38
39/// Decode a TOON string into a JSON value.
40///
41/// # Panics
42///
43/// Panics if decoding fails due to malformed input or strict-mode validation errors.
44/// Use [`try_decode`] for a fallible version that returns `Result`.
45#[must_use]
46pub fn decode(input: &str, options: Option<DecodeOptions>) -> JsonValue {
47    try_decode(input, options).unwrap_or_else(|err| panic!("{err}"))
48}
49
50/// Try to decode TOON lines into a JSON value, returning a Result.
51///
52/// This is the fallible version of [`decode_from_lines`]. Use this when you want to handle
53/// decoding errors gracefully instead of panicking.
54///
55/// # Errors
56///
57/// Returns an error if decoding fails due to malformed input or strict-mode validation errors.
58pub fn try_decode_from_lines(
59    lines: impl IntoIterator<Item = String>,
60    options: Option<DecodeOptions>,
61) -> Result<JsonValue> {
62    let resolved = resolve_decode_options(options);
63    let events = decoder_impl::decode_stream_sync(
64        lines,
65        Some(DecodeStreamOptions {
66            indent: Some(resolved.indent),
67            strict: Some(resolved.strict),
68        }),
69    )?;
70
71    let mut node = build_node_from_events(events)?;
72
73    if resolved.expand_paths == ExpandPathsMode::Safe {
74        node = expand_paths_safe(node, resolved.strict)?;
75    }
76
77    Ok(node_to_json(node))
78}
79
80#[must_use]
81/// Decode TOON lines into a JSON value.
82///
83/// # Panics
84///
85/// Panics if decoding fails due to malformed input or strict-mode validation errors.
86/// Use [`try_decode_from_lines`] for a fallible version that returns `Result`.
87pub fn decode_from_lines(
88    lines: impl IntoIterator<Item = String>,
89    options: Option<DecodeOptions>,
90) -> JsonValue {
91    try_decode_from_lines(lines, options).unwrap_or_else(|err| panic!("{err}"))
92}
93
94/// Try to decode TOON lines into a stream of events, returning a Result.
95///
96/// This is the fallible version of [`decode_stream_sync`]. Use this when you want to handle
97/// decoding errors gracefully instead of panicking.
98///
99/// # Errors
100///
101/// Returns an error if decoding fails due to malformed input or strict-mode validation errors.
102pub fn try_decode_stream_sync(
103    lines: impl IntoIterator<Item = String>,
104    options: Option<DecodeStreamOptions>,
105) -> Result<Vec<JsonStreamEvent>> {
106    decoder_impl::decode_stream_sync(lines, options)
107}
108
109#[must_use]
110/// Decode TOON lines into a stream of events.
111///
112/// # Panics
113///
114/// Panics if decoding fails due to malformed input or strict-mode validation errors.
115/// Use [`try_decode_stream_sync`] for a fallible version that returns `Result`.
116pub fn decode_stream_sync(
117    lines: impl IntoIterator<Item = String>,
118    options: Option<DecodeStreamOptions>,
119) -> Vec<JsonStreamEvent> {
120    try_decode_stream_sync(lines, options).unwrap_or_else(|err| panic!("{err}"))
121}
122
123/// Try to decode TOON lines into a stream of events asynchronously, returning a Result.
124///
125/// This is the fallible version of [`decode_stream`]. Use this when you want to handle
126/// decoding errors gracefully instead of panicking.
127///
128/// When the `async-stream` feature is enabled, this uses the asupersync runtime for
129/// true async streaming with cancellation support. Otherwise, it falls back to
130/// synchronous decoding wrapped in an async function.
131///
132/// # Errors
133///
134/// Returns an error if decoding fails due to malformed input or strict-mode validation errors.
135#[cfg(not(feature = "async-stream"))]
136pub async fn try_decode_stream(
137    lines: impl IntoIterator<Item = String>,
138    options: Option<DecodeStreamOptions>,
139) -> Result<Vec<JsonStreamEvent>> {
140    decoder_impl::decode_stream_sync(lines, options)
141}
142
143/// Try to decode TOON lines into a stream of events asynchronously, returning a Result.
144///
145/// This version uses the asupersync runtime for true async streaming with
146/// cancellation support and yield points between line processing.
147///
148/// # Errors
149///
150/// Returns an error if decoding fails due to malformed input or strict-mode validation errors.
151#[cfg(feature = "async-stream")]
152pub async fn try_decode_stream(
153    lines: impl IntoIterator<Item = String>,
154    options: Option<DecodeStreamOptions>,
155) -> Result<Vec<JsonStreamEvent>> {
156    async_decode::try_decode_stream_async(lines, options).await
157}
158
159#[must_use]
160/// Decode TOON lines into a stream of events asynchronously.
161///
162/// # Panics
163///
164/// Panics if decoding fails due to malformed input or strict-mode validation errors.
165/// Use [`try_decode_stream`] for a fallible version that returns `Result`.
166pub async fn decode_stream(
167    lines: impl IntoIterator<Item = String>,
168    options: Option<DecodeStreamOptions>,
169) -> Vec<JsonStreamEvent> {
170    try_decode_stream(lines, options)
171        .await
172        .unwrap_or_else(|err| panic!("{err}"))
173}