1use std::sync::Arc;
50
51use arc_swap::ArcSwap;
52use num_bigint::BigInt;
53
54use crate::collections::{PersistentHashSet, PersistentVector, SortedMap, SortedSet};
55use crate::error::ValueError;
56use crate::shared::{SharedAtom, SharedValue};
57use crate::types::DelayState;
58use crate::{Keyword, MapValue, PersistentList, PersistentQueue, SetValue, Symbol, Value};
59use cljrs_gc::GcPtr;
60
61#[derive(Debug, Clone, PartialEq, Eq)]
65pub enum CloneError {
66 NotShareable {
68 type_name: &'static str,
70 },
71 Disconnected,
73}
74
75impl std::fmt::Display for CloneError {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 match self {
78 CloneError::NotShareable { type_name } => {
79 write!(
80 f,
81 "value of type `{type_name}` cannot cross an isolate boundary"
82 )
83 }
84 CloneError::Disconnected => write!(f, "isolate channel is disconnected"),
85 }
86 }
87}
88
89impl std::error::Error for CloneError {}
90
91fn not_shareable(type_name: &'static str) -> CloneError {
92 CloneError::NotShareable { type_name }
93}
94
95#[derive(Clone, Debug)]
101pub enum SerializedValue {
102 Nil,
104 Bool(bool),
105 Long(i64),
106 Double(f64),
107 BigInt(BigInt),
108 BigDecimal(bigdecimal::BigDecimal),
109 Ratio(num_rational::Ratio<BigInt>),
110 Char(char),
111 Str(String),
112 Uuid(u128),
113 Pattern(String),
115
116 Symbol {
118 namespace: Option<Arc<str>>,
119 name: Arc<str>,
120 version: Option<Arc<str>>,
121 },
122 Keyword {
123 namespace: Option<Arc<str>>,
124 name: Arc<str>,
125 },
126
127 List(Vec<SerializedValue>),
129 Vector(Vec<SerializedValue>),
130 ArrayMap(Vec<(SerializedValue, SerializedValue)>),
131 HashMap(Vec<(SerializedValue, SerializedValue)>),
132 SortedMap(Vec<(SerializedValue, SerializedValue)>),
133 HashSet(Vec<SerializedValue>),
134 SortedSet(Vec<SerializedValue>),
135 Queue(Vec<SerializedValue>),
136 Cons {
137 head: Box<SerializedValue>,
138 tail: Box<SerializedValue>,
139 },
140
141 TypeInstance {
143 type_tag: Arc<str>,
144 fields: Vec<(SerializedValue, SerializedValue)>,
145 },
146
147 Error(Box<SerializedError>),
149
150 BooleanArray(Vec<bool>),
152 ByteArray(Vec<i8>),
153 ShortArray(Vec<i16>),
154 IntArray(Vec<i32>),
155 LongArray(Vec<i64>),
156 FloatArray(Vec<f32>),
157 DoubleArray(Vec<f64>),
158 CharArray(Vec<char>),
159 ObjectArray(Vec<SerializedValue>),
160
161 WithMeta {
163 value: Box<SerializedValue>,
164 meta: Box<SerializedValue>,
165 },
166 Reduced(Box<SerializedValue>),
167
168 SharedAtom(Arc<SharedAtom>),
172 ByteBlob(Arc<[u8]>),
174 Var {
180 namespace: Arc<str>,
181 name: Arc<str>,
182 is_macro: bool,
183 shared_root: Arc<ArcSwap<Option<SharedValue>>>,
184 },
185}
186
187const _: () = {
189 const fn _assert_send<T: Send + Sync>() {}
190 let _ = _assert_send::<SerializedValue>;
191};
192
193impl SerializedValue {
194 pub fn byte_size(&self) -> usize {
202 const NODE: usize = std::mem::size_of::<SerializedValue>();
205
206 let payload = match self {
207 SerializedValue::Nil
208 | SerializedValue::Bool(_)
209 | SerializedValue::Long(_)
210 | SerializedValue::Double(_)
211 | SerializedValue::Char(_)
212 | SerializedValue::Uuid(_) => 0,
213
214 SerializedValue::BigInt(b) => (b.bits() as usize / 8) + 1,
215 SerializedValue::Ratio(r) => {
216 (r.numer().bits() as usize + r.denom().bits() as usize) / 8 + 2
217 }
218 SerializedValue::BigDecimal(_) => 16,
219
220 SerializedValue::Str(s) => s.len(),
221 SerializedValue::Pattern(s) => s.len(),
222
223 SerializedValue::Symbol {
224 namespace, name, ..
225 } => namespace.as_ref().map_or(0, |n| n.len()) + name.len(),
226 SerializedValue::Keyword { namespace, name } => {
227 namespace.as_ref().map_or(0, |n| n.len()) + name.len()
228 }
229
230 SerializedValue::List(items)
231 | SerializedValue::Vector(items)
232 | SerializedValue::HashSet(items)
233 | SerializedValue::SortedSet(items)
234 | SerializedValue::Queue(items)
235 | SerializedValue::ObjectArray(items) => {
236 items.iter().map(SerializedValue::byte_size).sum()
237 }
238
239 SerializedValue::ArrayMap(pairs)
240 | SerializedValue::HashMap(pairs)
241 | SerializedValue::SortedMap(pairs) => pairs
242 .iter()
243 .map(|(k, v)| k.byte_size() + v.byte_size())
244 .sum(),
245
246 SerializedValue::TypeInstance { fields, .. } => fields
247 .iter()
248 .map(|(k, v)| k.byte_size() + v.byte_size())
249 .sum(),
250
251 SerializedValue::Cons { head, tail } => head.byte_size() + tail.byte_size(),
252
253 SerializedValue::Error(e) => e.byte_size(),
254
255 SerializedValue::BooleanArray(v) => v.len(),
256 SerializedValue::ByteArray(v) => v.len(),
257 SerializedValue::ShortArray(v) => std::mem::size_of_val(v.as_slice()),
258 SerializedValue::IntArray(v) => std::mem::size_of_val(v.as_slice()),
259 SerializedValue::LongArray(v) => std::mem::size_of_val(v.as_slice()),
260 SerializedValue::FloatArray(v) => std::mem::size_of_val(v.as_slice()),
261 SerializedValue::DoubleArray(v) => std::mem::size_of_val(v.as_slice()),
262 SerializedValue::CharArray(v) => std::mem::size_of_val(v.as_slice()),
263
264 SerializedValue::WithMeta { value, meta } => value.byte_size() + meta.byte_size(),
265 SerializedValue::Reduced(inner) => inner.byte_size(),
266
267 SerializedValue::SharedAtom(_) | SerializedValue::ByteBlob(_) => 0,
269
270 SerializedValue::Var {
272 namespace, name, ..
273 } => namespace.len() + name.len(),
274 };
275
276 NODE + payload
277 }
278}
279
280impl SerializedError {
281 fn byte_size(&self) -> usize {
282 std::mem::size_of::<SerializedError>()
283 + self.message.len()
284 + self.data.as_ref().map_or(0, |pairs| {
285 pairs
286 .iter()
287 .map(|(k, v)| k.byte_size() + v.byte_size())
288 .sum()
289 })
290 + self.cause.as_ref().map_or(0, |c| c.byte_size())
291 }
292}
293
294#[derive(Clone, Debug)]
296pub struct SerializedError {
297 pub kind: SerializedErrorKind,
298 pub message: String,
299 pub data: Option<Vec<(SerializedValue, SerializedValue)>>,
300 pub cause: Option<Box<SerializedError>>,
301}
302
303#[derive(Clone, Debug)]
305pub enum SerializedErrorKind {
306 WrongType {
307 expected: &'static str,
308 got: String,
309 },
310 IndexOutOfBounds {
311 idx: usize,
312 count: usize,
313 },
314 ArityError {
315 name: String,
316 expected: String,
317 got: usize,
318 },
319 NotCallable {
320 value: String,
321 },
322 OddMap {
323 count: usize,
324 },
325 Unsupported,
326 Other(String),
327 GasExhausted,
328 OutOfRange,
329 TransientAlreadyPersisted,
330 Parse,
331 Thrown(Box<SerializedValue>),
332}
333
334pub fn serialize(v: &Value) -> Result<SerializedValue, CloneError> {
339 match v {
340 Value::WithMeta(inner, meta) => Ok(SerializedValue::WithMeta {
342 value: Box::new(serialize(inner)?),
343 meta: Box::new(serialize(meta)?),
344 }),
345 Value::Reduced(inner) => Ok(SerializedValue::Reduced(Box::new(serialize(inner)?))),
346
347 Value::Nil => Ok(SerializedValue::Nil),
349 Value::Bool(b) => Ok(SerializedValue::Bool(*b)),
350 Value::Long(n) => Ok(SerializedValue::Long(*n)),
351 Value::Double(d) => Ok(SerializedValue::Double(*d)),
352 Value::Char(c) => Ok(SerializedValue::Char(*c)),
353 Value::Uuid(u) => Ok(SerializedValue::Uuid(*u)),
354
355 Value::BigInt(p) => Ok(SerializedValue::BigInt(p.get().clone())),
356 Value::BigDecimal(p) => Ok(SerializedValue::BigDecimal(p.get().clone())),
357 Value::Ratio(p) => Ok(SerializedValue::Ratio(p.get().clone())),
358 Value::Str(p) => Ok(SerializedValue::Str(p.get().clone())),
359 Value::Pattern(p) => Ok(SerializedValue::Pattern(p.get().as_str().to_owned())),
360
361 Value::Symbol(p) => {
363 let s = p.get();
364 Ok(SerializedValue::Symbol {
365 namespace: s.namespace.clone(),
366 name: s.name.clone(),
367 version: s.version.clone(),
368 })
369 }
370 Value::Keyword(p) => {
371 let k = p.get();
372 Ok(SerializedValue::Keyword {
373 namespace: k.namespace.clone(),
374 name: k.name.clone(),
375 })
376 }
377
378 Value::List(p) => {
380 let items: Result<Vec<_>, _> = p.get().iter().map(serialize).collect();
381 Ok(SerializedValue::List(items?))
382 }
383 Value::Vector(p) => {
384 let items: Result<Vec<_>, _> = p.get().iter().map(serialize).collect();
385 Ok(SerializedValue::Vector(items?))
386 }
387 Value::Map(m) => serialize_map(m),
388 Value::Set(s) => serialize_set(s),
389 Value::Queue(p) => {
390 let items: Result<Vec<_>, _> = p.get().iter().map(serialize).collect();
391 Ok(SerializedValue::Queue(items?))
392 }
393 Value::Cons(p) => {
394 let c = p.get();
395 Ok(SerializedValue::Cons {
396 head: Box::new(serialize(&c.head)?),
397 tail: Box::new(serialize(&c.tail)?),
398 })
399 }
400
401 Value::TypeInstance(p) => {
403 let ti = p.get();
404 let fields = match ti.mutable.as_ref().map(|a| a.get().deref()) {
408 Some(Value::Map(mm)) => {
409 let mut merged = ti.fields.clone();
410 for (k, v) in mm.iter() {
411 merged = merged.assoc(k.clone(), v.clone());
412 }
413 serialize_map_pairs(&merged)?
414 }
415 _ => serialize_map_pairs(&ti.fields)?,
416 };
417 Ok(SerializedValue::TypeInstance {
418 type_tag: ti.type_tag.clone(),
419 fields,
420 })
421 }
422
423 Value::Error(p) => Ok(SerializedValue::Error(Box::new(serialize_error(p.get())?))),
425
426 Value::BooleanArray(p) => Ok(SerializedValue::BooleanArray(
428 p.get().lock().unwrap().clone(),
429 )),
430 Value::ByteArray(p) => Ok(SerializedValue::ByteArray(p.get().lock().unwrap().clone())),
431 Value::ShortArray(p) => Ok(SerializedValue::ShortArray(p.get().lock().unwrap().clone())),
432 Value::IntArray(p) => Ok(SerializedValue::IntArray(p.get().lock().unwrap().clone())),
433 Value::LongArray(p) => Ok(SerializedValue::LongArray(p.get().lock().unwrap().clone())),
434 Value::FloatArray(p) => Ok(SerializedValue::FloatArray(p.get().lock().unwrap().clone())),
435 Value::DoubleArray(p) => Ok(SerializedValue::DoubleArray(
436 p.get().lock().unwrap().clone(),
437 )),
438 Value::CharArray(p) => Ok(SerializedValue::CharArray(p.get().lock().unwrap().clone())),
439 Value::ObjectArray(p) => {
440 let guard = p.get().0.lock().unwrap();
441 let items: Result<Vec<_>, _> = guard.iter().map(serialize).collect();
442 Ok(SerializedValue::ObjectArray(items?))
443 }
444
445 Value::LazySeq(p) => serialize(&p.get().realize()),
447
448 Value::Delay(p) => {
450 let state = p.get().state.lock().unwrap();
451 if let DelayState::Forced(v) = &*state {
452 serialize(v)
453 } else {
454 Err(not_shareable("delay"))
455 }
456 }
457
458 Value::Resource(_) => Err(not_shareable("resource")),
460 Value::NativeObject(_) => Err(not_shareable("native-object")),
461 Value::Matcher(_) => Err(not_shareable("matcher")),
462
463 Value::Fn(_) | Value::Macro(_) => Err(not_shareable("fn")),
464 Value::BoundFn(_) => Err(not_shareable("fn")),
465 Value::NativeFunction(_) => Err(not_shareable("fn")),
466 Value::ProtocolFn(_) => Err(not_shareable("fn")),
467 Value::MultiFn(_) => Err(not_shareable("fn")),
468
469 Value::Var(p) => {
471 let var = p.get();
472 let shared_empty = var.shared_root.load().is_none();
479 if shared_empty && var.is_bound() {
480 return Err(not_shareable("var"));
481 }
482 Ok(SerializedValue::Var {
483 namespace: var.namespace.clone(),
484 name: var.name.clone(),
485 is_macro: var.is_macro,
486 shared_root: var.shared_root.clone(),
487 })
488 }
489 Value::Atom(_) => Err(not_shareable("atom")),
490 Value::Volatile(_) => Err(not_shareable("volatile")),
491 Value::Promise(_) => Err(not_shareable("promise")),
492 Value::Future(_) => Err(not_shareable("future")),
493 Value::Agent(_) => Err(not_shareable("agent")),
494
495 Value::Namespace(_) => Err(not_shareable("namespace")),
496 Value::Protocol(_) => Err(not_shareable("protocol")),
497
498 Value::TransientMap(_) => Err(not_shareable("transient-map")),
499 Value::TransientSet(_) => Err(not_shareable("transient-set")),
500 Value::TransientVector(_) => Err(not_shareable("transient-vector")),
501
502 Value::SharedAtom(a) => Ok(SerializedValue::SharedAtom(a.clone())),
504 Value::ByteBlob(b) => Ok(SerializedValue::ByteBlob(b.clone())),
505 }
506}
507
508fn serialize_map(m: &MapValue) -> Result<SerializedValue, CloneError> {
509 let pairs = serialize_map_pairs(m)?;
510 Ok(match m {
511 MapValue::Array(_) => SerializedValue::ArrayMap(pairs),
512 MapValue::Hash(_) => SerializedValue::HashMap(pairs),
513 MapValue::Sorted(_) => SerializedValue::SortedMap(pairs),
514 })
515}
516
517fn serialize_map_pairs(
518 m: &MapValue,
519) -> Result<Vec<(SerializedValue, SerializedValue)>, CloneError> {
520 let mut pairs = Vec::with_capacity(m.count());
521 let mut err: Option<CloneError> = None;
522 m.for_each(|k, v| {
523 if err.is_some() {
524 return;
525 }
526 match (serialize(k), serialize(v)) {
527 (Ok(sk), Ok(sv)) => pairs.push((sk, sv)),
528 (Err(e), _) | (_, Err(e)) => err = Some(e),
529 }
530 });
531 if let Some(e) = err { Err(e) } else { Ok(pairs) }
532}
533
534fn serialize_set(s: &SetValue) -> Result<SerializedValue, CloneError> {
535 let items: Result<Vec<_>, _> = s.iter().map(serialize).collect();
536 Ok(match s {
537 SetValue::Hash(_) => SerializedValue::HashSet(items?),
538 SetValue::Sorted(_) => SerializedValue::SortedSet(items?),
539 })
540}
541
542fn serialize_error(e: &crate::error::ExceptionInfo) -> Result<SerializedError, CloneError> {
543 let kind = match &e.error {
544 ValueError::WrongType { expected, got } => SerializedErrorKind::WrongType {
545 expected,
546 got: got.clone(),
547 },
548 ValueError::IndexOutOfBounds { idx, count } => SerializedErrorKind::IndexOutOfBounds {
549 idx: *idx,
550 count: *count,
551 },
552 ValueError::ArityError {
553 name,
554 expected,
555 got,
556 } => SerializedErrorKind::ArityError {
557 name: name.clone(),
558 expected: expected.clone(),
559 got: *got,
560 },
561 ValueError::NotCallable { value } => SerializedErrorKind::NotCallable {
562 value: value.clone(),
563 },
564 ValueError::OddMap { count } => SerializedErrorKind::OddMap { count: *count },
565 ValueError::Unsupported => SerializedErrorKind::Unsupported,
566 ValueError::Other(s) => SerializedErrorKind::Other(s.clone()),
567 ValueError::GasExhausted => SerializedErrorKind::GasExhausted,
568 ValueError::OutOfRange => SerializedErrorKind::OutOfRange,
569 ValueError::TransientAlreadyPersisted => SerializedErrorKind::TransientAlreadyPersisted,
570 ValueError::Parse => SerializedErrorKind::Parse,
571 ValueError::Thrown(v) => SerializedErrorKind::Thrown(Box::new(serialize(v)?)),
572 };
573
574 let data = e.data.as_ref().map(serialize_map_pairs).transpose()?;
575
576 let cause = e
577 .cause
578 .as_ref()
579 .map(|c| serialize_error(c.get()).map(Box::new))
580 .transpose()?;
581
582 Ok(SerializedError {
583 kind,
584 message: e.message.clone(),
585 data,
586 cause,
587 })
588}
589
590pub fn deserialize(sv: SerializedValue) -> Value {
596 match sv {
597 SerializedValue::WithMeta { value, meta } => {
598 Value::WithMeta(Box::new(deserialize(*value)), Box::new(deserialize(*meta)))
599 }
600 SerializedValue::Reduced(inner) => Value::Reduced(Box::new(deserialize(*inner))),
601
602 SerializedValue::Nil => Value::Nil,
603 SerializedValue::Bool(b) => Value::Bool(b),
604 SerializedValue::Long(n) => Value::Long(n),
605 SerializedValue::Double(d) => Value::Double(d),
606 SerializedValue::Char(c) => Value::Char(c),
607 SerializedValue::Uuid(u) => Value::Uuid(u),
608
609 SerializedValue::BigInt(n) => Value::BigInt(GcPtr::new(n)),
610 SerializedValue::BigDecimal(d) => Value::BigDecimal(GcPtr::new(d)),
611 SerializedValue::Ratio(r) => Value::Ratio(GcPtr::new(r)),
612 SerializedValue::Str(s) => Value::Str(GcPtr::new(s)),
613 SerializedValue::Pattern(src) => Value::Pattern(GcPtr::new(
614 crate::regex::Pattern::new(&src).expect("pattern was valid at serialize time"),
615 )),
616
617 SerializedValue::Symbol {
618 namespace,
619 name,
620 version,
621 } => Value::Symbol(GcPtr::new(Symbol {
622 namespace,
623 name,
624 version,
625 })),
626 SerializedValue::Keyword { namespace, name } => {
627 Value::Keyword(GcPtr::new(Keyword { namespace, name }))
628 }
629
630 SerializedValue::List(items) => Value::List(GcPtr::new(PersistentList::from_iter(
631 items.into_iter().map(deserialize),
632 ))),
633 SerializedValue::Vector(items) => Value::Vector(GcPtr::new(PersistentVector::from_iter(
634 items.into_iter().map(deserialize),
635 ))),
636 SerializedValue::ArrayMap(pairs) => Value::Map(MapValue::from_pairs(
637 pairs
638 .into_iter()
639 .map(|(k, v)| (deserialize(k), deserialize(v)))
640 .collect(),
641 )),
642 SerializedValue::HashMap(pairs) => Value::Map(MapValue::from_pairs(
643 pairs
644 .into_iter()
645 .map(|(k, v)| (deserialize(k), deserialize(v)))
646 .collect(),
647 )),
648 SerializedValue::SortedMap(pairs) => {
649 let items: Vec<(Value, Value)> = pairs
651 .into_iter()
652 .map(|(k, v)| (deserialize(k), deserialize(v)))
653 .collect();
654 let sm = SortedMap::from_pairs(items);
655 Value::Map(MapValue::Sorted(GcPtr::new(sm)))
656 }
657 SerializedValue::HashSet(items) => {
658 let mut hs = PersistentHashSet::empty();
659 for item in items.into_iter().map(deserialize) {
660 hs = hs.conj(item);
661 }
662 Value::Set(SetValue::Hash(GcPtr::new(hs)))
663 }
664 SerializedValue::SortedSet(items) => {
665 let mut ss = SortedSet::empty();
666 for item in items.into_iter().map(deserialize) {
667 ss = ss.conj(item);
668 }
669 Value::Set(SetValue::Sorted(GcPtr::new(ss)))
670 }
671 SerializedValue::Queue(items) => {
672 let mut q = PersistentQueue::empty();
673 for item in items.into_iter().map(deserialize) {
674 q = q.conj(item);
675 }
676 Value::Queue(GcPtr::new(q))
677 }
678 SerializedValue::Cons { head, tail } => {
679 use crate::types::CljxCons;
680 Value::Cons(GcPtr::new(CljxCons {
681 head: deserialize(*head),
682 tail: deserialize(*tail),
683 }))
684 }
685
686 SerializedValue::TypeInstance { type_tag, fields } => {
687 use crate::value::TypeInstance;
688 let pairs: Vec<(Value, Value)> = fields
689 .into_iter()
690 .map(|(k, v)| (deserialize(k), deserialize(v)))
691 .collect();
692 Value::TypeInstance(GcPtr::new(TypeInstance {
693 type_tag,
694 fields: MapValue::from_pairs(pairs),
695 mutable: None,
696 }))
697 }
698
699 SerializedValue::Error(se) => Value::Error(GcPtr::new(deserialize_error(*se))),
700
701 SerializedValue::BooleanArray(v) => {
702 Value::BooleanArray(GcPtr::new(std::sync::Mutex::new(v)))
703 }
704 SerializedValue::ByteArray(v) => Value::ByteArray(GcPtr::new(std::sync::Mutex::new(v))),
705 SerializedValue::ShortArray(v) => Value::ShortArray(GcPtr::new(std::sync::Mutex::new(v))),
706 SerializedValue::IntArray(v) => Value::IntArray(GcPtr::new(std::sync::Mutex::new(v))),
707 SerializedValue::LongArray(v) => Value::LongArray(GcPtr::new(std::sync::Mutex::new(v))),
708 SerializedValue::FloatArray(v) => Value::FloatArray(GcPtr::new(std::sync::Mutex::new(v))),
709 SerializedValue::DoubleArray(v) => Value::DoubleArray(GcPtr::new(std::sync::Mutex::new(v))),
710 SerializedValue::CharArray(v) => Value::CharArray(GcPtr::new(std::sync::Mutex::new(v))),
711 SerializedValue::ObjectArray(items) => {
712 use crate::value::ObjectArray;
713 Value::ObjectArray(GcPtr::new(ObjectArray::new(
714 items.into_iter().map(deserialize).collect(),
715 )))
716 }
717
718 SerializedValue::SharedAtom(a) => Value::SharedAtom(a),
720 SerializedValue::ByteBlob(b) => Value::ByteBlob(b),
721 SerializedValue::Var {
722 namespace,
723 name,
724 is_macro,
725 shared_root,
726 } => Value::Var(GcPtr::new(crate::types::Var::from_shared_root(
727 namespace,
728 name,
729 is_macro,
730 shared_root,
731 ))),
732 }
733}
734
735fn deserialize_error(se: SerializedError) -> crate::error::ExceptionInfo {
736 let error = match se.kind {
737 SerializedErrorKind::WrongType { expected, got } => ValueError::WrongType { expected, got },
738 SerializedErrorKind::IndexOutOfBounds { idx, count } => {
739 ValueError::IndexOutOfBounds { idx, count }
740 }
741 SerializedErrorKind::ArityError {
742 name,
743 expected,
744 got,
745 } => ValueError::ArityError {
746 name,
747 expected,
748 got,
749 },
750 SerializedErrorKind::NotCallable { value } => ValueError::NotCallable { value },
751 SerializedErrorKind::OddMap { count } => ValueError::OddMap { count },
752 SerializedErrorKind::Unsupported => ValueError::Unsupported,
753 SerializedErrorKind::Other(s) => ValueError::Other(s),
754 SerializedErrorKind::GasExhausted => ValueError::GasExhausted,
755 SerializedErrorKind::OutOfRange => ValueError::OutOfRange,
756 SerializedErrorKind::TransientAlreadyPersisted => ValueError::TransientAlreadyPersisted,
757 SerializedErrorKind::Parse => ValueError::Parse,
758 SerializedErrorKind::Thrown(sv) => ValueError::Thrown(deserialize(*sv)),
759 };
760
761 let data = se.data.map(|pairs| {
762 MapValue::from_pairs(
763 pairs
764 .into_iter()
765 .map(|(k, v)| (deserialize(k), deserialize(v)))
766 .collect(),
767 )
768 });
769
770 let cause = se.cause.map(|c| GcPtr::new(deserialize_error(*c)));
771
772 crate::error::ExceptionInfo::new(error, se.message, data, cause)
773}
774
775#[cfg(test)]
778mod tests {
779 use super::*;
780
781 fn roundtrip(v: &Value) -> Value {
782 deserialize(serialize(v).expect("serialize"))
783 }
784
785 #[test]
786 fn scalars_roundtrip() {
787 assert_eq!(roundtrip(&Value::Nil), Value::Nil);
788 assert_eq!(roundtrip(&Value::Bool(true)), Value::Bool(true));
789 assert_eq!(roundtrip(&Value::Long(42)), Value::Long(42));
790 assert_eq!(roundtrip(&Value::Char('x')), Value::Char('x'));
791 assert_eq!(roundtrip(&Value::Uuid(12345)), Value::Uuid(12345));
792 }
793
794 #[test]
795 fn string_roundtrip() {
796 let v = Value::string("hello, world");
797 assert_eq!(roundtrip(&v), v);
798 }
799
800 #[test]
801 fn keyword_roundtrip() {
802 let v = Value::keyword(Keyword::simple("foo"));
803 assert_eq!(roundtrip(&v), v);
804 let v2 = Value::keyword(Keyword::qualified("clojure.core", "map"));
805 assert_eq!(roundtrip(&v2), v2);
806 }
807
808 #[test]
809 fn symbol_roundtrip() {
810 let v = Value::symbol(Symbol::simple("my-fn"));
811 assert_eq!(roundtrip(&v), v);
812 }
813
814 #[test]
815 fn list_roundtrip() {
816 let v = Value::List(GcPtr::new(PersistentList::from_iter([
817 Value::Long(1),
818 Value::Long(2),
819 Value::Long(3),
820 ])));
821 assert_eq!(roundtrip(&v), v);
822 }
823
824 #[test]
825 fn vector_roundtrip() {
826 let v = Value::Vector(GcPtr::new(PersistentVector::from_iter([
827 Value::string("a"),
828 Value::Bool(false),
829 Value::Nil,
830 ])));
831 assert_eq!(roundtrip(&v), v);
832 }
833
834 #[test]
835 fn nested_map_roundtrip() {
836 let inner = Value::Vector(GcPtr::new(PersistentVector::from_iter([Value::Long(1)])));
837 let v = MapValue::from_pairs(vec![(Value::keyword(Keyword::simple("k")), inner)]);
838 let v = Value::Map(v);
839 assert_eq!(roundtrip(&v), v);
840 }
841
842 #[test]
843 fn resource_not_shareable() {
844 use crate::resource::ResourceHandle;
845 use std::any::Any;
846 use std::sync::Arc;
847 #[derive(Debug)]
848 struct FakeResource;
849 impl crate::resource::Resource for FakeResource {
850 fn resource_type(&self) -> &'static str {
851 "fake"
852 }
853 fn close(&self) -> crate::error::ValueResult<()> {
854 Ok(())
855 }
856 fn is_closed(&self) -> bool {
857 false
858 }
859 fn as_any(&self) -> &dyn Any {
860 self
861 }
862 }
863 let r = Value::Resource(ResourceHandle(Arc::new(FakeResource)));
864 assert!(matches!(
865 serialize(&r),
866 Err(CloneError::NotShareable {
867 type_name: "resource"
868 })
869 ));
870 }
871
872 #[test]
873 fn atom_not_shareable() {
874 use crate::types::Atom;
875 let a = Value::Atom(GcPtr::new(Atom::new(Value::Nil)));
876 assert!(matches!(
877 serialize(&a),
878 Err(CloneError::NotShareable { type_name: "atom" })
879 ));
880 }
881
882 #[test]
883 fn fn_not_shareable() {
884 use crate::types::{Arity, NativeFn};
885 let nf = Value::NativeFunction(GcPtr::new(NativeFn::new("test", Arity::Fixed(0), |_| {
886 Ok(Value::Nil)
887 })));
888 assert!(matches!(
889 serialize(&nf),
890 Err(CloneError::NotShareable { type_name: "fn" })
891 ));
892 }
893
894 #[test]
895 fn lazy_seq_realized_roundtrip() {
896 use crate::types::{LazySeq, Thunk};
897 struct DoneThunk;
898 impl std::fmt::Debug for DoneThunk {
899 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
900 write!(f, "DoneThunk")
901 }
902 }
903 impl cljrs_gc::Trace for DoneThunk {
904 fn trace(&self, _: &mut cljrs_gc::MarkVisitor) {}
905 }
906 impl Thunk for DoneThunk {
907 fn force(&self) -> Result<Value, String> {
908 Ok(Value::Long(99))
909 }
910 }
911 let ls = LazySeq::new(Box::new(DoneThunk));
912 let _ = ls.realize(); let v = Value::LazySeq(GcPtr::new(ls));
914 assert_eq!(roundtrip(&v), Value::Long(99));
915 }
916
917 #[test]
918 fn with_meta_roundtrip() {
919 let v = Value::Long(7).with_meta(Value::Map(MapValue::empty()));
920 let rt = roundtrip(&v);
921 assert_eq!(rt, Value::Long(7));
923 }
924
925 #[test]
926 fn reduced_roundtrip() {
927 let v = Value::Reduced(Box::new(Value::Long(55)));
928 assert_eq!(roundtrip(&v), Value::Reduced(Box::new(Value::Long(55))));
929 }
930
931 #[test]
932 fn byte_size_counts_string_payload() {
933 let small = serialize(&Value::string("hi")).unwrap();
934 let large = serialize(&Value::string("x".repeat(1000))).unwrap();
935 assert!(large.byte_size() > small.byte_size() + 900);
937 }
938
939 #[test]
940 fn byte_size_grows_with_collection() {
941 let small = serialize(&Value::Vector(GcPtr::new(PersistentVector::from_iter([
942 Value::Long(1),
943 ]))))
944 .unwrap();
945 let large = serialize(&Value::Vector(GcPtr::new(PersistentVector::from_iter(
946 (0..100).map(Value::Long),
947 ))))
948 .unwrap();
949 assert!(large.byte_size() > small.byte_size());
950 }
951
952 #[test]
953 fn var_with_promotable_root_roundtrips() {
954 use crate::types::Var;
955 let var = Var::new("user", "answer");
957 var.bind(Value::Long(42));
958 let v = Value::Var(GcPtr::new(var));
959
960 let crossed = roundtrip(&v);
961 if let Value::Var(p) = crossed {
962 let got = p.get();
963 assert_eq!(got.namespace.as_ref(), "user");
964 assert_eq!(got.name.as_ref(), "answer");
965 assert_eq!(got.deref(), Some(Value::Long(42)));
967 } else {
968 panic!("expected a Var on the receiving side");
969 }
970 }
971
972 #[test]
973 fn var_keyword_root_preserves_identity() {
974 use crate::types::Var;
975 let var = Var::new("user", "k");
976 var.bind(Value::keyword(Keyword::qualified("ns", "kw")));
977 let v = Value::Var(GcPtr::new(var));
978
979 let crossed = roundtrip(&v);
980 let Value::Var(p) = crossed else {
981 panic!("expected Var")
982 };
983 assert_eq!(
985 p.get().deref(),
986 Some(Value::keyword(Keyword::qualified("ns", "kw")))
987 );
988 }
989
990 #[test]
991 fn var_shares_root_cell_across_boundary() {
992 use crate::types::Var;
993 let var = GcPtr::new(Var::new("user", "shared"));
996 var.get().bind(Value::Long(1));
997 let v = Value::Var(var.clone());
998
999 let Value::Var(recv) = roundtrip(&v) else {
1000 panic!("expected Var")
1001 };
1002 assert_eq!(recv.get().deref_shared(), Some(Value::Long(1)));
1003
1004 var.get().bind(Value::Long(2));
1006 assert_eq!(recv.get().deref_shared(), Some(Value::Long(2)));
1007 }
1008
1009 #[test]
1010 fn var_with_nonpromotable_root_is_not_shareable() {
1011 use crate::types::{Arity, NativeFn, Var};
1012 let var = Var::new("user", "f");
1014 var.bind(Value::NativeFunction(GcPtr::new(NativeFn::new(
1015 "f",
1016 Arity::Fixed(0),
1017 |_| Ok(Value::Nil),
1018 ))));
1019 let v = Value::Var(GcPtr::new(var));
1020 assert!(matches!(
1021 serialize(&v),
1022 Err(CloneError::NotShareable { type_name: "var" })
1023 ));
1024 }
1025
1026 #[test]
1027 fn unbound_var_crosses_as_unbound() {
1028 use crate::types::Var;
1029 let v = Value::Var(GcPtr::new(Var::new("user", "later")));
1030 let Value::Var(p) = roundtrip(&v) else {
1031 panic!("expected Var")
1032 };
1033 assert!(!p.get().is_bound());
1034 }
1035
1036 #[test]
1037 fn byte_size_scalar_is_node_sized() {
1038 let node = std::mem::size_of::<SerializedValue>();
1040 assert_eq!(serialize(&Value::Long(7)).unwrap().byte_size(), node);
1041 assert_eq!(serialize(&Value::Nil).unwrap().byte_size(), node);
1042 }
1043}