use serde::{Deserialize, Serialize};
use super::sematon::Sematon;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FoldedSematon {
pub id: String,
pub payload_json: String,
pub witness_r: f32,
pub witness_entropy: f32,
pub witness_converged: bool,
pub witness_step: u32,
pub address_base: u32,
pub address_coeff0: u16,
pub address_coeff1: u16,
pub entropy: f32,
pub density: f32,
pub impedance: f32,
pub shape_hash: u32,
pub constructive: bool,
pub source: String,
}
pub fn fold_sematon<T: Clone + Serialize>(sematon: &Sematon<T>) -> FoldedSematon {
FoldedSematon {
id: sematon.id.clone(),
payload_json: serde_json::to_string(&sematon.payload).unwrap_or_default(),
witness_r: sematon.witness.r,
witness_entropy: sematon.witness.entropy,
witness_converged: sematon.witness.converged,
witness_step: sematon.witness.step,
address_base: sematon.address.base,
address_coeff0: sematon.address.coeff0,
address_coeff1: sematon.address.coeff1,
entropy: sematon.entropy,
density: sematon.density,
impedance: sematon.impedance,
shape_hash: sematon.shape_hash,
constructive: sematon.constructive,
source: sematon.source.clone(),
}
}
pub fn unfold_sematon<T: Clone + for<'de> Deserialize<'de>>(
folded: &FoldedSematon,
) -> Result<Sematon<T>, String> {
let payload: T = serde_json::from_str(&folded.payload_json)
.map_err(|e| format!("Failed to deserialize payload: {}", e))?;
Ok(Sematon {
id: folded.id.clone(),
payload,
witness: super::witness::ConvergenceWitness {
r: folded.witness_r,
entropy: folded.witness_entropy,
converged: folded.witness_converged,
step: folded.witness_step,
},
address: super::graph::PadicAddr {
base: folded.address_base,
coeff0: folded.address_coeff0,
coeff1: folded.address_coeff1,
},
entropy: folded.entropy,
density: folded.density,
impedance: folded.impedance,
shape_hash: folded.shape_hash,
constructive: folded.constructive,
source: folded.source.clone(),
})
}
pub fn fold_to_json<T: Clone + Serialize>(sematon: &Sematon<T>) -> String {
let folded = fold_sematon(sematon);
serde_json::to_string(&folded).unwrap_or_default()
}
pub fn unfold_from_json<T: Clone + for<'de> Deserialize<'de>>(
json: &str,
) -> Result<Sematon<T>, String> {
let folded: FoldedSematon =
serde_json::from_str(json).map_err(|e| format!("Failed to parse FoldedSematon: {}", e))?;
unfold_sematon(&folded)
}
#[cfg(test)]
mod tests {
use super::*;
use super::super::witness::ConvergenceWitness;
use super::super::graph::PadicAddr;
#[test]
fn test_fold_unfold_roundtrip() {
let w = ConvergenceWitness {
r: 0.95,
entropy: 0.3,
converged: true,
step: 42,
};
let original = Sematon::new(
vec![1.0f32, 2.0, 3.0],
w,
PadicAddr { base: 3, coeff0: 1, coeff1: 7 },
"test-surface",
);
let folded = fold_sematon(&original);
let restored: Sematon<Vec<f32>> = unfold_sematon(&folded).unwrap();
assert_eq!(restored.id, original.id);
assert_eq!(restored.payload, original.payload);
assert!((restored.witness.r - original.witness.r).abs() < 1e-6);
assert_eq!(restored.witness.converged, original.witness.converged);
assert_eq!(restored.address.base, original.address.base);
assert_eq!(restored.shape_hash, original.shape_hash);
assert_eq!(restored.constructive, original.constructive);
}
#[test]
fn test_fold_to_json_roundtrip() {
let w = ConvergenceWitness { r: 0.8, entropy: 0.5, converged: false, step: 10 };
let original = Sematon::new("hello world".to_string(), w, PadicAddr::default(), "test");
let json = fold_to_json(&original);
let restored: Sematon<String> = unfold_from_json(&json).unwrap();
assert_eq!(restored.payload, "hello world");
assert_eq!(restored.id, original.id);
}
#[test]
fn test_unfold_bad_json_errors() {
let result: Result<Sematon<u32>, _> = unfold_from_json("not valid json");
assert!(result.is_err());
}
}