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