1use crate::seqstring::global_string;
37use crate::value::{MapKey as RuntimeMapKey, Value, VariantData};
38use serde::{Deserialize, Serialize};
39use std::collections::{BTreeMap, HashMap};
40use std::sync::Arc;
41
42#[derive(Debug)]
44pub enum SerializeError {
45 QuotationNotSerializable,
47 ClosureNotSerializable,
49 ChannelNotSerializable,
51 BincodeError(Box<bincode::Error>),
53 InvalidData(String),
55 NonFiniteFloat(f64),
57}
58
59impl std::fmt::Display for SerializeError {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 match self {
62 SerializeError::QuotationNotSerializable => {
63 write!(f, "Quotations cannot be serialized - code is not data")
64 }
65 SerializeError::ClosureNotSerializable => {
66 write!(f, "Closures cannot be serialized - code is not data")
67 }
68 SerializeError::ChannelNotSerializable => {
69 write!(f, "Channels cannot be serialized - runtime state")
70 }
71 SerializeError::BincodeError(e) => write!(f, "Bincode error: {}", e),
72 SerializeError::InvalidData(msg) => write!(f, "Invalid data: {}", msg),
73 SerializeError::NonFiniteFloat(v) => {
74 write!(f, "Cannot serialize non-finite float: {}", v)
75 }
76 }
77 }
78}
79
80impl std::error::Error for SerializeError {
81 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
82 match self {
83 SerializeError::BincodeError(e) => Some(e.as_ref()),
84 _ => None,
85 }
86 }
87}
88
89impl From<bincode::Error> for SerializeError {
90 fn from(e: bincode::Error) -> Self {
91 SerializeError::BincodeError(Box::new(e))
92 }
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
100pub enum TypedMapKey {
101 Int(i64),
102 Bool(bool),
103 String(String),
104}
105
106impl TypedMapKey {
107 pub fn to_typed_value(&self) -> TypedValue {
109 match self {
110 TypedMapKey::Int(v) => TypedValue::Int(*v),
111 TypedMapKey::Bool(v) => TypedValue::Bool(*v),
112 TypedMapKey::String(v) => TypedValue::String(v.clone()),
113 }
114 }
115
116 pub fn from_runtime(key: &RuntimeMapKey) -> Self {
118 match key {
119 RuntimeMapKey::Int(v) => TypedMapKey::Int(*v),
120 RuntimeMapKey::Bool(v) => TypedMapKey::Bool(*v),
121 RuntimeMapKey::String(s) => TypedMapKey::String(s.as_str().to_string()),
122 }
123 }
124
125 pub fn to_runtime(&self) -> RuntimeMapKey {
127 match self {
128 TypedMapKey::Int(v) => RuntimeMapKey::Int(*v),
129 TypedMapKey::Bool(v) => RuntimeMapKey::Bool(*v),
130 TypedMapKey::String(s) => RuntimeMapKey::String(global_string(s.clone())),
131 }
132 }
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
140pub enum TypedValue {
141 Int(i64),
142 Float(f64),
143 Bool(bool),
144 String(String),
145 Symbol(String),
147 Map(BTreeMap<TypedMapKey, TypedValue>),
149 Variant {
151 tag: String,
152 fields: Vec<TypedValue>,
153 },
154}
155
156impl TypedValue {
157 pub fn from_value(value: &Value) -> Result<Self, SerializeError> {
163 match value {
164 Value::Int(v) => Ok(TypedValue::Int(*v)),
165 Value::Float(v) => {
166 if !v.is_finite() {
167 return Err(SerializeError::NonFiniteFloat(*v));
168 }
169 Ok(TypedValue::Float(*v))
170 }
171 Value::Bool(v) => Ok(TypedValue::Bool(*v)),
172 Value::String(s) => Ok(TypedValue::String(s.as_str().to_string())),
173 Value::Symbol(s) => Ok(TypedValue::Symbol(s.as_str().to_string())),
174 Value::Map(map) => {
175 let mut typed_map = BTreeMap::new();
176 for (k, v) in map.iter() {
177 let typed_key = TypedMapKey::from_runtime(k);
178 let typed_value = TypedValue::from_value(v)?;
179 typed_map.insert(typed_key, typed_value);
180 }
181 Ok(TypedValue::Map(typed_map))
182 }
183 Value::Variant(data) => {
184 let mut typed_fields = Vec::with_capacity(data.fields.len());
185 for field in data.fields.iter() {
186 typed_fields.push(TypedValue::from_value(field)?);
187 }
188 Ok(TypedValue::Variant {
189 tag: data.tag.as_str().to_string(),
190 fields: typed_fields,
191 })
192 }
193 Value::Quotation { .. } => Err(SerializeError::QuotationNotSerializable),
194 Value::Closure { .. } => Err(SerializeError::ClosureNotSerializable),
195 Value::Channel(_) => Err(SerializeError::ChannelNotSerializable),
196 Value::WeaveCtx { .. } => Err(SerializeError::ChannelNotSerializable), }
198 }
199
200 pub fn to_value(&self) -> Value {
205 match self {
206 TypedValue::Int(v) => Value::Int(*v),
207 TypedValue::Float(v) => Value::Float(*v),
208 TypedValue::Bool(v) => Value::Bool(*v),
209 TypedValue::String(s) => Value::String(global_string(s.clone())),
210 TypedValue::Symbol(s) => Value::Symbol(global_string(s.clone())),
211 TypedValue::Map(map) => {
212 let mut runtime_map = HashMap::new();
213 for (k, v) in map.iter() {
214 runtime_map.insert(k.to_runtime(), v.to_value());
215 }
216 Value::Map(Box::new(runtime_map))
217 }
218 TypedValue::Variant { tag, fields } => {
219 let runtime_fields: Vec<Value> = fields.iter().map(|f| f.to_value()).collect();
220 Value::Variant(Arc::new(VariantData::new(
221 global_string(tag.clone()),
222 runtime_fields,
223 )))
224 }
225 }
226 }
227
228 pub fn to_map_key(&self) -> Result<TypedMapKey, SerializeError> {
230 match self {
231 TypedValue::Int(v) => Ok(TypedMapKey::Int(*v)),
232 TypedValue::Bool(v) => Ok(TypedMapKey::Bool(*v)),
233 TypedValue::String(v) => Ok(TypedMapKey::String(v.clone())),
234 TypedValue::Float(_) => Err(SerializeError::InvalidData(
235 "Float cannot be a map key".to_string(),
236 )),
237 TypedValue::Map(_) => Err(SerializeError::InvalidData(
238 "Map cannot be a map key".to_string(),
239 )),
240 TypedValue::Variant { .. } => Err(SerializeError::InvalidData(
241 "Variant cannot be a map key".to_string(),
242 )),
243 TypedValue::Symbol(v) => Ok(TypedMapKey::String(v.clone())),
244 }
245 }
246
247 pub fn to_bytes(&self) -> Result<Vec<u8>, SerializeError> {
249 bincode::serialize(self).map_err(SerializeError::from)
250 }
251
252 pub fn from_bytes(bytes: &[u8]) -> Result<Self, SerializeError> {
254 bincode::deserialize(bytes).map_err(SerializeError::from)
255 }
256
257 pub fn to_debug_string(&self) -> String {
259 match self {
260 TypedValue::Int(v) => format!("{}", v),
261 TypedValue::Float(v) => format!("{}", v),
262 TypedValue::Bool(v) => format!("{}", v),
263 TypedValue::String(v) => format!("{:?}", v),
264 TypedValue::Symbol(v) => format!(":{}", v),
265 TypedValue::Map(m) => {
266 let entries: Vec<String> = m
267 .iter()
268 .map(|(k, v)| format!("{}: {}", key_to_debug_string(k), v.to_debug_string()))
269 .collect();
270 format!("{{ {} }}", entries.join(", "))
271 }
272 TypedValue::Variant { tag, fields } => {
273 if fields.is_empty() {
274 format!("(Variant#{})", tag)
275 } else {
276 let field_strs: Vec<String> =
277 fields.iter().map(|f| f.to_debug_string()).collect();
278 format!("(Variant#{} {})", tag, field_strs.join(" "))
279 }
280 }
281 }
282 }
283}
284
285fn key_to_debug_string(key: &TypedMapKey) -> String {
286 match key {
287 TypedMapKey::Int(v) => format!("{}", v),
288 TypedMapKey::Bool(v) => format!("{}", v),
289 TypedMapKey::String(v) => format!("{:?}", v),
290 }
291}
292
293pub trait ValueSerialize {
295 fn to_typed(&self) -> Result<TypedValue, SerializeError>;
297
298 fn to_bytes(&self) -> Result<Vec<u8>, SerializeError>;
300}
301
302impl ValueSerialize for Value {
303 fn to_typed(&self) -> Result<TypedValue, SerializeError> {
304 TypedValue::from_value(self)
305 }
306
307 fn to_bytes(&self) -> Result<Vec<u8>, SerializeError> {
308 TypedValue::from_value(self)?.to_bytes()
309 }
310}
311
312#[cfg(test)]
313mod tests {
314 use super::*;
315 use crate::seqstring::global_string;
316
317 #[test]
318 fn test_int_roundtrip() {
319 let value = Value::Int(42);
320 let typed = TypedValue::from_value(&value).unwrap();
321 let back = typed.to_value();
322 assert_eq!(value, back);
323 }
324
325 #[test]
326 fn test_float_roundtrip() {
327 let value = Value::Float(1.23456);
328 let typed = TypedValue::from_value(&value).unwrap();
329 let back = typed.to_value();
330 assert_eq!(value, back);
331 }
332
333 #[test]
334 fn test_bool_roundtrip() {
335 let value = Value::Bool(true);
336 let typed = TypedValue::from_value(&value).unwrap();
337 let back = typed.to_value();
338 assert_eq!(value, back);
339 }
340
341 #[test]
342 fn test_string_roundtrip() {
343 let value = Value::String(global_string("hello".to_string()));
344 let typed = TypedValue::from_value(&value).unwrap();
345 let back = typed.to_value();
346 match (&value, &back) {
348 (Value::String(a), Value::String(b)) => assert_eq!(a.as_str(), b.as_str()),
349 _ => panic!("Expected strings"),
350 }
351 }
352
353 #[test]
354 fn test_map_roundtrip() {
355 let mut map = HashMap::new();
356 map.insert(
357 RuntimeMapKey::String(global_string("key".to_string())),
358 Value::Int(42),
359 );
360 map.insert(RuntimeMapKey::Int(1), Value::Bool(true));
361
362 let value = Value::Map(Box::new(map));
363 let typed = TypedValue::from_value(&value).unwrap();
364 let back = typed.to_value();
365
366 if let Value::Map(m) = back {
368 assert_eq!(m.len(), 2);
369 } else {
370 panic!("Expected map");
371 }
372 }
373
374 #[test]
375 fn test_variant_roundtrip() {
376 let data = VariantData::new(
377 global_string("TestVariant".to_string()),
378 vec![Value::Int(100), Value::Bool(false)],
379 );
380 let value = Value::Variant(Arc::new(data));
381
382 let typed = TypedValue::from_value(&value).unwrap();
383 let back = typed.to_value();
384
385 if let Value::Variant(v) = back {
386 assert_eq!(v.tag.as_str(), "TestVariant");
387 assert_eq!(v.fields.len(), 2);
388 } else {
389 panic!("Expected variant");
390 }
391 }
392
393 #[test]
394 fn test_quotation_not_serializable() {
395 let value = Value::Quotation {
396 wrapper: 12345,
397 impl_: 12345,
398 };
399 let result = TypedValue::from_value(&value);
400 assert!(matches!(
401 result,
402 Err(SerializeError::QuotationNotSerializable)
403 ));
404 }
405
406 #[test]
407 fn test_closure_not_serializable() {
408 use std::sync::Arc;
409 let value = Value::Closure {
410 fn_ptr: 12345,
411 env: Arc::from(vec![Value::Int(1)].into_boxed_slice()),
412 };
413 let result = TypedValue::from_value(&value);
414 assert!(matches!(
415 result,
416 Err(SerializeError::ClosureNotSerializable)
417 ));
418 }
419
420 #[test]
421 fn test_bytes_roundtrip() {
422 let typed = TypedValue::Map(BTreeMap::from([
423 (TypedMapKey::String("x".to_string()), TypedValue::Int(10)),
424 (TypedMapKey::Int(42), TypedValue::Bool(true)),
425 ]));
426
427 let bytes = typed.to_bytes().unwrap();
428 let parsed = TypedValue::from_bytes(&bytes).unwrap();
429 assert_eq!(typed, parsed);
430 }
431
432 #[test]
433 fn test_bincode_is_compact() {
434 let typed = TypedValue::Int(42);
435 let bytes = typed.to_bytes().unwrap();
436 assert!(
437 bytes.len() < 20,
438 "Expected compact encoding, got {} bytes",
439 bytes.len()
440 );
441 }
442
443 #[test]
444 fn test_debug_string() {
445 let typed = TypedValue::String("hello".to_string());
446 assert_eq!(typed.to_debug_string(), "\"hello\"");
447
448 let typed = TypedValue::Int(42);
449 assert_eq!(typed.to_debug_string(), "42");
450 }
451
452 #[test]
453 fn test_nested_structure() {
454 let inner_variant = TypedValue::Variant {
456 tag: "NestedVariant".to_string(),
457 fields: vec![TypedValue::String("inner".to_string())],
458 };
459
460 let mut inner_map = BTreeMap::new();
461 inner_map.insert(TypedMapKey::String("nested".to_string()), inner_variant);
462
463 let outer = TypedValue::Map(inner_map);
464
465 let bytes = outer.to_bytes().unwrap();
466 let parsed = TypedValue::from_bytes(&bytes).unwrap();
467 assert_eq!(outer, parsed);
468 }
469
470 #[test]
471 fn test_nan_not_serializable() {
472 let value = Value::Float(f64::NAN);
473 let result = TypedValue::from_value(&value);
474 assert!(matches!(result, Err(SerializeError::NonFiniteFloat(_))));
475 }
476
477 #[test]
478 fn test_infinity_not_serializable() {
479 let value = Value::Float(f64::INFINITY);
480 let result = TypedValue::from_value(&value);
481 assert!(matches!(result, Err(SerializeError::NonFiniteFloat(_))));
482
483 let value = Value::Float(f64::NEG_INFINITY);
484 let result = TypedValue::from_value(&value);
485 assert!(matches!(result, Err(SerializeError::NonFiniteFloat(_))));
486 }
487
488 #[test]
489 fn test_corrupted_data_returns_error() {
490 let corrupted = vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
492 let result = TypedValue::from_bytes(&corrupted);
493 assert!(result.is_err());
494 }
495
496 #[test]
497 fn test_empty_data_returns_error() {
498 let result = TypedValue::from_bytes(&[]);
499 assert!(result.is_err());
500 }
501
502 #[test]
503 fn test_truncated_data_returns_error() {
504 let typed = TypedValue::String("hello world".to_string());
506 let bytes = typed.to_bytes().unwrap();
507 let truncated = &bytes[..bytes.len() / 2];
508 let result = TypedValue::from_bytes(truncated);
509 assert!(result.is_err());
510 }
511}