1use std::sync::Arc;
39
40use num_bigint::BigInt;
41
42use crate::collections::{PersistentHashSet, PersistentVector, SortedMap, SortedSet};
43use crate::error::ValueError;
44use crate::shared::SharedAtom;
45use crate::types::DelayState;
46use crate::{Keyword, MapValue, PersistentList, PersistentQueue, SetValue, Symbol, Value};
47use cljrs_gc::GcPtr;
48
49#[derive(Debug, Clone, PartialEq, Eq)]
53pub enum CloneError {
54 NotShareable {
56 type_name: &'static str,
58 },
59 Disconnected,
61}
62
63impl std::fmt::Display for CloneError {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 match self {
66 CloneError::NotShareable { type_name } => {
67 write!(
68 f,
69 "value of type `{type_name}` cannot cross an isolate boundary"
70 )
71 }
72 CloneError::Disconnected => write!(f, "isolate channel is disconnected"),
73 }
74 }
75}
76
77impl std::error::Error for CloneError {}
78
79fn not_shareable(type_name: &'static str) -> CloneError {
80 CloneError::NotShareable { type_name }
81}
82
83#[derive(Clone, Debug)]
89pub enum SerializedValue {
90 Nil,
92 Bool(bool),
93 Long(i64),
94 Double(f64),
95 BigInt(BigInt),
96 BigDecimal(bigdecimal::BigDecimal),
97 Ratio(num_rational::Ratio<BigInt>),
98 Char(char),
99 Str(String),
100 Uuid(u128),
101 Pattern(String),
103
104 Symbol {
106 namespace: Option<Arc<str>>,
107 name: Arc<str>,
108 version: Option<Arc<str>>,
109 },
110 Keyword {
111 namespace: Option<Arc<str>>,
112 name: Arc<str>,
113 },
114
115 List(Vec<SerializedValue>),
117 Vector(Vec<SerializedValue>),
118 ArrayMap(Vec<(SerializedValue, SerializedValue)>),
119 HashMap(Vec<(SerializedValue, SerializedValue)>),
120 SortedMap(Vec<(SerializedValue, SerializedValue)>),
121 HashSet(Vec<SerializedValue>),
122 SortedSet(Vec<SerializedValue>),
123 Queue(Vec<SerializedValue>),
124 Cons {
125 head: Box<SerializedValue>,
126 tail: Box<SerializedValue>,
127 },
128
129 TypeInstance {
131 type_tag: Arc<str>,
132 fields: Vec<(SerializedValue, SerializedValue)>,
133 },
134
135 Error(Box<SerializedError>),
137
138 BooleanArray(Vec<bool>),
140 ByteArray(Vec<i8>),
141 ShortArray(Vec<i16>),
142 IntArray(Vec<i32>),
143 LongArray(Vec<i64>),
144 FloatArray(Vec<f32>),
145 DoubleArray(Vec<f64>),
146 CharArray(Vec<char>),
147 ObjectArray(Vec<SerializedValue>),
148
149 WithMeta {
151 value: Box<SerializedValue>,
152 meta: Box<SerializedValue>,
153 },
154 Reduced(Box<SerializedValue>),
155
156 SharedAtom(Arc<SharedAtom>),
160 ByteBlob(Arc<[u8]>),
162}
163
164const _: () = {
166 const fn _assert_send<T: Send + Sync>() {}
167 let _ = _assert_send::<SerializedValue>;
168};
169
170#[derive(Clone, Debug)]
172pub struct SerializedError {
173 pub kind: SerializedErrorKind,
174 pub message: String,
175 pub data: Option<Vec<(SerializedValue, SerializedValue)>>,
176 pub cause: Option<Box<SerializedError>>,
177}
178
179#[derive(Clone, Debug)]
181pub enum SerializedErrorKind {
182 WrongType {
183 expected: &'static str,
184 got: String,
185 },
186 IndexOutOfBounds {
187 idx: usize,
188 count: usize,
189 },
190 ArityError {
191 name: String,
192 expected: String,
193 got: usize,
194 },
195 NotCallable {
196 value: String,
197 },
198 OddMap {
199 count: usize,
200 },
201 Unsupported,
202 Other(String),
203 OutOfRange,
204 TransientAlreadyPersisted,
205 Parse,
206 Thrown(Box<SerializedValue>),
207}
208
209pub fn serialize(v: &Value) -> Result<SerializedValue, CloneError> {
214 match v {
215 Value::WithMeta(inner, meta) => Ok(SerializedValue::WithMeta {
217 value: Box::new(serialize(inner)?),
218 meta: Box::new(serialize(meta)?),
219 }),
220 Value::Reduced(inner) => Ok(SerializedValue::Reduced(Box::new(serialize(inner)?))),
221
222 Value::Nil => Ok(SerializedValue::Nil),
224 Value::Bool(b) => Ok(SerializedValue::Bool(*b)),
225 Value::Long(n) => Ok(SerializedValue::Long(*n)),
226 Value::Double(d) => Ok(SerializedValue::Double(*d)),
227 Value::Char(c) => Ok(SerializedValue::Char(*c)),
228 Value::Uuid(u) => Ok(SerializedValue::Uuid(*u)),
229
230 Value::BigInt(p) => Ok(SerializedValue::BigInt(p.get().clone())),
231 Value::BigDecimal(p) => Ok(SerializedValue::BigDecimal(p.get().clone())),
232 Value::Ratio(p) => Ok(SerializedValue::Ratio(p.get().clone())),
233 Value::Str(p) => Ok(SerializedValue::Str(p.get().clone())),
234 Value::Pattern(p) => Ok(SerializedValue::Pattern(p.get().as_str().to_owned())),
235
236 Value::Symbol(p) => {
238 let s = p.get();
239 Ok(SerializedValue::Symbol {
240 namespace: s.namespace.clone(),
241 name: s.name.clone(),
242 version: s.version.clone(),
243 })
244 }
245 Value::Keyword(p) => {
246 let k = p.get();
247 Ok(SerializedValue::Keyword {
248 namespace: k.namespace.clone(),
249 name: k.name.clone(),
250 })
251 }
252
253 Value::List(p) => {
255 let items: Result<Vec<_>, _> = p.get().iter().map(serialize).collect();
256 Ok(SerializedValue::List(items?))
257 }
258 Value::Vector(p) => {
259 let items: Result<Vec<_>, _> = p.get().iter().map(serialize).collect();
260 Ok(SerializedValue::Vector(items?))
261 }
262 Value::Map(m) => serialize_map(m),
263 Value::Set(s) => serialize_set(s),
264 Value::Queue(p) => {
265 let items: Result<Vec<_>, _> = p.get().iter().map(serialize).collect();
266 Ok(SerializedValue::Queue(items?))
267 }
268 Value::Cons(p) => {
269 let c = p.get();
270 Ok(SerializedValue::Cons {
271 head: Box::new(serialize(&c.head)?),
272 tail: Box::new(serialize(&c.tail)?),
273 })
274 }
275
276 Value::TypeInstance(p) => {
278 let ti = p.get();
279 let fields = serialize_map_pairs(&ti.fields)?;
280 Ok(SerializedValue::TypeInstance {
281 type_tag: ti.type_tag.clone(),
282 fields,
283 })
284 }
285
286 Value::Error(p) => Ok(SerializedValue::Error(Box::new(serialize_error(p.get())?))),
288
289 Value::BooleanArray(p) => Ok(SerializedValue::BooleanArray(
291 p.get().lock().unwrap().clone(),
292 )),
293 Value::ByteArray(p) => Ok(SerializedValue::ByteArray(p.get().lock().unwrap().clone())),
294 Value::ShortArray(p) => Ok(SerializedValue::ShortArray(p.get().lock().unwrap().clone())),
295 Value::IntArray(p) => Ok(SerializedValue::IntArray(p.get().lock().unwrap().clone())),
296 Value::LongArray(p) => Ok(SerializedValue::LongArray(p.get().lock().unwrap().clone())),
297 Value::FloatArray(p) => Ok(SerializedValue::FloatArray(p.get().lock().unwrap().clone())),
298 Value::DoubleArray(p) => Ok(SerializedValue::DoubleArray(
299 p.get().lock().unwrap().clone(),
300 )),
301 Value::CharArray(p) => Ok(SerializedValue::CharArray(p.get().lock().unwrap().clone())),
302 Value::ObjectArray(p) => {
303 let guard = p.get().0.lock().unwrap();
304 let items: Result<Vec<_>, _> = guard.iter().map(serialize).collect();
305 Ok(SerializedValue::ObjectArray(items?))
306 }
307
308 Value::LazySeq(p) => serialize(&p.get().realize()),
310
311 Value::Delay(p) => {
313 let state = p.get().state.lock().unwrap();
314 if let DelayState::Forced(v) = &*state {
315 serialize(v)
316 } else {
317 Err(not_shareable("delay"))
318 }
319 }
320
321 Value::Resource(_) => Err(not_shareable("resource")),
323 Value::NativeObject(_) => Err(not_shareable("native-object")),
324 Value::Matcher(_) => Err(not_shareable("matcher")),
325
326 Value::Fn(_) | Value::Macro(_) => Err(not_shareable("fn")),
327 Value::BoundFn(_) => Err(not_shareable("fn")),
328 Value::NativeFunction(_) => Err(not_shareable("fn")),
329 Value::ProtocolFn(_) => Err(not_shareable("fn")),
330 Value::MultiFn(_) => Err(not_shareable("fn")),
331
332 Value::Var(_) => Err(not_shareable("var")),
333 Value::Atom(_) => Err(not_shareable("atom")),
334 Value::Volatile(_) => Err(not_shareable("volatile")),
335 Value::Promise(_) => Err(not_shareable("promise")),
336 Value::Future(_) => Err(not_shareable("future")),
337 Value::Agent(_) => Err(not_shareable("agent")),
338
339 Value::Namespace(_) => Err(not_shareable("namespace")),
340 Value::Protocol(_) => Err(not_shareable("protocol")),
341
342 Value::TransientMap(_) => Err(not_shareable("transient-map")),
343 Value::TransientSet(_) => Err(not_shareable("transient-set")),
344 Value::TransientVector(_) => Err(not_shareable("transient-vector")),
345
346 Value::SharedAtom(a) => Ok(SerializedValue::SharedAtom(a.clone())),
348 Value::ByteBlob(b) => Ok(SerializedValue::ByteBlob(b.clone())),
349 }
350}
351
352fn serialize_map(m: &MapValue) -> Result<SerializedValue, CloneError> {
353 let pairs = serialize_map_pairs(m)?;
354 Ok(match m {
355 MapValue::Array(_) => SerializedValue::ArrayMap(pairs),
356 MapValue::Hash(_) => SerializedValue::HashMap(pairs),
357 MapValue::Sorted(_) => SerializedValue::SortedMap(pairs),
358 })
359}
360
361fn serialize_map_pairs(
362 m: &MapValue,
363) -> Result<Vec<(SerializedValue, SerializedValue)>, CloneError> {
364 let mut pairs = Vec::with_capacity(m.count());
365 let mut err: Option<CloneError> = None;
366 m.for_each(|k, v| {
367 if err.is_some() {
368 return;
369 }
370 match (serialize(k), serialize(v)) {
371 (Ok(sk), Ok(sv)) => pairs.push((sk, sv)),
372 (Err(e), _) | (_, Err(e)) => err = Some(e),
373 }
374 });
375 if let Some(e) = err { Err(e) } else { Ok(pairs) }
376}
377
378fn serialize_set(s: &SetValue) -> Result<SerializedValue, CloneError> {
379 let items: Result<Vec<_>, _> = s.iter().map(serialize).collect();
380 Ok(match s {
381 SetValue::Hash(_) => SerializedValue::HashSet(items?),
382 SetValue::Sorted(_) => SerializedValue::SortedSet(items?),
383 })
384}
385
386fn serialize_error(e: &crate::error::ExceptionInfo) -> Result<SerializedError, CloneError> {
387 let kind = match &e.error {
388 ValueError::WrongType { expected, got } => SerializedErrorKind::WrongType {
389 expected,
390 got: got.clone(),
391 },
392 ValueError::IndexOutOfBounds { idx, count } => SerializedErrorKind::IndexOutOfBounds {
393 idx: *idx,
394 count: *count,
395 },
396 ValueError::ArityError {
397 name,
398 expected,
399 got,
400 } => SerializedErrorKind::ArityError {
401 name: name.clone(),
402 expected: expected.clone(),
403 got: *got,
404 },
405 ValueError::NotCallable { value } => SerializedErrorKind::NotCallable {
406 value: value.clone(),
407 },
408 ValueError::OddMap { count } => SerializedErrorKind::OddMap { count: *count },
409 ValueError::Unsupported => SerializedErrorKind::Unsupported,
410 ValueError::Other(s) => SerializedErrorKind::Other(s.clone()),
411 ValueError::OutOfRange => SerializedErrorKind::OutOfRange,
412 ValueError::TransientAlreadyPersisted => SerializedErrorKind::TransientAlreadyPersisted,
413 ValueError::Parse => SerializedErrorKind::Parse,
414 ValueError::Thrown(v) => SerializedErrorKind::Thrown(Box::new(serialize(v)?)),
415 };
416
417 let data = e.data.as_ref().map(serialize_map_pairs).transpose()?;
418
419 let cause = e
420 .cause
421 .as_ref()
422 .map(|c| serialize_error(c.get()).map(Box::new))
423 .transpose()?;
424
425 Ok(SerializedError {
426 kind,
427 message: e.message.clone(),
428 data,
429 cause,
430 })
431}
432
433pub fn deserialize(sv: SerializedValue) -> Value {
439 match sv {
440 SerializedValue::WithMeta { value, meta } => {
441 Value::WithMeta(Box::new(deserialize(*value)), Box::new(deserialize(*meta)))
442 }
443 SerializedValue::Reduced(inner) => Value::Reduced(Box::new(deserialize(*inner))),
444
445 SerializedValue::Nil => Value::Nil,
446 SerializedValue::Bool(b) => Value::Bool(b),
447 SerializedValue::Long(n) => Value::Long(n),
448 SerializedValue::Double(d) => Value::Double(d),
449 SerializedValue::Char(c) => Value::Char(c),
450 SerializedValue::Uuid(u) => Value::Uuid(u),
451
452 SerializedValue::BigInt(n) => Value::BigInt(GcPtr::new(n)),
453 SerializedValue::BigDecimal(d) => Value::BigDecimal(GcPtr::new(d)),
454 SerializedValue::Ratio(r) => Value::Ratio(GcPtr::new(r)),
455 SerializedValue::Str(s) => Value::Str(GcPtr::new(s)),
456 SerializedValue::Pattern(src) => Value::Pattern(GcPtr::new(
457 regex::Regex::new(&src).expect("pattern was valid at serialize time"),
458 )),
459
460 SerializedValue::Symbol {
461 namespace,
462 name,
463 version,
464 } => Value::Symbol(GcPtr::new(Symbol {
465 namespace,
466 name,
467 version,
468 })),
469 SerializedValue::Keyword { namespace, name } => {
470 Value::Keyword(GcPtr::new(Keyword { namespace, name }))
471 }
472
473 SerializedValue::List(items) => Value::List(GcPtr::new(PersistentList::from_iter(
474 items.into_iter().map(deserialize),
475 ))),
476 SerializedValue::Vector(items) => Value::Vector(GcPtr::new(PersistentVector::from_iter(
477 items.into_iter().map(deserialize),
478 ))),
479 SerializedValue::ArrayMap(pairs) => Value::Map(MapValue::from_pairs(
480 pairs
481 .into_iter()
482 .map(|(k, v)| (deserialize(k), deserialize(v)))
483 .collect(),
484 )),
485 SerializedValue::HashMap(pairs) => Value::Map(MapValue::from_pairs(
486 pairs
487 .into_iter()
488 .map(|(k, v)| (deserialize(k), deserialize(v)))
489 .collect(),
490 )),
491 SerializedValue::SortedMap(pairs) => {
492 let items: Vec<(Value, Value)> = pairs
494 .into_iter()
495 .map(|(k, v)| (deserialize(k), deserialize(v)))
496 .collect();
497 let sm = SortedMap::from_pairs(items);
498 Value::Map(MapValue::Sorted(GcPtr::new(sm)))
499 }
500 SerializedValue::HashSet(items) => {
501 let mut hs = PersistentHashSet::empty();
502 for item in items.into_iter().map(deserialize) {
503 hs = hs.conj(item);
504 }
505 Value::Set(SetValue::Hash(GcPtr::new(hs)))
506 }
507 SerializedValue::SortedSet(items) => {
508 let mut ss = SortedSet::empty();
509 for item in items.into_iter().map(deserialize) {
510 ss = ss.conj(item);
511 }
512 Value::Set(SetValue::Sorted(GcPtr::new(ss)))
513 }
514 SerializedValue::Queue(items) => {
515 let mut q = PersistentQueue::empty();
516 for item in items.into_iter().map(deserialize) {
517 q = q.conj(item);
518 }
519 Value::Queue(GcPtr::new(q))
520 }
521 SerializedValue::Cons { head, tail } => {
522 use crate::types::CljxCons;
523 Value::Cons(GcPtr::new(CljxCons {
524 head: deserialize(*head),
525 tail: deserialize(*tail),
526 }))
527 }
528
529 SerializedValue::TypeInstance { type_tag, fields } => {
530 use crate::value::TypeInstance;
531 let pairs: Vec<(Value, Value)> = fields
532 .into_iter()
533 .map(|(k, v)| (deserialize(k), deserialize(v)))
534 .collect();
535 Value::TypeInstance(GcPtr::new(TypeInstance {
536 type_tag,
537 fields: MapValue::from_pairs(pairs),
538 }))
539 }
540
541 SerializedValue::Error(se) => Value::Error(GcPtr::new(deserialize_error(*se))),
542
543 SerializedValue::BooleanArray(v) => {
544 Value::BooleanArray(GcPtr::new(std::sync::Mutex::new(v)))
545 }
546 SerializedValue::ByteArray(v) => Value::ByteArray(GcPtr::new(std::sync::Mutex::new(v))),
547 SerializedValue::ShortArray(v) => Value::ShortArray(GcPtr::new(std::sync::Mutex::new(v))),
548 SerializedValue::IntArray(v) => Value::IntArray(GcPtr::new(std::sync::Mutex::new(v))),
549 SerializedValue::LongArray(v) => Value::LongArray(GcPtr::new(std::sync::Mutex::new(v))),
550 SerializedValue::FloatArray(v) => Value::FloatArray(GcPtr::new(std::sync::Mutex::new(v))),
551 SerializedValue::DoubleArray(v) => Value::DoubleArray(GcPtr::new(std::sync::Mutex::new(v))),
552 SerializedValue::CharArray(v) => Value::CharArray(GcPtr::new(std::sync::Mutex::new(v))),
553 SerializedValue::ObjectArray(items) => {
554 use crate::value::ObjectArray;
555 Value::ObjectArray(GcPtr::new(ObjectArray::new(
556 items.into_iter().map(deserialize).collect(),
557 )))
558 }
559
560 SerializedValue::SharedAtom(a) => Value::SharedAtom(a),
562 SerializedValue::ByteBlob(b) => Value::ByteBlob(b),
563 }
564}
565
566fn deserialize_error(se: SerializedError) -> crate::error::ExceptionInfo {
567 let error = match se.kind {
568 SerializedErrorKind::WrongType { expected, got } => ValueError::WrongType { expected, got },
569 SerializedErrorKind::IndexOutOfBounds { idx, count } => {
570 ValueError::IndexOutOfBounds { idx, count }
571 }
572 SerializedErrorKind::ArityError {
573 name,
574 expected,
575 got,
576 } => ValueError::ArityError {
577 name,
578 expected,
579 got,
580 },
581 SerializedErrorKind::NotCallable { value } => ValueError::NotCallable { value },
582 SerializedErrorKind::OddMap { count } => ValueError::OddMap { count },
583 SerializedErrorKind::Unsupported => ValueError::Unsupported,
584 SerializedErrorKind::Other(s) => ValueError::Other(s),
585 SerializedErrorKind::OutOfRange => ValueError::OutOfRange,
586 SerializedErrorKind::TransientAlreadyPersisted => ValueError::TransientAlreadyPersisted,
587 SerializedErrorKind::Parse => ValueError::Parse,
588 SerializedErrorKind::Thrown(sv) => ValueError::Thrown(deserialize(*sv)),
589 };
590
591 let data = se.data.map(|pairs| {
592 MapValue::from_pairs(
593 pairs
594 .into_iter()
595 .map(|(k, v)| (deserialize(k), deserialize(v)))
596 .collect(),
597 )
598 });
599
600 let cause = se.cause.map(|c| GcPtr::new(deserialize_error(*c)));
601
602 crate::error::ExceptionInfo::new(error, se.message, data, cause)
603}
604
605#[cfg(test)]
608mod tests {
609 use super::*;
610
611 fn roundtrip(v: &Value) -> Value {
612 deserialize(serialize(v).expect("serialize"))
613 }
614
615 #[test]
616 fn scalars_roundtrip() {
617 assert_eq!(roundtrip(&Value::Nil), Value::Nil);
618 assert_eq!(roundtrip(&Value::Bool(true)), Value::Bool(true));
619 assert_eq!(roundtrip(&Value::Long(42)), Value::Long(42));
620 assert_eq!(roundtrip(&Value::Char('x')), Value::Char('x'));
621 assert_eq!(roundtrip(&Value::Uuid(12345)), Value::Uuid(12345));
622 }
623
624 #[test]
625 fn string_roundtrip() {
626 let v = Value::string("hello, world");
627 assert_eq!(roundtrip(&v), v);
628 }
629
630 #[test]
631 fn keyword_roundtrip() {
632 let v = Value::keyword(Keyword::simple("foo"));
633 assert_eq!(roundtrip(&v), v);
634 let v2 = Value::keyword(Keyword::qualified("clojure.core", "map"));
635 assert_eq!(roundtrip(&v2), v2);
636 }
637
638 #[test]
639 fn symbol_roundtrip() {
640 let v = Value::symbol(Symbol::simple("my-fn"));
641 assert_eq!(roundtrip(&v), v);
642 }
643
644 #[test]
645 fn list_roundtrip() {
646 let v = Value::List(GcPtr::new(PersistentList::from_iter([
647 Value::Long(1),
648 Value::Long(2),
649 Value::Long(3),
650 ])));
651 assert_eq!(roundtrip(&v), v);
652 }
653
654 #[test]
655 fn vector_roundtrip() {
656 let v = Value::Vector(GcPtr::new(PersistentVector::from_iter([
657 Value::string("a"),
658 Value::Bool(false),
659 Value::Nil,
660 ])));
661 assert_eq!(roundtrip(&v), v);
662 }
663
664 #[test]
665 fn nested_map_roundtrip() {
666 let inner = Value::Vector(GcPtr::new(PersistentVector::from_iter([Value::Long(1)])));
667 let v = MapValue::from_pairs(vec![(Value::keyword(Keyword::simple("k")), inner)]);
668 let v = Value::Map(v);
669 assert_eq!(roundtrip(&v), v);
670 }
671
672 #[test]
673 fn resource_not_shareable() {
674 use crate::resource::ResourceHandle;
675 use std::any::Any;
676 use std::sync::Arc;
677 #[derive(Debug)]
678 struct FakeResource;
679 impl crate::resource::Resource for FakeResource {
680 fn resource_type(&self) -> &'static str {
681 "fake"
682 }
683 fn close(&self) -> crate::error::ValueResult<()> {
684 Ok(())
685 }
686 fn is_closed(&self) -> bool {
687 false
688 }
689 fn as_any(&self) -> &dyn Any {
690 self
691 }
692 }
693 let r = Value::Resource(ResourceHandle(Arc::new(FakeResource)));
694 assert!(matches!(
695 serialize(&r),
696 Err(CloneError::NotShareable {
697 type_name: "resource"
698 })
699 ));
700 }
701
702 #[test]
703 fn atom_not_shareable() {
704 use crate::types::Atom;
705 let a = Value::Atom(GcPtr::new(Atom::new(Value::Nil)));
706 assert!(matches!(
707 serialize(&a),
708 Err(CloneError::NotShareable { type_name: "atom" })
709 ));
710 }
711
712 #[test]
713 fn fn_not_shareable() {
714 use crate::types::{Arity, NativeFn};
715 let nf = Value::NativeFunction(GcPtr::new(NativeFn::new("test", Arity::Fixed(0), |_| {
716 Ok(Value::Nil)
717 })));
718 assert!(matches!(
719 serialize(&nf),
720 Err(CloneError::NotShareable { type_name: "fn" })
721 ));
722 }
723
724 #[test]
725 fn lazy_seq_realized_roundtrip() {
726 use crate::types::{LazySeq, Thunk};
727 struct DoneThunk;
728 impl std::fmt::Debug for DoneThunk {
729 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
730 write!(f, "DoneThunk")
731 }
732 }
733 impl cljrs_gc::Trace for DoneThunk {
734 fn trace(&self, _: &mut cljrs_gc::MarkVisitor) {}
735 }
736 impl Thunk for DoneThunk {
737 fn force(&self) -> Result<Value, String> {
738 Ok(Value::Long(99))
739 }
740 }
741 let ls = LazySeq::new(Box::new(DoneThunk));
742 let _ = ls.realize(); let v = Value::LazySeq(GcPtr::new(ls));
744 assert_eq!(roundtrip(&v), Value::Long(99));
745 }
746
747 #[test]
748 fn with_meta_roundtrip() {
749 let v = Value::Long(7).with_meta(Value::Map(MapValue::empty()));
750 let rt = roundtrip(&v);
751 assert_eq!(rt, Value::Long(7));
753 }
754
755 #[test]
756 fn reduced_roundtrip() {
757 let v = Value::Reduced(Box::new(Value::Long(55)));
758 assert_eq!(roundtrip(&v), Value::Reduced(Box::new(Value::Long(55))));
759 }
760}