use crate::{TauqError, compile_tauq};
use serde::de::DeserializeOwned;
use std::path::Path;
pub fn from_str<T: DeserializeOwned>(s: &str) -> Result<T, TauqError> {
let json = compile_tauq(s)?;
serde_json::from_value(json).map_err(|e| {
TauqError::Interpret(crate::error::InterpretError::new(format!(
"Deserialization error: {}",
e
)))
})
}
pub fn from_file<T: DeserializeOwned>(path: impl AsRef<Path>) -> Result<T, TauqError> {
let source = std::fs::read_to_string(path.as_ref()).map_err(TauqError::Io)?;
let json = compile_tauq(&source)?;
serde_json::from_value(json).map_err(|e| {
TauqError::Interpret(crate::error::InterpretError::new(format!(
"Deserialization error: {}",
e
)))
})
}
pub fn from_bytes<T: DeserializeOwned>(bytes: &[u8]) -> Result<T, TauqError> {
let s = std::str::from_utf8(bytes).map_err(|e| {
TauqError::Interpret(crate::error::InterpretError::new(format!(
"Invalid UTF-8: {}",
e
)))
})?;
from_str(s)
}
#[cfg(test)]
mod tests {
use super::*;
use serde::Deserialize;
#[derive(Deserialize, Debug, PartialEq)]
struct SimpleConfig {
workers: f64, timeout: f64,
}
#[derive(Deserialize, Debug, PartialEq)]
struct NestedConfig {
app: AppConfig,
database: DatabaseConfig,
}
#[derive(Deserialize, Debug, PartialEq)]
struct AppConfig {
name: String,
version: String,
}
#[derive(Deserialize, Debug, PartialEq)]
struct DatabaseConfig {
host: String,
port: f64, ssl: bool,
}
#[derive(Deserialize, Debug, PartialEq)]
struct ConfigWithArray {
tags: Vec<String>,
ports: Vec<f64>, }
#[test]
fn test_from_str_simple() {
let tauq = r#"
workers 8
timeout 30
"#;
let config: SimpleConfig = from_str(tauq).unwrap();
assert_eq!(
config,
SimpleConfig {
workers: 8.0,
timeout: 30.0
}
);
}
#[test]
fn test_from_str_nested() {
let tauq = r#"
app {
name "MyApp"
version "1.0.0"
}
database {
host localhost
port 5432
ssl true
}
"#;
let config: NestedConfig = from_str(tauq).unwrap();
assert_eq!(config.app.name, "MyApp");
assert_eq!(config.app.version, "1.0.0");
assert_eq!(config.database.host, "localhost");
assert_eq!(config.database.port, 5432.0);
assert!(config.database.ssl);
}
#[test]
fn test_from_str_with_arrays() {
let tauq = r#"
tags [api backend web]
ports [8080 8081 8082]
"#;
let config: ConfigWithArray = from_str(tauq).unwrap();
assert_eq!(config.tags, vec!["api", "backend", "web"]);
assert_eq!(config.ports, vec![8080.0, 8081.0, 8082.0]);
}
#[test]
fn test_from_bytes() {
let bytes = b"workers 8\ntimeout 30";
let config: SimpleConfig = from_bytes(bytes).unwrap();
assert_eq!(
config,
SimpleConfig {
workers: 8.0,
timeout: 30.0
}
);
}
#[test]
fn test_deserialization_error() {
use serde::Deserialize;
let tauq = "workers 8\ntimeout 30";
#[allow(dead_code)]
#[derive(Deserialize)]
struct WrongType {
workers: String, }
let result: Result<WrongType, _> = from_str(tauq);
assert!(result.is_err());
}
}