hedl_toon/lib.rs
1// Dweve HEDL - Hierarchical Entity Data Language
2//
3// Copyright (c) 2025 Dweve IP B.V. and individual contributors.
4//
5// SPDX-License-Identifier: Apache-2.0
6//
7// Licensed under the Apache License, Version 2.0 (the "License");
8// you may not use this file except in compliance with the License.
9// You may obtain a copy of the License in the LICENSE file at the
10// root of this repository or at: http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! HEDL ↔ TOON Conversion
19//!
20//! Bidirectional conversion between HEDL documents and TOON (Token-Oriented Object Notation) format.
21//! Uses the official `toon-format` crate for spec-compliant parsing and serialization.
22//!
23//! # Overview
24//!
25//! This crate provides conversion between HEDL and TOON using the official TOON parser.
26//! TOON is designed for efficient processing by Large Language Models while maintaining
27//! human readability.
28//!
29//! # Quick Start
30//!
31//! ```rust
32//! use hedl_toon::hedl_to_toon;
33//! use hedl_core::Document;
34//!
35//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
36//! let hedl = r#"%V:2.0
37//! %NULL:~
38//! %QUOTE:"
39//! %S:User:[id, name]
40//! ---
41//! users:@User
42//! |u1, Alice
43//! |u2, Bob
44//! "#;
45//!
46//! let doc = hedl_core::parse(hedl.as_bytes())?;
47//! let toon = hedl_to_toon(&doc)?;
48//! println!("{}", toon);
49//! # Ok(())
50//! # }
51//! ```
52//!
53//! TOON Spec: <https://github.com/toon-format/spec>
54
55#![cfg_attr(not(test), warn(missing_docs))]
56
57mod encoder;
58mod error;
59mod from_toon;
60mod to_toon;
61
62pub use error::{Result, ToonError, MAX_NESTING_DEPTH};
63pub use from_toon::{from_toon, from_toon_with_config, FromToonConfig};
64pub use to_toon::{to_toon, Delimiter, ToToonConfig, ToToonConfigBuilder};
65
66use hedl_core::Document;
67
68/// Convert HEDL document to TOON string with default configuration
69///
70/// Uses the official toon-format crate for spec-compliant output.
71///
72/// # Arguments
73///
74/// * `doc` - The HEDL document to convert
75///
76/// # Returns
77///
78/// A TOON-formatted string, or a [`ToonError`] if conversion fails.
79pub fn hedl_to_toon(doc: &Document) -> Result<String> {
80 to_toon(doc, &ToToonConfig::default())
81}
82
83/// Parse TOON string to HEDL document
84///
85/// Uses the official toon-format crate for spec-compliant parsing.
86///
87/// # Arguments
88///
89/// * `toon` - The TOON formatted string to parse
90///
91/// # Returns
92///
93/// A HEDL Document, or a [`ToonError`] if parsing fails.
94pub fn toon_to_hedl(toon: &str) -> Result<Document> {
95 from_toon(toon)
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn test_simple_roundtrip() {
104 let hedl = r#"%V:2.0
105%NULL:~
106%QUOTE:"
107%S:User:[id, name, email]
108---
109users:@User
110 |u1, Alice, alice@example.com
111 |u2, Bob, bob@example.com
112"#;
113 let doc = hedl_core::parse(hedl.as_bytes()).unwrap();
114 let toon = hedl_to_toon(&doc).unwrap();
115
116 // Parse TOON back
117 let doc2 = toon_to_hedl(&toon).unwrap();
118
119 // Verify structure preserved
120 assert!(doc2.root.contains_key("users"));
121 }
122
123 #[test]
124 fn test_nested_object() {
125 let hedl = r#"%V:2.0
126%NULL:~
127%QUOTE:"
128---
129config:
130 name: MyApp
131 version: 1.0
132 settings:
133 debug: true
134 timeout: 30
135"#;
136 let doc = hedl_core::parse(hedl.as_bytes()).unwrap();
137 let toon = hedl_to_toon(&doc).unwrap();
138
139 assert!(toon.contains("config:"));
140 assert!(toon.contains("name: MyApp"));
141 }
142
143 #[test]
144 fn test_arrays() {
145 let hedl = r#"%V:2.0
146%NULL:~
147%QUOTE:"
148---
149numbers: [1, 2, 3, 4, 5]
150tags: (rust, python, go)
151"#;
152 let doc = hedl_core::parse(hedl.as_bytes()).unwrap();
153 let toon = hedl_to_toon(&doc).unwrap();
154
155 // Parse back and verify
156 let doc2 = toon_to_hedl(&toon).unwrap();
157 assert!(doc2.root.contains_key("numbers"));
158 assert!(doc2.root.contains_key("tags"));
159 }
160}