use serde::Serialize;
#[cfg(feature = "toon")]
use toon_format::{encode_default, EncodeOptions, ToonError};
#[derive(Debug, Clone, Default)]
pub struct ToonEncoder {
pub use_tabs: bool,
pub fold_keys: bool,
}
impl ToonEncoder {
pub fn new() -> Self {
Self::default()
}
pub fn compact() -> Self {
Self {
use_tabs: true,
fold_keys: true,
}
}
pub fn with_tabs(mut self, use_tabs: bool) -> Self {
self.use_tabs = use_tabs;
self
}
pub fn with_key_folding(mut self, fold_keys: bool) -> Self {
self.fold_keys = fold_keys;
self
}
#[cfg(feature = "toon")]
pub fn encode<T: Serialize>(&self, value: &T) -> Result<String, ToonEncodeError> {
let options = self.build_options();
toon_format::encode(value, &options).map_err(ToonEncodeError::from)
}
#[cfg(not(feature = "toon"))]
pub fn encode<T: Serialize>(&self, value: &T) -> Result<String, ToonEncodeError> {
serde_json::to_string_pretty(value).map_err(ToonEncodeError::from)
}
#[cfg(feature = "toon")]
pub fn encode_default<T: Serialize>(value: &T) -> Result<String, ToonEncodeError> {
encode_default(value).map_err(ToonEncodeError::from)
}
#[cfg(not(feature = "toon"))]
pub fn encode_default<T: Serialize>(value: &T) -> Result<String, ToonEncodeError> {
serde_json::to_string_pretty(value).map_err(ToonEncodeError::from)
}
pub fn encode_json(&self, value: &serde_json::Value) -> Result<String, ToonEncodeError> {
self.encode(value)
}
#[cfg(feature = "toon")]
fn build_options(&self) -> EncodeOptions {
use toon_format::types::{Delimiter, KeyFoldingMode};
let mut options = EncodeOptions::default();
if self.use_tabs {
options = options.with_delimiter(Delimiter::Tab);
}
if self.fold_keys {
options = options.with_key_folding(KeyFoldingMode::Safe);
}
options
}
}
#[derive(Debug)]
pub enum ToonEncodeError {
#[cfg(feature = "toon")]
Toon(ToonError),
Json(serde_json::Error),
}
impl std::fmt::Display for ToonEncodeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
#[cfg(feature = "toon")]
ToonEncodeError::Toon(e) => write!(f, "TOON encoding error: {}", e),
ToonEncodeError::Json(e) => write!(f, "JSON encoding error: {}", e),
}
}
}
impl std::error::Error for ToonEncodeError {}
#[cfg(feature = "toon")]
impl From<ToonError> for ToonEncodeError {
fn from(err: ToonError) -> Self {
ToonEncodeError::Toon(err)
}
}
impl From<serde_json::Error> for ToonEncodeError {
fn from(err: serde_json::Error) -> Self {
ToonEncodeError::Json(err)
}
}
#[cfg(feature = "toon")]
pub fn tool_schema_to_toon(schema: &crate::tools::ToolSchema) -> Result<String, ToonEncodeError> {
use serde_json::json;
let value = json!({
"name": schema.name,
"description": schema.description,
"parameters": schema.parameters
});
ToonEncoder::encode_default(&value)
}
#[cfg(not(feature = "toon"))]
pub fn tool_schema_to_toon(schema: &crate::tools::ToolSchema) -> Result<String, ToonEncodeError> {
serde_json::to_string_pretty(schema).map_err(ToonEncodeError::from)
}
#[cfg(feature = "toon")]
pub fn format_tool_call_toon(
tool_name: &str,
args: &serde_json::Value,
) -> Result<String, ToonEncodeError> {
use serde_json::json;
let value = json!({
"tool": tool_name,
"args": args
});
ToonEncoder::encode_default(&value)
}
#[cfg(not(feature = "toon"))]
pub fn format_tool_call_toon(
tool_name: &str,
args: &serde_json::Value,
) -> Result<String, ToonEncodeError> {
use serde_json::json;
let value = json!({
"tool": tool_name,
"args": args
});
serde_json::to_string_pretty(&value).map_err(ToonEncodeError::from)
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_encoder_basic() {
let encoder = ToonEncoder::new();
let data = json!({"name": "Alice", "age": 30});
let result = encoder.encode(&data).unwrap();
assert!(!result.is_empty());
}
#[test]
fn test_encoder_array() {
let encoder = ToonEncoder::new();
let data = json!({
"users": [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"}
]
});
let result = encoder.encode(&data).unwrap();
assert!(!result.is_empty());
#[cfg(feature = "toon")]
{
assert!(result.contains("users"));
}
}
#[test]
fn test_encode_default() {
let data = json!({"key": "value"});
let result = ToonEncoder::encode_default(&data).unwrap();
assert!(!result.is_empty());
}
#[test]
fn test_format_tool_call() {
let result = format_tool_call_toon("search", &json!({"query": "rust"})).unwrap();
assert!(result.contains("search"));
assert!(result.contains("rust"));
}
}