1use serde::Serialize;
34
35#[cfg(feature = "toon")]
36use toon_format::{encode_default, EncodeOptions, ToonError};
37
38#[derive(Debug, Clone, Default)]
43pub struct ToonEncoder {
44 pub use_tabs: bool,
46 pub fold_keys: bool,
48}
49
50impl ToonEncoder {
51 pub fn new() -> Self {
53 Self::default()
54 }
55
56 pub fn compact() -> Self {
58 Self {
59 use_tabs: true,
60 fold_keys: true,
61 }
62 }
63
64 pub fn with_tabs(mut self, use_tabs: bool) -> Self {
66 self.use_tabs = use_tabs;
67 self
68 }
69
70 pub fn with_key_folding(mut self, fold_keys: bool) -> Self {
72 self.fold_keys = fold_keys;
73 self
74 }
75
76 #[cfg(feature = "toon")]
81 pub fn encode<T: Serialize>(&self, value: &T) -> Result<String, ToonEncodeError> {
82 let options = self.build_options();
83 toon_format::encode(value, &options).map_err(ToonEncodeError::from)
84 }
85
86 #[cfg(not(feature = "toon"))]
88 pub fn encode<T: Serialize>(&self, value: &T) -> Result<String, ToonEncodeError> {
89 serde_json::to_string_pretty(value).map_err(ToonEncodeError::from)
90 }
91
92 #[cfg(feature = "toon")]
94 pub fn encode_default<T: Serialize>(value: &T) -> Result<String, ToonEncodeError> {
95 encode_default(value).map_err(ToonEncodeError::from)
96 }
97
98 #[cfg(not(feature = "toon"))]
100 pub fn encode_default<T: Serialize>(value: &T) -> Result<String, ToonEncodeError> {
101 serde_json::to_string_pretty(value).map_err(ToonEncodeError::from)
102 }
103
104 pub fn encode_json(&self, value: &serde_json::Value) -> Result<String, ToonEncodeError> {
106 self.encode(value)
107 }
108
109 #[cfg(feature = "toon")]
111 fn build_options(&self) -> EncodeOptions {
112 use toon_format::types::{Delimiter, KeyFoldingMode};
113 let mut options = EncodeOptions::default();
114
115 if self.use_tabs {
116 options = options.with_delimiter(Delimiter::Tab);
117 }
118
119 if self.fold_keys {
120 options = options.with_key_folding(KeyFoldingMode::Safe);
121 }
122
123 options
124 }
125}
126
127#[derive(Debug)]
129pub enum ToonEncodeError {
130 #[cfg(feature = "toon")]
132 Toon(ToonError),
133 Json(serde_json::Error),
135}
136
137impl std::fmt::Display for ToonEncodeError {
138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 match self {
140 #[cfg(feature = "toon")]
141 ToonEncodeError::Toon(e) => write!(f, "TOON encoding error: {}", e),
142 ToonEncodeError::Json(e) => write!(f, "JSON encoding error: {}", e),
143 }
144 }
145}
146
147impl std::error::Error for ToonEncodeError {}
148
149#[cfg(feature = "toon")]
150impl From<ToonError> for ToonEncodeError {
151 fn from(err: ToonError) -> Self {
152 ToonEncodeError::Toon(err)
153 }
154}
155
156impl From<serde_json::Error> for ToonEncodeError {
157 fn from(err: serde_json::Error) -> Self {
158 ToonEncodeError::Json(err)
159 }
160}
161
162#[cfg(feature = "toon")]
167pub fn tool_schema_to_toon(schema: &crate::tools::ToolSchema) -> Result<String, ToonEncodeError> {
168 use serde_json::json;
169
170 let value = json!({
171 "name": schema.name,
172 "description": schema.description,
173 "parameters": schema.parameters
174 });
175
176 ToonEncoder::encode_default(&value)
177}
178
179#[cfg(not(feature = "toon"))]
181pub fn tool_schema_to_toon(schema: &crate::tools::ToolSchema) -> Result<String, ToonEncodeError> {
182 serde_json::to_string_pretty(schema).map_err(ToonEncodeError::from)
183}
184
185#[cfg(feature = "toon")]
200pub fn format_tool_call_toon(
201 tool_name: &str,
202 args: &serde_json::Value,
203) -> Result<String, ToonEncodeError> {
204 use serde_json::json;
205
206 let value = json!({
207 "tool": tool_name,
208 "args": args
209 });
210
211 ToonEncoder::encode_default(&value)
212}
213
214#[cfg(not(feature = "toon"))]
216pub fn format_tool_call_toon(
217 tool_name: &str,
218 args: &serde_json::Value,
219) -> Result<String, ToonEncodeError> {
220 use serde_json::json;
221
222 let value = json!({
223 "tool": tool_name,
224 "args": args
225 });
226
227 serde_json::to_string_pretty(&value).map_err(ToonEncodeError::from)
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233 use serde_json::json;
234
235 #[test]
236 fn test_encoder_basic() {
237 let encoder = ToonEncoder::new();
238 let data = json!({"name": "Alice", "age": 30});
239 let result = encoder.encode(&data).unwrap();
240 assert!(!result.is_empty());
241 }
242
243 #[test]
244 fn test_encoder_array() {
245 let encoder = ToonEncoder::new();
246 let data = json!({
247 "users": [
248 {"id": 1, "name": "Alice"},
249 {"id": 2, "name": "Bob"}
250 ]
251 });
252 let result = encoder.encode(&data).unwrap();
253 assert!(!result.is_empty());
254
255 #[cfg(feature = "toon")]
256 {
257 assert!(result.contains("users"));
259 }
260 }
261
262 #[test]
263 fn test_encode_default() {
264 let data = json!({"key": "value"});
265 let result = ToonEncoder::encode_default(&data).unwrap();
266 assert!(!result.is_empty());
267 }
268
269 #[test]
270 fn test_format_tool_call() {
271 let result = format_tool_call_toon("search", &json!({"query": "rust"})).unwrap();
272 assert!(result.contains("search"));
273 assert!(result.contains("rust"));
274 }
275}