Skip to main content

steel/
rvals.rs

1pub mod cycles;
2
3use crate::{
4    gc::{
5        shared::{
6            MappedScopedReadContainer, MappedScopedWriteContainer, ScopedReadContainer,
7            ScopedWriteContainer, ShareableMut, StandardShared,
8        },
9        unsafe_erased_pointers::{OpaqueReference, TemporaryMutableView, TemporaryReadonlyView},
10        Gc, GcMut,
11    },
12    parser::{
13        ast::{self, Atom, ExprKind},
14        parser::SyntaxObject,
15        span::Span,
16        tokens::TokenType,
17    },
18    primitives::numbers::realp,
19    rerrs::{ErrorKind, SteelErr},
20    steel_vm::vm::{
21        threads::closure_into_serializable, BuiltInSignature, Continuation, ContinuationMark,
22    },
23    values::{
24        closed::{Heap, HeapRef, MarkAndSweepContext},
25        functions::{BoxedDynFunction, ByteCodeLambda},
26        lazy_stream::LazyStream,
27        lists::Pair,
28        port::{SendablePort, SteelPort},
29        structs::{SerializableUserDefinedStruct, UserDefinedStruct},
30        transducers::{Reducer, Transducer},
31        HashMapConsumingIter, HashSetConsumingIter, SteelPortRepr, VectorConsumingIter,
32    },
33};
34use alloc::vec::IntoIter;
35use std::{
36    any::{Any, TypeId},
37    cell::RefCell,
38    cmp::Ordering,
39    convert::TryInto,
40    fmt,
41    future::Future,
42    hash::{Hash, Hasher},
43    io::Write,
44    ops::Deref,
45    pin::Pin,
46    rc::Rc,
47    result,
48    sync::{Arc, Mutex},
49    task::Context,
50};
51use thin_vec::ThinVec;
52
53// TODO
54#[macro_export]
55macro_rules! list {
56    () => { $crate::rvals::SteelVal::ListV(
57        im_lists::list![]
58    ) };
59
60    ( $($x:expr),* ) => {{
61        $crate::rvals::SteelVal::ListV(vec![$(
62            $crate::rvals::IntoSteelVal::into_steelval($x).unwrap()
63        ), *].into())
64    }};
65
66    ( $($x:expr ,)* ) => {{
67        $crate::rvals::SteelVal::ListV(im_lists::list![$(
68            $crate::rvals::IntoSteelVal::into_steelval($x).unwrap()
69        )*])
70    }};
71}
72
73use bigdecimal::BigDecimal;
74use parking_lot::RwLock;
75use smallvec::SmallVec;
76use SteelVal::*;
77
78use crate::values::{HashMap, HashSet, Vector};
79
80use futures_task::noop_waker_ref;
81use futures_util::future::Shared;
82use futures_util::FutureExt;
83
84use crate::values::lists::List;
85use num_bigint::{BigInt, ToBigInt};
86use num_rational::{BigRational, Rational32};
87use num_traits::{FromPrimitive, Signed, ToPrimitive, Zero};
88use steel_parser::tokens::{IntLiteral, RealLiteral};
89
90use self::cycles::{CycleDetector, IterativeDropHandler};
91
92pub type RcRefSteelVal = Rc<RefCell<SteelVal>>;
93pub fn new_rc_ref_cell(x: SteelVal) -> RcRefSteelVal {
94    Rc::new(RefCell::new(x))
95}
96
97pub type Result<T> = result::Result<T, SteelErr>;
98pub type FunctionSignature = fn(&[SteelVal]) -> Result<SteelVal>;
99pub type MutFunctionSignature = fn(&mut [SteelVal]) -> Result<SteelVal>;
100
101#[cfg(not(feature = "sync"))]
102pub type BoxedAsyncFunctionSignature =
103    crate::gc::Shared<Box<dyn Fn(&[SteelVal]) -> Result<FutureResult>>>;
104
105#[cfg(feature = "sync")]
106pub type BoxedAsyncFunctionSignature =
107    crate::gc::Shared<Box<dyn Fn(&[SteelVal]) -> Result<FutureResult> + Send + Sync + 'static>>;
108
109pub type AsyncSignature = fn(&[SteelVal]) -> FutureResult;
110
111#[cfg(not(feature = "sync"))]
112pub type BoxedFutureResult = Pin<Box<dyn Future<Output = Result<SteelVal>>>>;
113
114#[cfg(feature = "sync")]
115pub type BoxedFutureResult = Pin<Box<dyn Future<Output = Result<SteelVal>> + Send + 'static>>;
116
117// TODO: Why can't I put sync here?
118// #[cfg(feature = "sync")]
119// pub type BoxedFutureResult = Pin<Box<dyn Future<Output = Result<SteelVal>> + Send + 'static>>;
120
121#[derive(Clone)]
122pub struct FutureResult(Shared<BoxedFutureResult>);
123
124impl FutureResult {
125    pub fn new(fut: BoxedFutureResult) -> Self {
126        FutureResult(fut.shared())
127    }
128
129    pub fn into_shared(self) -> Shared<BoxedFutureResult> {
130        self.0
131    }
132}
133
134// This is an attempt to one off poll a future
135// This should enable us to use embedded async functions
136// Will require using call/cc w/ a thread queue in steel, however it should be possible
137pub(crate) fn poll_future(mut fut: Shared<BoxedFutureResult>) -> Option<Result<SteelVal>> {
138    // If the future has already been awaited (by somebody) get that value instead
139    if let Some(output) = fut.peek() {
140        return Some(output.clone());
141    }
142
143    // Otherwise, go ahead and poll the value to see if its ready
144    // The context is going to exist exclusively in Steel, hidden behind an `await`
145    let waker = noop_waker_ref();
146    let context = &mut Context::from_waker(waker);
147
148    // Polling requires a pinned future - TODO make sure this is correct
149    let mut_fut = Pin::new(&mut fut);
150
151    match Future::poll(mut_fut, context) {
152        core::task::Poll::Ready(r) => Some(r),
153        core::task::Poll::Pending => None,
154    }
155}
156
157/// Attempt to cast this custom type down to the underlying type
158pub fn as_underlying_type<T: 'static>(value: &dyn CustomType) -> Option<&T> {
159    value.as_any_ref().downcast_ref::<T>()
160}
161
162pub fn as_underlying_type_mut<T: 'static>(value: &mut dyn CustomType) -> Option<&mut T> {
163    value.as_any_ref_mut().downcast_mut::<T>()
164}
165
166pub trait Custom: private::Sealed {
167    fn fmt(&self) -> Option<core::result::Result<String, core::fmt::Error>> {
168        None
169    }
170
171    #[cfg(feature = "dylibs")]
172    fn fmt_ffi(&self) -> Option<abi_stable::std_types::RString> {
173        None
174    }
175
176    fn into_serializable_steelval(&mut self) -> Option<SerializableSteelVal> {
177        None
178    }
179
180    fn as_iterator(&self) -> Option<Box<dyn Iterator<Item = SteelVal>>> {
181        None
182    }
183
184    fn gc_drop_mut(&mut self, _drop_handler: &mut IterativeDropHandler) {}
185
186    fn gc_visit_children(&self, _context: &mut MarkAndSweepContext) {}
187
188    fn visit_equality(&self, _visitor: &mut cycles::EqualityVisitor) {}
189
190    fn equality_hint(&self, _other: &dyn CustomType) -> bool {
191        true
192    }
193
194    fn equality_hint_general(&self, _other: &SteelVal) -> bool {
195        false
196    }
197
198    #[cfg(feature = "custom-hash")]
199    fn try_as_dyn_hash(&self) -> Option<&dyn DynHash> {
200        None
201    }
202
203    #[doc(hidden)]
204    fn into_error(self) -> core::result::Result<SteelErr, Self>
205    where
206        Self: Sized,
207    {
208        Err(self)
209    }
210}
211
212#[cfg(not(feature = "sync"))]
213pub trait MaybeSendSyncStatic: 'static {}
214
215#[cfg(not(feature = "sync"))]
216impl<T: 'static> MaybeSendSyncStatic for T {}
217
218#[cfg(feature = "sync")]
219pub trait MaybeSendSyncStatic: Send + Sync + 'static {}
220
221#[cfg(feature = "sync")]
222impl<T: Send + Sync + 'static> MaybeSendSyncStatic for T {}
223
224/// Dyn compatible version of [Hash]
225#[cfg(feature = "custom-hash")]
226pub trait DynHash {
227    fn dyn_hash(&self, h: &mut dyn ::core::hash::Hasher);
228}
229
230#[cfg(feature = "custom-hash")]
231impl<T: ::core::hash::Hash> DynHash for T {
232    fn dyn_hash(&self, h: &mut dyn ::core::hash::Hasher) {
233        self.hash(&mut Box::new(h))
234    }
235}
236
237#[cfg(feature = "sync")]
238pub trait CustomType: MaybeSendSyncStatic {
239    fn as_any_ref(&self) -> &dyn Any;
240    fn as_any_ref_mut(&mut self) -> &mut dyn Any;
241    fn name(&self) -> &str {
242        core::any::type_name::<Self>()
243    }
244    fn inner_type_id(&self) -> TypeId;
245    fn display(&self) -> core::result::Result<String, core::fmt::Error> {
246        Ok(format!("#<{}>", self.name()))
247    }
248    fn as_serializable_steelval(&mut self) -> Option<SerializableSteelVal> {
249        None
250    }
251    fn drop_mut(&mut self, _drop_handler: &mut IterativeDropHandler) {}
252    fn visit_children(&self, _context: &mut MarkAndSweepContext) {}
253    // TODO: Add this back at some point
254    // fn visit_children_ref_queue(&self, _context: &mut MarkAndSweepContextRefQueue) {}
255    fn visit_children_for_equality(&self, _visitor: &mut cycles::EqualityVisitor) {}
256    fn check_equality_hint(&self, _other: &dyn CustomType) -> bool {
257        true
258    }
259    fn check_equality_hint_general(&self, _other: &SteelVal) -> bool {
260        false
261    }
262
263    #[cfg(feature = "custom-hash")]
264    fn try_as_dyn_hash(&self) -> Option<&dyn DynHash> {
265        None
266    }
267
268    #[doc(hidden)]
269    fn into_error_(self) -> core::result::Result<SteelErr, Self>
270    where
271        Self: Sized,
272    {
273        Err(self)
274    }
275}
276
277#[cfg(not(feature = "sync"))]
278pub trait CustomType {
279    fn as_any_ref(&self) -> &dyn Any;
280    fn as_any_ref_mut(&mut self) -> &mut dyn Any;
281    fn name(&self) -> &str {
282        core::any::type_name::<Self>()
283    }
284    fn inner_type_id(&self) -> TypeId;
285    fn display(&self) -> core::result::Result<String, core::fmt::Error> {
286        Ok(format!("#<{}>", self.name()))
287    }
288    fn as_serializable_steelval(&mut self) -> Option<SerializableSteelVal> {
289        None
290    }
291    fn drop_mut(&mut self, _drop_handler: &mut IterativeDropHandler) {}
292    fn visit_children(&self, _context: &mut MarkAndSweepContext) {}
293    fn visit_children_for_equality(&self, _visitor: &mut cycles::EqualityVisitor) {}
294    fn check_equality_hint(&self, _other: &dyn CustomType) -> bool {
295        true
296    }
297    fn check_equality_hint_general(&self, _other: &SteelVal) -> bool {
298        false
299    }
300
301    #[cfg(feature = "custom-hash")]
302    fn try_as_dyn_hash(&self) -> Option<&dyn DynHash> {
303        None
304    }
305
306    #[doc(hidden)]
307    fn into_error_(self) -> core::result::Result<SteelErr, Self>
308    where
309        Self: Sized,
310    {
311        Err(self)
312    }
313}
314
315impl<T: Custom + MaybeSendSyncStatic> CustomType for T {
316    fn as_any_ref(&self) -> &dyn Any {
317        self as &dyn Any
318    }
319    fn as_any_ref_mut(&mut self) -> &mut dyn Any {
320        self as &mut dyn Any
321    }
322    fn inner_type_id(&self) -> TypeId {
323        core::any::TypeId::of::<Self>()
324    }
325    fn display(&self) -> core::result::Result<String, core::fmt::Error> {
326        if let Some(formatted) = self.fmt() {
327            formatted
328        } else {
329            Ok(format!("#<{}>", self.name()))
330        }
331    }
332
333    fn as_serializable_steelval(&mut self) -> Option<SerializableSteelVal> {
334        <T as Custom>::into_serializable_steelval(self)
335    }
336
337    fn drop_mut(&mut self, drop_handler: &mut IterativeDropHandler) {
338        self.gc_drop_mut(drop_handler)
339    }
340
341    fn visit_children(&self, context: &mut MarkAndSweepContext) {
342        self.gc_visit_children(context)
343    }
344
345    // TODO: Equality visitor
346    fn visit_children_for_equality(&self, visitor: &mut cycles::EqualityVisitor) {
347        self.visit_equality(visitor)
348    }
349
350    fn check_equality_hint(&self, other: &dyn CustomType) -> bool {
351        self.equality_hint(other)
352    }
353
354    fn check_equality_hint_general(&self, other: &SteelVal) -> bool {
355        self.equality_hint_general(other)
356    }
357
358    fn into_error_(self) -> core::result::Result<SteelErr, Self>
359    where
360        Self: Sized,
361    {
362        self.into_error()
363    }
364
365    #[cfg(feature = "custom-hash")]
366    fn try_as_dyn_hash(&self) -> Option<&dyn DynHash> {
367        Custom::try_as_dyn_hash(self)
368    }
369}
370
371impl<T: CustomType + 'static> IntoSteelVal for T {
372    fn into_steelval(self) -> Result<SteelVal> {
373        Ok(SteelVal::Custom(Gc::new_mut(Box::new(self))))
374    }
375
376    fn as_error(self) -> core::result::Result<SteelErr, Self> {
377        T::into_error_(self)
378    }
379}
380
381pub trait IntoSerializableSteelVal {
382    fn into_serializable_steelval(val: &SteelVal) -> Result<SerializableSteelVal>;
383}
384
385impl<T: CustomType + Clone + Send + Sync + 'static> IntoSerializableSteelVal for T {
386    fn into_serializable_steelval(val: &SteelVal) -> Result<SerializableSteelVal> {
387        if let SteelVal::Custom(v) = val {
388            let left = v.read().as_any_ref().downcast_ref::<T>().cloned();
389            let _lifted = left.ok_or_else(|| {
390                let error_message = format!(
391                    "Type Mismatch: Type of SteelVal: {:?}, did not match the given type: {}",
392                    val,
393                    core::any::type_name::<Self>()
394                );
395                SteelErr::new(ErrorKind::ConversionError, error_message)
396            });
397
398            todo!()
399        } else {
400            let error_message = format!(
401                "Type Mismatch: Type of SteelVal: {:?} did not match the given type, expecting opaque struct: {}",
402                val,
403                core::any::type_name::<Self>()
404            );
405
406            Err(SteelErr::new(ErrorKind::ConversionError, error_message))
407        }
408    }
409}
410
411// TODO: Marshalling out of the type could also try to yoink from a native steel struct.
412// If possible, we can try to line the constructor up with the fields
413impl<T: CustomType + Clone + 'static> FromSteelVal for T {
414    fn from_steelval(val: &SteelVal) -> Result<Self> {
415        if let SteelVal::Custom(v) = val {
416            // let left_type = v.borrow().as_any_ref();
417            // TODO: @Matt - dylibs cause issues here, as the underlying type ids are different
418            // across workspaces and builds
419            let left = v.read().as_any_ref().downcast_ref::<T>().cloned();
420            left.ok_or_else(|| {
421                let error_message = format!(
422                    "Type Mismatch: Type of SteelVal: {:?}, did not match the given type: {}",
423                    val,
424                    core::any::type_name::<Self>()
425                );
426                SteelErr::new(ErrorKind::ConversionError, error_message)
427            })
428        } else {
429            let error_message = format!(
430                "Type Mismatch: Type of SteelVal: {:?} did not match the given type, expecting opaque struct: {}",
431                val,
432                core::any::type_name::<Self>()
433            );
434
435            Err(SteelErr::new(ErrorKind::ConversionError, error_message))
436        }
437    }
438}
439
440/// The entry point for turning values into SteelVals
441/// The is implemented for most primitives and collections
442/// You can also manually implement this for any type, or can optionally
443/// get this implementation for a custom struct by using the custom
444/// steel derive.
445pub trait IntoSteelVal: Sized {
446    fn into_steelval(self) -> Result<SteelVal>;
447
448    #[doc(hidden)]
449    fn as_error(self) -> core::result::Result<SteelErr, Self> {
450        Err(self)
451    }
452}
453
454/// The exit point for turning SteelVals into outside world values
455/// This is implement for most primitives and collections
456/// You can also manually implement this for any type, or can optionally
457/// get this implementation for a custom struct by using the custom
458/// steel derive.
459pub trait FromSteelVal: Sized {
460    fn from_steelval(val: &SteelVal) -> Result<Self>;
461}
462
463pub trait PrimitiveAsRef<'a>: Sized {
464    fn primitive_as_ref(val: &'a SteelVal) -> Result<Self>;
465    fn maybe_primitive_as_ref(val: &'a SteelVal) -> Option<Self>;
466}
467
468pub trait PrimitiveAsRefMut<'a>: Sized {
469    fn primitive_as_ref(val: &'a mut SteelVal) -> Result<Self>;
470    fn maybe_primitive_as_ref(val: &'a mut SteelVal) -> Option<Self>;
471}
472
473pub struct RestArgsIter<'a, T>(
474    pub core::iter::Map<core::slice::Iter<'a, SteelVal>, fn(&'a SteelVal) -> Result<T>>,
475);
476
477impl<'a, T: PrimitiveAsRef<'a> + 'a> RestArgsIter<'a, T> {
478    pub fn new(
479        args: core::iter::Map<core::slice::Iter<'a, SteelVal>, fn(&'a SteelVal) -> Result<T>>,
480    ) -> Self {
481        RestArgsIter(args)
482    }
483
484    pub fn from_slice(args: &'a [SteelVal]) -> Result<Self> {
485        Ok(RestArgsIter(args.iter().map(T::primitive_as_ref)))
486    }
487}
488
489impl<'a, T> Iterator for RestArgsIter<'a, T> {
490    type Item = Result<T>;
491
492    fn next(&mut self) -> Option<Self::Item> {
493        self.0.next()
494    }
495
496    fn size_hint(&self) -> (usize, Option<usize>) {
497        self.0.size_hint()
498    }
499}
500
501impl<'a, T> ExactSizeIterator for RestArgsIter<'a, T> {}
502
503pub struct RestArgs<T: FromSteelVal>(pub Vec<T>);
504
505impl<T: FromSteelVal> RestArgs<T> {
506    pub fn new(args: Vec<T>) -> Self {
507        RestArgs(args)
508    }
509
510    pub fn from_slice(args: &[SteelVal]) -> Result<Self> {
511        args.iter()
512            .map(|x| T::from_steelval(x))
513            .collect::<Result<Vec<_>>>()
514            .map(RestArgs)
515    }
516}
517
518impl<T: FromSteelVal> core::ops::Deref for RestArgs<T> {
519    type Target = [T];
520
521    fn deref(&self) -> &Self::Target {
522        &self.0
523    }
524}
525
526mod private {
527
528    use core::any::Any;
529
530    pub trait Sealed {}
531
532    impl<T: Any> Sealed for T {}
533}
534
535pub enum SRef<'b, T: ?Sized + 'b> {
536    Temporary(&'b T),
537    Owned(MappedScopedReadContainer<'b, T>),
538}
539
540impl<'b, T: ?Sized + 'b> Deref for SRef<'b, T> {
541    type Target = T;
542
543    #[inline]
544    fn deref(&self) -> &T {
545        match self {
546            SRef::Temporary(inner) => inner,
547            SRef::Owned(inner) => inner,
548        }
549    }
550}
551
552// Can you take a steel val and execute operations on it by reference
553pub trait AsRefSteelVal: Sized {
554    type Nursery: Default;
555
556    fn as_ref<'b, 'a: 'b>(val: &'a SteelVal) -> Result<SRef<'b, Self>>;
557}
558
559pub trait AsSlice<T> {
560    fn as_slice_repr(&self) -> &[T];
561}
562
563impl<T> AsSlice<T> for Vec<T> {
564    fn as_slice_repr(&self) -> &[T] {
565        self.as_slice()
566    }
567}
568
569// TODO: Try to incorporate these all into one trait if possible
570pub trait AsRefSteelValFromUnsized<T>: Sized {
571    type Output: AsSlice<T>;
572
573    fn as_ref_from_unsized(val: &SteelVal) -> Result<Self::Output>;
574}
575
576pub trait AsRefMutSteelVal: Sized {
577    fn as_mut_ref<'b, 'a: 'b>(val: &'a SteelVal) -> Result<MappedScopedWriteContainer<'b, Self>>;
578}
579
580pub(crate) trait AsRefMutSteelValFromRef: Sized {
581    fn as_mut_ref_from_ref(val: &SteelVal) -> crate::rvals::Result<TemporaryMutableView<Self>>;
582}
583
584pub(crate) trait AsRefSteelValFromRef: Sized {
585    fn as_ref_from_ref(val: &SteelVal) -> crate::rvals::Result<TemporaryReadonlyView<Self>>;
586}
587
588impl AsRefSteelVal for UserDefinedStruct {
589    type Nursery = ();
590
591    fn as_ref<'b, 'a: 'b>(val: &'a SteelVal) -> Result<SRef<'b, Self>> {
592        if let SteelVal::CustomStruct(l) = val {
593            Ok(SRef::Temporary(l))
594        } else {
595            stop!(TypeMismatch => "Value cannot be referenced as a list")
596        }
597    }
598}
599
600impl<T: CustomType + MaybeSendSyncStatic> AsRefSteelVal for T {
601    type Nursery = ();
602
603    fn as_ref<'b, 'a: 'b>(val: &'a SteelVal) -> Result<SRef<'b, Self>> {
604        if let SteelVal::Custom(v) = val {
605            let res = ScopedReadContainer::map(v.read(), |x| x.as_any_ref());
606
607            if res.is::<T>() {
608                Ok(SRef::Owned(MappedScopedReadContainer::map(res, |x| {
609                    x.downcast_ref::<T>().unwrap()
610                })))
611            } else {
612                let error_message = format!(
613                    "Type Mismatch: Type of SteelVal: {} did not match the given type: {}",
614                    val,
615                    core::any::type_name::<Self>()
616                );
617                Err(SteelErr::new(ErrorKind::ConversionError, error_message))
618            }
619            // res
620        } else {
621            let error_message = format!(
622                "Type Mismatch: Type of SteelVal: {} did not match the given type: {}",
623                val,
624                core::any::type_name::<Self>()
625            );
626
627            Err(SteelErr::new(ErrorKind::ConversionError, error_message))
628        }
629    }
630}
631
632impl<T: CustomType + MaybeSendSyncStatic> AsRefMutSteelVal for T {
633    fn as_mut_ref<'b, 'a: 'b>(val: &'a SteelVal) -> Result<MappedScopedWriteContainer<'b, Self>> {
634        if let SteelVal::Custom(v) = val {
635            let res = ScopedWriteContainer::map(v.write(), |x| x.as_any_ref_mut());
636
637            if res.is::<T>() {
638                Ok(MappedScopedWriteContainer::map(res, |x| {
639                    x.downcast_mut::<T>().unwrap()
640                }))
641            } else {
642                let error_message = format!(
643                    "Type Mismatch: Type of SteelVal: {} did not match the given type: {}",
644                    val,
645                    core::any::type_name::<Self>()
646                );
647                Err(SteelErr::new(ErrorKind::ConversionError, error_message))
648            }
649            // res
650        } else {
651            let error_message = format!(
652                "Type Mismatch: Type of SteelVal: {} did not match the given type: {}",
653                val,
654                core::any::type_name::<Self>()
655            );
656
657            Err(SteelErr::new(ErrorKind::ConversionError, error_message))
658        }
659    }
660}
661
662impl ast::TryFromSteelValVisitorForExprKind {
663    pub fn visit_syntax_object(&mut self, value: &Syntax) -> Result<ExprKind> {
664        let span = value.span;
665
666        // dbg!(&span);
667        // let source = self.source.clone();
668        match &value.syntax {
669            // Mutual recursion case
670            SyntaxObject(s) => self.visit_syntax_object(s),
671            BoolV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::new(
672                TokenType::BooleanLiteral(*x),
673                span,
674            )))),
675            NumV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::new(
676                RealLiteral::Float((*x).into()).into(),
677                span,
678            )))),
679            IntV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::new(
680                RealLiteral::Int(IntLiteral::Small(*x)).into(),
681                span,
682            )))),
683            VectorV(lst) => {
684                let items: Result<ThinVec<ExprKind>> = lst.iter().map(|x| self.visit(x)).collect();
685                Ok(ExprKind::List(crate::parser::ast::List::new(items?)))
686            }
687            StringV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::new(
688                TokenType::StringLiteral(x.as_str().into()),
689                span,
690            )))),
691
692            SymbolV(x) if x.starts_with("#:") => Ok(ExprKind::Atom(Atom::new(SyntaxObject::new(
693                TokenType::Keyword(x.as_str().into()),
694                span,
695            )))),
696
697            SymbolV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::new(
698                TokenType::Identifier(x.as_str().into()),
699                span,
700            )))),
701
702            ListV(l) => {
703                // Rooted - things operate as normal
704                if self.qq_depth == 0 {
705                    let maybe_special_form = l.first().and_then(|x| {
706                        x.as_symbol()
707                            .or_else(|| x.as_syntax_object().and_then(|x| x.syntax.as_symbol()))
708                    });
709
710                    match maybe_special_form {
711                        Some(x) if x.as_str() == "quote" => {
712                            if self.quoted {
713                                let items: core::result::Result<ThinVec<ExprKind>, _> =
714                                    l.iter().map(|x| self.visit(x)).collect();
715
716                                return Ok(ExprKind::List(ast::List::new(items?)));
717                            }
718
719                            self.quoted = true;
720
721                            let return_value = l
722                                .into_iter()
723                                .map(|x| self.visit(x))
724                                .collect::<core::result::Result<ThinVec<_>, _>>()?
725                                .try_into()?;
726
727                            self.quoted = false;
728
729                            return Ok(return_value);
730                        } // "quasiquote" => {
731                        //     self.qq_depth += 1;
732                        // }
733                        // None => {
734                        // return Ok(ExprKind::empty());
735                        // }
736                        _ => {}
737                    }
738                }
739
740                Ok(l.into_iter()
741                    .map(|x| self.visit(x))
742                    .collect::<core::result::Result<ThinVec<_>, _>>()?
743                    .try_into()?)
744            }
745
746            CharV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::new(
747                TokenType::CharacterLiteral(*x),
748                span,
749            )))),
750            _ => stop!(ConversionError => "unable to convert {:?} to expression", &value.syntax),
751        }
752    }
753}
754
755#[derive(Debug, Clone)]
756pub struct Syntax {
757    pub(crate) raw: Option<SteelVal>,
758    pub(crate) syntax: SteelVal,
759    span: Span,
760}
761
762impl Syntax {
763    pub fn new(syntax: SteelVal, span: Span) -> Syntax {
764        Self {
765            raw: None,
766            syntax,
767            span,
768        }
769    }
770
771    pub fn proto(raw: SteelVal, syntax: SteelVal, span: Span) -> Syntax {
772        Self {
773            raw: Some(raw),
774            syntax,
775            span,
776        }
777    }
778
779    pub fn syntax_e(&self) -> SteelVal {
780        self.syntax.clone()
781    }
782
783    pub fn new_with_source(syntax: SteelVal, span: Span) -> Syntax {
784        Self {
785            raw: None,
786            syntax,
787            span,
788        }
789    }
790
791    pub fn syntax_loc(&self) -> Span {
792        self.span
793    }
794
795    pub fn syntax_datum(&self) -> SteelVal {
796        self.raw.clone().unwrap()
797    }
798
799    pub(crate) fn steelval_to_exprkind(value: &SteelVal) -> Result<ExprKind> {
800        match value {
801            // Mutual recursion case
802            SyntaxObject(s) => s.to_exprkind(),
803            BoolV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::default(
804                TokenType::BooleanLiteral(*x),
805            )))),
806            NumV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::default(
807                RealLiteral::Float((*x).into()).into(),
808            )))),
809            IntV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::default(
810                RealLiteral::Int(IntLiteral::Small(*x)).into(),
811            )))),
812            VectorV(lst) => {
813                let items: Result<ThinVec<ExprKind>> =
814                    lst.iter().map(Self::steelval_to_exprkind).collect();
815                Ok(ExprKind::List(crate::parser::ast::List::new(items?)))
816            }
817            StringV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::default(
818                TokenType::StringLiteral(x.as_str().into()),
819            )))),
820            // LambdaV(_) => Err("Can't convert from Lambda to expression!"),
821            // MacroV(_) => Err("Can't convert from Macro to expression!"),
822            SymbolV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::default(
823                TokenType::Identifier(x.as_str().into()),
824            )))),
825            ListV(l) => {
826                let items: Result<ThinVec<ExprKind>> =
827                    l.iter().map(Self::steelval_to_exprkind).collect();
828
829                Ok(ExprKind::List(crate::parser::ast::List::new(items?)))
830            }
831            CharV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::default(
832                TokenType::CharacterLiteral(*x),
833            )))),
834            _ => stop!(ConversionError => "unable to convert {:?} to expression", value),
835        }
836    }
837
838    // TODO: match on self.syntax. If its itself a syntax object, then just recur on that until we bottom out
839    // Otherwise, reconstruct the ExprKind and replace the span and source information into the representation
840    pub fn to_exprkind(&self) -> Result<ExprKind> {
841        let span = self.span;
842        // let source = self.source.clone();
843        match &self.syntax {
844            // Mutual recursion case
845            SyntaxObject(s) => s.to_exprkind(),
846            BoolV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::new(
847                TokenType::BooleanLiteral(*x),
848                span,
849            )))),
850            NumV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::new(
851                RealLiteral::Float((*x).into()).into(),
852                span,
853            )))),
854            IntV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::new(
855                RealLiteral::Int(IntLiteral::Small(*x)).into(),
856                span,
857            )))),
858            VectorV(lst) => {
859                let items: Result<ThinVec<ExprKind>> =
860                    lst.iter().map(Self::steelval_to_exprkind).collect();
861                Ok(ExprKind::List(crate::parser::ast::List::new(items?)))
862            }
863            StringV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::new(
864                TokenType::StringLiteral(x.as_str().into()),
865                span,
866            )))),
867            // LambdaV(_) => Err("Can't convert from Lambda to expression!"),
868            // MacroV(_) => Err("Can't convert from Macro to expression!"),
869            SymbolV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::new(
870                TokenType::Identifier(x.as_str().into()),
871                span,
872            )))),
873            ListV(l) => {
874                let items: Result<ThinVec<ExprKind>> =
875                    l.iter().map(Self::steelval_to_exprkind).collect();
876
877                Ok(ExprKind::List(crate::parser::ast::List::new(items?)))
878            }
879            CharV(x) => Ok(ExprKind::Atom(Atom::new(SyntaxObject::new(
880                TokenType::CharacterLiteral(*x),
881                span,
882            )))),
883            _ => stop!(ConversionError => "unable to convert {:?} to expression", &self.syntax),
884        }
885    }
886}
887
888impl IntoSteelVal for Syntax {
889    fn into_steelval(self) -> Result<SteelVal> {
890        Ok(SteelVal::SyntaxObject(Gc::new(self)))
891    }
892}
893
894impl AsRefSteelVal for Syntax {
895    type Nursery = ();
896
897    fn as_ref<'b, 'a: 'b>(val: &'a SteelVal) -> Result<SRef<'b, Self>> {
898        if let SteelVal::SyntaxObject(s) = val {
899            Ok(SRef::Temporary(s))
900        } else {
901            stop!(TypeMismatch => "Value cannot be referenced as a syntax object: {}", val)
902        }
903    }
904}
905
906impl From<Syntax> for SteelVal {
907    fn from(val: Syntax) -> Self {
908        SteelVal::SyntaxObject(Gc::new(val))
909    }
910}
911
912// TODO:
913// This needs to be a method on the runtime: in order to properly support
914// threads
915// Tracking issue here: https://github.com/mattwparas/steel/issues/98
916
917// Values which can be sent to another thread.
918// If it cannot be sent to another thread, then we'll error out on conversion.
919// TODO: Add boxed dyn functions to this.
920// #[derive(PartialEq)]
921pub enum SerializableSteelVal {
922    Closure(crate::values::functions::SerializedLambda),
923    BoolV(bool),
924    NumV(f64),
925    IntV(isize),
926    CharV(char),
927    Void,
928    StringV(String),
929    FuncV(FunctionSignature),
930    MutFunc(MutFunctionSignature),
931    HashMapV(Vec<(SerializableSteelVal, SerializableSteelVal)>),
932    ListV(Vec<SerializableSteelVal>),
933    Pair(Box<(SerializableSteelVal, SerializableSteelVal)>),
934    VectorV(Vec<SerializableSteelVal>),
935    ByteVectorV(Vec<u8>),
936    BoxedDynFunction(BoxedDynFunction),
937    BuiltIn(BuiltInSignature),
938    SymbolV(String),
939    Custom(Box<dyn CustomType + Send>),
940    CustomStruct(SerializableUserDefinedStruct),
941    // Attempt to reuse the storage if possible
942    HeapAllocated(usize),
943    Port(SendablePort),
944    Rational(Rational32),
945}
946
947pub enum SerializedHeapRef {
948    Serialized(Option<SerializableSteelVal>),
949    Closed(HeapRef<SteelVal>),
950}
951
952pub struct HeapSerializer<'a> {
953    pub heap: &'a mut Heap,
954    pub fake_heap: &'a mut std::collections::HashMap<usize, SerializedHeapRef>,
955    // After the conversion, we go back through, and patch the values from the fake heap
956    // in to each of the values listed here - otherwise, we'll miss cycles
957    pub values_to_fill_in: &'a mut std::collections::HashMap<usize, HeapRef<SteelVal>>,
958
959    // Cache the functions that get built
960    pub built_functions: &'a mut std::collections::HashMap<u32, Gc<ByteCodeLambda>>,
961}
962
963// Once crossed over the line, convert BACK into a SteelVal
964// This should be infallible.
965pub fn from_serializable_value(ctx: &mut HeapSerializer, val: SerializableSteelVal) -> SteelVal {
966    match val {
967        SerializableSteelVal::Closure(c) => {
968            if c.captures.is_empty() {
969                if let Some(already_made) = ctx.built_functions.get(&c.id) {
970                    SteelVal::Closure(already_made.clone())
971                } else {
972                    let id = c.id;
973                    let value = Gc::new(ByteCodeLambda::from_serialized(ctx, c));
974
975                    // Save those as well
976                    // Probably need to just do this for all
977                    ctx.built_functions.insert(id, value.clone());
978                    SteelVal::Closure(value)
979                }
980            } else {
981                SteelVal::Closure(Gc::new(ByteCodeLambda::from_serialized(ctx, c)))
982            }
983        }
984        SerializableSteelVal::BoolV(b) => SteelVal::BoolV(b),
985        SerializableSteelVal::NumV(n) => SteelVal::NumV(n),
986        SerializableSteelVal::IntV(i) => SteelVal::IntV(i),
987        SerializableSteelVal::CharV(c) => SteelVal::CharV(c),
988        SerializableSteelVal::Void => SteelVal::Void,
989        SerializableSteelVal::Rational(r) => SteelVal::Rational(r),
990        SerializableSteelVal::StringV(s) => SteelVal::StringV(s.into()),
991        SerializableSteelVal::FuncV(f) => SteelVal::FuncV(f),
992        SerializableSteelVal::MutFunc(f) => SteelVal::MutFunc(f),
993        SerializableSteelVal::HashMapV(h) => SteelVal::HashMapV(
994            Gc::new(
995                h.into_iter()
996                    .map(|(k, v)| {
997                        (
998                            from_serializable_value(ctx, k),
999                            from_serializable_value(ctx, v),
1000                        )
1001                    })
1002                    .collect::<HashMap<_, _>>(),
1003            )
1004            .into(),
1005        ),
1006        SerializableSteelVal::ListV(v) => SteelVal::ListV(
1007            v.into_iter()
1008                .map(|x| from_serializable_value(ctx, x))
1009                .collect(),
1010        ),
1011        SerializableSteelVal::VectorV(v) => SteelVal::VectorV(SteelVector(Gc::new(
1012            v.into_iter()
1013                .map(|x| from_serializable_value(ctx, x))
1014                .collect(),
1015        ))),
1016        SerializableSteelVal::BoxedDynFunction(f) => SteelVal::BoxedFunction(Gc::new(f)),
1017        SerializableSteelVal::BuiltIn(f) => SteelVal::BuiltIn(f),
1018        SerializableSteelVal::SymbolV(s) => SteelVal::SymbolV(s.into()),
1019        SerializableSteelVal::Custom(b) => SteelVal::Custom(Gc::new_mut(b)),
1020        SerializableSteelVal::CustomStruct(s) => {
1021            SteelVal::CustomStruct(Gc::new(UserDefinedStruct {
1022                fields: {
1023                    let fields = s
1024                        .fields
1025                        .into_iter()
1026                        .map(|x| from_serializable_value(ctx, x));
1027
1028                    // fields.collect()
1029
1030                    // let mut recycle: crate::values::recycler::Recycle<Vec<_>> =
1031                    //     crate::values::recycler::Recycle::new();
1032
1033                    let mut recycle: crate::values::recycler::Recycle<SmallVec<_>> =
1034                        crate::values::recycler::Recycle::new();
1035
1036                    recycle.extend(fields);
1037
1038                    recycle
1039                },
1040                type_descriptor: s.type_descriptor,
1041            }))
1042        }
1043        SerializableSteelVal::Port(p) => SteelVal::PortV(SteelPort::from_sendable_port(p)),
1044        SerializableSteelVal::HeapAllocated(v) => {
1045            // todo!()
1046
1047            if let Some(mut guard) = ctx.fake_heap.get_mut(&v) {
1048                match &mut guard {
1049                    SerializedHeapRef::Serialized(value) => {
1050                        let value = core::mem::take(value);
1051
1052                        if let Some(value) = value {
1053                            let _ = from_serializable_value(ctx, value);
1054
1055                            todo!()
1056                            // let allocation = ctx.heap.allocate_without_collection(value);
1057
1058                            // ctx.fake_heap
1059                            //     .insert(v, SerializedHeapRef::Closed(allocation.clone()));
1060
1061                            // SteelVal::HeapAllocated(allocation)
1062                        } else {
1063                            // println!("If we're getting here - it means the value from the heap has already
1064                            // been converting. if so, we should do something...");
1065
1066                            todo!()
1067
1068                            // let fake_allocation =
1069                            //     ctx.heap.allocate_without_collection(SteelVal::Void);
1070
1071                            // ctx.values_to_fill_in.insert(v, fake_allocation.clone());
1072
1073                            // SteelVal::HeapAllocated(fake_allocation)
1074                        }
1075                    }
1076
1077                    SerializedHeapRef::Closed(c) => SteelVal::HeapAllocated(c.clone()),
1078                }
1079            } else {
1080                // Shouldn't silently fail here, but we will... for now
1081
1082                // let allocation = ctx.heap.allocate_without_collection(SteelVal::Void);
1083
1084                // ctx.fake_heap
1085                //     .insert(v, SerializedHeapRef::Closed(allocation.clone()));
1086
1087                // SteelVal::HeapAllocated(allocation)
1088
1089                todo!()
1090            }
1091        }
1092        SerializableSteelVal::Pair(pair) => {
1093            let (car, cdr) = *pair;
1094
1095            crate::values::lists::Pair::cons(
1096                from_serializable_value(ctx, car),
1097                from_serializable_value(ctx, cdr),
1098            )
1099            .into()
1100        }
1101        SerializableSteelVal::ByteVectorV(bytes) => {
1102            SteelVal::ByteVector(SteelByteVector::new(bytes))
1103        }
1104    }
1105}
1106
1107// The serializable value needs to refer to the original heap -
1108// that way can reference the original stuff easily.
1109
1110// TODO: Use the cycle detector instead
1111pub fn into_serializable_value(
1112    val: SteelVal,
1113    serialized_heap: &mut std::collections::HashMap<usize, SerializableSteelVal>,
1114    visited: &mut std::collections::HashSet<usize>,
1115) -> Result<SerializableSteelVal> {
1116    // dbg!(&serialized_heap);
1117
1118    match val {
1119        SteelVal::Closure(c) => closure_into_serializable(&c, serialized_heap, visited)
1120            .map(SerializableSteelVal::Closure),
1121        SteelVal::BoolV(b) => Ok(SerializableSteelVal::BoolV(b)),
1122        SteelVal::NumV(n) => Ok(SerializableSteelVal::NumV(n)),
1123        SteelVal::IntV(n) => Ok(SerializableSteelVal::IntV(n)),
1124        SteelVal::CharV(c) => Ok(SerializableSteelVal::CharV(c)),
1125        SteelVal::Void => Ok(SerializableSteelVal::Void),
1126        SteelVal::StringV(s) => Ok(SerializableSteelVal::StringV(s.to_string())),
1127        SteelVal::FuncV(f) => Ok(SerializableSteelVal::FuncV(f)),
1128        SteelVal::ListV(l) => Ok(SerializableSteelVal::ListV(
1129            l.into_iter()
1130                .map(|x| into_serializable_value(x, serialized_heap, visited))
1131                .collect::<Result<_>>()?,
1132        )),
1133        SteelVal::Pair(pair) => Ok(SerializableSteelVal::Pair(Box::new((
1134            into_serializable_value(pair.car.clone(), serialized_heap, visited)?,
1135            into_serializable_value(pair.cdr.clone(), serialized_heap, visited)?,
1136        )))),
1137        SteelVal::BoxedFunction(f) => Ok(SerializableSteelVal::BoxedDynFunction((*f).clone())),
1138        SteelVal::BuiltIn(f) => Ok(SerializableSteelVal::BuiltIn(f)),
1139        SteelVal::SymbolV(s) => Ok(SerializableSteelVal::SymbolV(s.to_string())),
1140        SteelVal::MutFunc(f) => Ok(SerializableSteelVal::MutFunc(f)),
1141        SteelVal::HashMapV(v) => Ok(SerializableSteelVal::HashMapV(
1142            v.0.unwrap()
1143                .into_iter()
1144                .map(|(k, v)| {
1145                    let kprime = into_serializable_value(k, serialized_heap, visited)?;
1146                    let vprime = into_serializable_value(v, serialized_heap, visited)?;
1147
1148                    Ok((kprime, vprime))
1149                })
1150                .collect::<Result<_>>()?,
1151        )),
1152
1153        SteelVal::Custom(c) => {
1154            if let Some(output) = c.write().as_serializable_steelval() {
1155                Ok(output)
1156            } else {
1157                stop!(Generic => "Custom type not allowed to be moved across threads!")
1158            }
1159        }
1160
1161        SteelVal::CustomStruct(s) => Ok(SerializableSteelVal::CustomStruct(
1162            SerializableUserDefinedStruct {
1163                fields: s
1164                    .fields
1165                    .iter()
1166                    .cloned()
1167                    .map(|x| into_serializable_value(x, serialized_heap, visited))
1168                    .collect::<Result<Vec<_>>>()?,
1169                type_descriptor: s.type_descriptor,
1170            },
1171        )),
1172
1173        SteelVal::PortV(p) => SendablePort::from_port(p).map(SerializableSteelVal::Port),
1174
1175        // If there is a cycle, this could cause problems?
1176        SteelVal::HeapAllocated(h) => {
1177            // We should pick it up on the way back the recursion
1178            if visited.contains(&h.as_ptr_usize())
1179                && !serialized_heap.contains_key(&h.as_ptr_usize())
1180            {
1181                // println!("Already visited: {}", h.as_ptr_usize());
1182
1183                Ok(SerializableSteelVal::HeapAllocated(h.as_ptr_usize()))
1184            } else {
1185                visited.insert(h.as_ptr_usize());
1186
1187                if serialized_heap.contains_key(&h.as_ptr_usize()) {
1188                    // println!("Already exists in map: {}", h.as_ptr_usize());
1189
1190                    Ok(SerializableSteelVal::HeapAllocated(h.as_ptr_usize()))
1191                } else {
1192                    // println!("Trying to insert: {} @ {}", h.get(), h.as_ptr_usize());
1193
1194                    let value = into_serializable_value(h.get(), serialized_heap, visited);
1195
1196                    let value = match value {
1197                        Ok(v) => v,
1198                        Err(e) => {
1199                            // println!("{}", e);
1200                            return Err(e);
1201                        }
1202                    };
1203
1204                    serialized_heap.insert(h.as_ptr_usize(), value);
1205
1206                    // println!("Inserting: {}", h.as_ptr_usize());
1207
1208                    Ok(SerializableSteelVal::HeapAllocated(h.as_ptr_usize()))
1209                }
1210            }
1211        }
1212
1213        SteelVal::VectorV(vector) => Ok(SerializableSteelVal::VectorV(
1214            vector
1215                .iter()
1216                .cloned()
1217                .map(|val| into_serializable_value(val, serialized_heap, visited))
1218                .collect::<Result<_>>()?,
1219        )),
1220
1221        SteelVal::ByteVector(bytes) => {
1222            Ok(SerializableSteelVal::ByteVectorV(bytes.vec.read().clone()))
1223        }
1224
1225        SteelVal::Rational(r) => Ok(SerializableSteelVal::Rational(r)),
1226
1227        illegal => stop!(Generic => "Type not allowed to be moved across threads!: {}", illegal),
1228    }
1229}
1230
1231#[derive(Clone, Debug, PartialEq, Eq)]
1232pub struct SteelMutableVector(pub(crate) Gc<RefCell<Vec<SteelVal>>>);
1233
1234#[derive(Clone, Debug, PartialEq, Eq)]
1235pub struct SteelVector(pub(crate) Gc<Vector<SteelVal>>);
1236
1237impl FromIterator<SteelVal> for SteelVector {
1238    fn from_iter<T: IntoIterator<Item = SteelVal>>(iter: T) -> Self {
1239        let vec = Vector::from_iter(iter);
1240        SteelVector(Gc::new(vec))
1241    }
1242}
1243
1244impl Deref for SteelVector {
1245    type Target = Vector<SteelVal>;
1246
1247    fn deref(&self) -> &Self::Target {
1248        &self.0
1249    }
1250}
1251
1252impl From<Gc<Vector<SteelVal>>> for SteelVector {
1253    fn from(value: Gc<Vector<SteelVal>>) -> Self {
1254        SteelVector(value)
1255    }
1256}
1257
1258#[derive(Clone, Debug, PartialEq)]
1259pub struct SteelHashMap(pub(crate) Gc<HashMap<SteelVal, SteelVal>>);
1260
1261#[cfg(feature = "imbl")]
1262impl Hash for SteelHashMap {
1263    fn hash<H>(&self, state: &mut H)
1264    where
1265        H: Hasher,
1266    {
1267        for i in self.iter() {
1268            i.hash(state);
1269        }
1270    }
1271}
1272
1273impl Deref for SteelHashMap {
1274    type Target = HashMap<SteelVal, SteelVal>;
1275
1276    fn deref(&self) -> &Self::Target {
1277        &self.0
1278    }
1279}
1280
1281impl From<Gc<HashMap<SteelVal, SteelVal>>> for SteelHashMap {
1282    fn from(value: Gc<HashMap<SteelVal, SteelVal>>) -> Self {
1283        SteelHashMap(value)
1284    }
1285}
1286
1287#[derive(Clone, Debug, PartialEq)]
1288pub struct SteelHashSet(pub(crate) Gc<HashSet<SteelVal>>);
1289
1290#[cfg(feature = "imbl")]
1291impl Hash for SteelHashSet {
1292    fn hash<H>(&self, state: &mut H)
1293    where
1294        H: Hasher,
1295    {
1296        for i in self.iter() {
1297            i.hash(state);
1298        }
1299    }
1300}
1301
1302impl Deref for SteelHashSet {
1303    type Target = HashSet<SteelVal>;
1304
1305    fn deref(&self) -> &Self::Target {
1306        &self.0
1307    }
1308}
1309
1310impl From<Gc<HashSet<SteelVal>>> for SteelHashSet {
1311    fn from(value: Gc<HashSet<SteelVal>>) -> Self {
1312        SteelHashSet(value)
1313    }
1314}
1315
1316pub enum TypeKind {
1317    Any,
1318    Bool,
1319    Num,
1320    Int,
1321    Char,
1322    Vector(Box<TypeKind>),
1323    Void,
1324    String,
1325    Function,
1326    HashMap(Box<TypeKind>, Box<TypeKind>),
1327    HashSet(Box<TypeKind>),
1328    List(Box<TypeKind>),
1329}
1330
1331/// A value as represented in the runtime.
1332#[repr(C, u8)]
1333pub enum SteelVal {
1334    /// Represents a bytecode closure.
1335    Closure(Gc<ByteCodeLambda>),
1336    /// Represents a boolean value.
1337    BoolV(bool),
1338    /// Represents a number, currently only f64 numbers are supported.
1339    NumV(f64),
1340    /// Represents an integer.
1341    IntV(isize),
1342    /// Represents a rational number.
1343    Rational(Rational32),
1344    /// Represents a character type
1345    CharV(char),
1346    /// Vectors are represented as `im_rc::Vector`'s, which are immutable
1347    /// data structures
1348    VectorV(SteelVector),
1349    /// Void return value
1350    Void,
1351    /// Represents strings
1352    StringV(SteelString),
1353    /// Represents built in rust functions
1354    FuncV(FunctionSignature),
1355    /// Represents a symbol, internally represented as `String`s
1356    SymbolV(SteelString),
1357    /// Container for a type that implements the `Custom Type` trait. (trait object)
1358    Custom(GcMut<Box<dyn CustomType>>), // TODO: @Matt - consider using just a mutex here, to relax some of the bounds?
1359    // Embedded HashMap
1360    HashMapV(SteelHashMap),
1361    // Embedded HashSet
1362    HashSetV(SteelHashSet),
1363    /// Represents a scheme-only struct
1364    CustomStruct(Gc<UserDefinedStruct>),
1365    /// Represents a port object
1366    PortV(SteelPort),
1367    /// Generic iterator wrapper
1368    IterV(Gc<Transducer>),
1369    /// Reducers
1370    ReducerV(Gc<Reducer>),
1371    /// Async Function wrapper
1372    FutureFunc(BoxedAsyncFunctionSignature),
1373    // Boxed Future Result
1374    FutureV(Gc<FutureResult>),
1375    // A stream of `SteelVal`.
1376    StreamV(Gc<LazyStream>),
1377    /// Custom closure
1378    BoxedFunction(Gc<BoxedDynFunction>),
1379    // Continuation
1380    ContinuationFunction(Continuation),
1381    // Function Pointer
1382    // #[cfg(feature = "jit")]
1383    // CompiledFunction(Box<JitFunctionPointer>),
1384    // List
1385    ListV(crate::values::lists::List<SteelVal>),
1386    // Holds a pair that contains 2 `SteelVal`.
1387    Pair(Gc<crate::values::lists::Pair>),
1388    // Mutable functions
1389    MutFunc(MutFunctionSignature),
1390    // Built in functions
1391    BuiltIn(BuiltInSignature),
1392    // Mutable vector
1393    MutableVector(HeapRef<Vec<SteelVal>>),
1394    // This should delegate to the underlying iterator - can allow for faster raw iteration if possible
1395    // Should allow for polling just a raw "next" on underlying elements
1396    BoxedIterator(GcMut<OpaqueIterator>),
1397    // Contains a syntax object.
1398    SyntaxObject(Gc<Syntax>),
1399    // Mutable storage, with Gc backing
1400    // Boxed(HeapRef),
1401    Boxed(GcMut<SteelVal>),
1402    // Holds a SteelVal on the heap.
1403    HeapAllocated(HeapRef<SteelVal>),
1404    // TODO: This itself, needs to be boxed unfortunately.
1405    Reference(Gc<OpaqueReference<'static>>),
1406    // Like IntV but supports larger values.
1407    BigNum(Gc<BigInt>),
1408    // Like Rational but supports larger numerators and denominators.
1409    BigRational(Gc<BigRational>),
1410    // A complex number.
1411    Complex(Gc<SteelComplex>),
1412    // Byte vectors
1413    ByteVector(SteelByteVector),
1414}
1415
1416impl Clone for SteelVal {
1417    #[inline(always)]
1418    fn clone(&self) -> Self {
1419        match self {
1420            Closure(gc) => Self::Closure(Gc::clone(gc)),
1421            BoolV(b) => Self::BoolV(*b),
1422            NumV(n) => Self::NumV(*n),
1423            IntV(i) => Self::IntV(*i),
1424            Rational(ratio) => Self::Rational(*ratio),
1425            CharV(c) => Self::CharV(*c),
1426            VectorV(steel_vector) => Self::VectorV(steel_vector.clone()),
1427            Void => Self::Void,
1428            StringV(steel_string) => Self::StringV(steel_string.clone()),
1429            FuncV(f) => Self::FuncV(*f),
1430            SymbolV(steel_string) => Self::SymbolV(steel_string.clone()),
1431            SteelVal::Custom(gc) => SteelVal::Custom(gc.clone()),
1432            HashMapV(steel_hash_map) => SteelVal::HashMapV(steel_hash_map.clone()),
1433            HashSetV(steel_hash_set) => SteelVal::HashSetV(steel_hash_set.clone()),
1434            CustomStruct(gc) => SteelVal::CustomStruct(gc.clone()),
1435            PortV(steel_port) => SteelVal::PortV(steel_port.clone()),
1436            IterV(gc) => SteelVal::IterV(gc.clone()),
1437            ReducerV(gc) => SteelVal::ReducerV(gc.clone()),
1438            FutureFunc(f) => SteelVal::FutureFunc(f.clone()),
1439            FutureV(gc) => SteelVal::FutureV(gc.clone()),
1440            StreamV(gc) => SteelVal::StreamV(gc.clone()),
1441            BoxedFunction(gc) => SteelVal::BoxedFunction(gc.clone()),
1442            ContinuationFunction(continuation) => {
1443                SteelVal::ContinuationFunction(continuation.clone())
1444            }
1445            ListV(generic_list) => SteelVal::ListV(generic_list.clone()),
1446            SteelVal::Pair(gc) => SteelVal::Pair(gc.clone()),
1447            MutFunc(f) => SteelVal::MutFunc(*f),
1448            BuiltIn(f) => SteelVal::BuiltIn(*f),
1449            MutableVector(heap_ref) => SteelVal::MutableVector(heap_ref.clone()),
1450            BoxedIterator(gc) => SteelVal::BoxedIterator(gc.clone()),
1451            SteelVal::SyntaxObject(gc) => SteelVal::SyntaxObject(gc.clone()),
1452            Boxed(gc) => SteelVal::Boxed(gc.clone()),
1453            HeapAllocated(heap_ref) => SteelVal::HeapAllocated(heap_ref.clone()),
1454            Reference(gc) => SteelVal::Reference(gc.clone()),
1455            BigNum(gc) => SteelVal::BigNum(gc.clone()),
1456            SteelVal::BigRational(gc) => SteelVal::BigRational(gc.clone()),
1457            Complex(gc) => SteelVal::Complex(gc.clone()),
1458            ByteVector(steel_byte_vector) => SteelVal::ByteVector(steel_byte_vector.clone()),
1459        }
1460    }
1461}
1462
1463impl Default for SteelVal {
1464    fn default() -> Self {
1465        SteelVal::Void
1466    }
1467}
1468
1469// Avoid as much dropping as possible. Otherwise we thrash the drop impl
1470// on steel values.
1471#[cfg(feature = "sync")]
1472pub(crate) enum SteelValPointer {
1473    /// Represents a bytecode closure.
1474    Closure(*const ByteCodeLambda),
1475    VectorV(*const Vector<SteelVal>),
1476    Custom(*const RwLock<Box<dyn CustomType>>),
1477    HashMapV(*const HashMap<SteelVal, SteelVal>),
1478    HashSetV(*const HashSet<SteelVal>),
1479    CustomStruct(*const UserDefinedStruct),
1480    IterV(*const Transducer),
1481    ReducerV(*const Reducer),
1482    StreamV(*const LazyStream),
1483    ContinuationFunction(*const RwLock<ContinuationMark>),
1484    ListV(crate::values::lists::CellPointer<SteelVal>),
1485    Pair(*const crate::values::lists::Pair),
1486    MutableVector(HeapRef<Vec<SteelVal>>),
1487    SyntaxObject(*const Syntax),
1488    BoxedIterator(*const RwLock<OpaqueIterator>),
1489    Boxed(*const RwLock<SteelVal>),
1490    HeapAllocated(HeapRef<SteelVal>),
1491}
1492
1493#[cfg(feature = "sync")]
1494unsafe impl Sync for SteelValPointer {}
1495#[cfg(feature = "sync")]
1496unsafe impl Send for SteelValPointer {}
1497
1498#[cfg(feature = "sync")]
1499impl SteelValPointer {
1500    pub(crate) fn from_value(value: &SteelVal) -> Option<Self> {
1501        match value {
1502            Closure(gc) => Some(Self::Closure(gc.as_ptr())),
1503            VectorV(steel_vector) => Some(Self::VectorV(steel_vector.0.as_ptr())),
1504            SteelVal::Custom(gc) => Some(Self::Custom(gc.as_ptr())),
1505            HashMapV(steel_hash_map) => Some(Self::HashMapV(steel_hash_map.0.as_ptr())),
1506            HashSetV(steel_hash_set) => Some(Self::HashSetV(steel_hash_set.0.as_ptr())),
1507            CustomStruct(gc) => Some(Self::CustomStruct(gc.as_ptr())),
1508            IterV(gc) => Some(Self::IterV(gc.as_ptr())),
1509            ReducerV(gc) => Some(Self::ReducerV(gc.as_ptr())),
1510            StreamV(gc) => Some(Self::StreamV(gc.as_ptr())),
1511            ListV(generic_list) => Some(Self::ListV(generic_list.as_ptr())),
1512            Pair(gc) => Some(Self::Pair(gc.as_ptr())),
1513            SteelVal::ContinuationFunction(continuation) => Some(Self::ContinuationFunction(
1514                crate::gc::shared::StandardShared::as_ptr(&continuation.inner),
1515            )),
1516            // TODO: See if we can avoid these clones?
1517            MutableVector(heap_ref) => Some(Self::MutableVector(heap_ref.clone())),
1518            BoxedIterator(gc) => Some(Self::BoxedIterator(gc.as_ptr())),
1519            SteelVal::SyntaxObject(gc) => Some(Self::SyntaxObject(gc.as_ptr())),
1520            Boxed(gc) => Some(Self::Boxed(gc.as_ptr())),
1521            // TODO: See if we can avoid these clones?
1522            HeapAllocated(heap_ref) => Some(Self::HeapAllocated(heap_ref.clone())),
1523            _ => None,
1524        }
1525    }
1526}
1527
1528#[cfg(feature = "sync")]
1529#[test]
1530fn check_send_sync() {
1531    let value = SteelVal::IntV(10);
1532
1533    let handle = std::thread::spawn(move || value);
1534
1535    handle.join().unwrap();
1536}
1537
1538#[derive(Clone, Debug)]
1539pub struct SteelByteVector {
1540    pub(crate) vec: GcMut<Vec<u8>>,
1541}
1542
1543impl SteelByteVector {
1544    pub fn new(vec: Vec<u8>) -> Self {
1545        Self {
1546            vec: Gc::new_mut(vec),
1547        }
1548    }
1549}
1550
1551impl PartialEq for SteelByteVector {
1552    fn eq(&self, other: &Self) -> bool {
1553        *(self.vec.read()) == *(other.vec.read())
1554    }
1555}
1556
1557impl Eq for SteelByteVector {}
1558
1559impl Hash for SteelByteVector {
1560    fn hash<H: Hasher>(&self, state: &mut H) {
1561        self.vec.read().hash(state);
1562    }
1563}
1564
1565/// Contains a complex number.
1566///
1567/// TODO: Optimize the contents of complex value. Holding `SteelVal` makes it easier to use existing
1568/// operations but a more specialized representation may be faster.
1569#[derive(Clone, Debug, Hash, PartialEq)]
1570pub struct SteelComplex {
1571    /// The real part of the complex number.
1572    pub re: SteelVal,
1573    /// The imaginary part of the complex number.
1574    pub im: SteelVal,
1575}
1576
1577impl SteelComplex {
1578    pub fn new(real: SteelVal, imaginary: SteelVal) -> SteelComplex {
1579        SteelComplex {
1580            re: real,
1581            im: imaginary,
1582        }
1583    }
1584
1585    /// Returns `true` if the imaginary part is negative.
1586    pub(crate) fn imaginary_is_negative(&self) -> bool {
1587        match &self.im {
1588            NumV(x) => x.is_negative(),
1589            IntV(x) => x.is_negative(),
1590            Rational(x) => x.is_negative(),
1591            BigNum(x) => x.is_negative(),
1592            SteelVal::BigRational(x) => x.is_negative(),
1593            _ => unreachable!(),
1594        }
1595    }
1596
1597    pub(crate) fn imaginary_is_finite(&self) -> bool {
1598        match &self.im {
1599            NumV(x) => x.is_finite(),
1600            IntV(_) | Rational(_) | BigNum(_) | SteelVal::BigRational(_) => true,
1601            _ => unreachable!(),
1602        }
1603    }
1604}
1605
1606impl IntoSteelVal for SteelComplex {
1607    #[inline(always)]
1608    fn into_steelval(self) -> Result<SteelVal> {
1609        Ok(match self.im {
1610            NumV(n) if n.is_zero() => self.re,
1611            IntV(0) => self.re,
1612            _ => SteelVal::Complex(Gc::new(self)),
1613        })
1614    }
1615}
1616
1617impl fmt::Display for SteelComplex {
1618    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1619        if self.imaginary_is_negative() || !self.imaginary_is_finite() {
1620            write!(f, "{re}{im}i", re = self.re, im = self.im)
1621        } else {
1622            write!(f, "{re}+{im}i", re = self.re, im = self.im)
1623        }
1624    }
1625}
1626
1627impl SteelVal {
1628    // TODO: Re-evaluate this - should this be buffered?
1629    pub fn new_dyn_writer_port(port: impl Write + Send + Sync + 'static) -> SteelVal {
1630        SteelVal::PortV(SteelPort {
1631            port: Gc::new_lock(SteelPortRepr::DynWriter(Arc::new(Mutex::new(port)))),
1632        })
1633    }
1634
1635    pub fn anonymous_boxed_function(
1636        function: alloc::sync::Arc<
1637            dyn Fn(&[SteelVal]) -> crate::rvals::Result<SteelVal> + Send + Sync + 'static,
1638        >,
1639    ) -> SteelVal {
1640        SteelVal::BoxedFunction(Gc::new(BoxedDynFunction {
1641            function,
1642            name: None,
1643            arity: None,
1644        }))
1645    }
1646
1647    pub fn as_box(&self) -> Option<HeapRef<SteelVal>> {
1648        if let SteelVal::HeapAllocated(heap_ref) = self {
1649            Some(heap_ref.clone())
1650        } else {
1651            None
1652        }
1653    }
1654
1655    pub fn as_box_to_inner(&self) -> Option<SteelVal> {
1656        self.as_box().map(|x| x.get())
1657    }
1658
1659    pub fn as_ptr_usize(&self) -> Option<usize> {
1660        match self {
1661            Closure(l) => Some(l.as_ptr() as usize),
1662            VectorV(v) => Some(v.0.as_ptr() as usize),
1663            // Void => todo!(),
1664            StringV(s) => Some(s.0.as_ptr() as usize),
1665            FuncV(_) => todo!(),
1666            // SymbolV(_) => todo!(),
1667            // SteelVal::Custom(_) => todo!(),
1668            HashMapV(h) => Some(h.0.as_ptr() as usize),
1669            HashSetV(h) => Some(h.0.as_ptr() as usize),
1670            CustomStruct(c) => Some(c.as_ptr() as usize),
1671            // PortV(_) => todo!(),
1672            // IterV(_) => todo!(),
1673            // ReducerV(_) => todo!(),
1674            // FutureFunc(_) => todo!(),
1675            // FutureV(_) => todo!(),
1676            // StreamV(_) => todo!(),
1677            // BoxedFunction(_) => todo!(),
1678            // ContinuationFunction(_) => todo!(),
1679            ListV(l) => Some(l.as_ptr_usize()),
1680            MutableVector(v) => Some(v.as_ptr_usize()),
1681            Custom(c) => Some(c.as_ptr() as usize),
1682            // BoxedIterator(_) => todo!(),
1683            // SteelVal::SyntaxObject(_) => todo!(),
1684            Boxed(b) => Some(b.as_ptr() as usize),
1685            HeapAllocated(h) => Some(h.as_ptr_usize()),
1686            Pair(p) => Some(p.as_ptr() as usize),
1687            SyntaxObject(s) => Some(s.as_ptr() as usize),
1688            // Reference(_) => todo!(),
1689            BigNum(b) => Some(b.as_ptr() as usize),
1690            _ => None,
1691        }
1692    }
1693
1694    // pub(crate) fn children_mut<'a>(&'a mut self) -> impl IntoIterator<Item = SteelVal> {
1695    //     match self {
1696    //         Self::CustomStruct(inner) => {
1697    //             if let Some(inner) = inner.get_mut() {
1698    //                 core::mem::take(&mut inner.borrow_mut().fields)
1699    //             } else {
1700    //                 core::iter::empty()
1701    //             }
1702    //         }
1703    //         _ => todo!(),
1704    //     }
1705    // }
1706}
1707
1708// TODO: Consider unboxed value types, for optimized usages when compiling segments of code.
1709// If we can infer the types from the concrete functions used, we don't need to have unboxed values -> We also
1710// can use concrete forms of the underlying functions as well.
1711// #[derive(Clone)]
1712// pub enum UnboxedSteelVal {
1713//     /// Represents a boolean value
1714//     BoolV(bool),
1715//     /// Represents a number, currently only f64 numbers are supported
1716//     NumV(f64),
1717//     /// Represents an integer
1718//     IntV(isize),
1719//     /// Represents a character type
1720//     CharV(char),
1721//     /// Vectors are represented as `im_rc::Vector`'s, which are immutable
1722//     /// data structures
1723//     VectorV(Vector<SteelVal>),
1724//     /// Void return value
1725//     Void,
1726//     /// Represents strings
1727//     StringV(SteelString),
1728//     /// Represents built in rust functions
1729//     FuncV(FunctionSignature),
1730//     /// Represents a symbol, internally represented as `String`s
1731//     SymbolV(SteelString),
1732//     /// Container for a type that implements the `Custom Type` trait. (trait object)
1733//     Custom(Gc<RefCell<Box<dyn CustomType>>>),
1734//     // Embedded HashMap
1735//     HashMapV(HashMap<SteelVal, SteelVal>),
1736//     // Embedded HashSet
1737//     HashSetV(HashSet<SteelVal>),
1738//     /// Represents a scheme-only struct
1739//     // StructV(Gc<SteelStruct>),
1740//     /// Alternative implementation of a scheme-only struct
1741//     CustomStruct(Gc<RefCell<UserDefinedStruct>>),
1742//     // Represents a special rust closure
1743//     // StructClosureV(Box<SteelStruct>, StructClosureSignature),
1744//     // StructClosureV(Box<StructClosure>),
1745//     /// Represents a port object
1746//     PortV(SteelPort),
1747//     /// Represents a bytecode closure
1748//     Closure(Gc<ByteCodeLambda>),
1749//     /// Generic iterator wrapper
1750//     IterV(Gc<Transducer>),
1751//     /// Reducers
1752//     ReducerV(Gc<Reducer>),
1753//     // Reducer(Reducer)
1754//     // Generic IntoIter wrapper
1755//     // Promise(Gc<SteelVal>),
1756//     /// Async Function wrapper
1757//     FutureFunc(BoxedAsyncFunctionSignature),
1758//     // Boxed Future Result
1759//     FutureV(Gc<FutureResult>),
1760
1761//     StreamV(Gc<LazyStream>),
1762//     // Break the cycle somehow
1763//     // EvaluationEnv(Weak<RefCell<Env>>),
1764//     /// Contract
1765//     Contract(Gc<ContractType>),
1766//     /// Contracted Function
1767//     ContractedFunction(Gc<ContractedFunction>),
1768//     /// Custom closure
1769//     BoxedFunction(BoxedFunctionSignature),
1770//     // Continuation
1771//     ContinuationFunction(Gc<Continuation>),
1772//     // List
1773//     ListV(List<SteelVal>),
1774//     // Mutable functions
1775//     MutFunc(MutFunctionSignature),
1776//     // Built in functions
1777//     BuiltIn(BuiltInSignature),
1778//     // Mutable vector
1779//     MutableVector(Gc<RefCell<Vec<SteelVal>>>),
1780//     // This should delegate to the underlying iterator - can allow for faster raw iteration if possible
1781//     // Should allow for polling just a raw "next" on underlying elements
1782//     BoxedIterator(Gc<RefCell<BuiltInDataStructureIterator>>),
1783
1784//     SyntaxObject(Gc<Syntax>),
1785
1786//     // Mutable storage, with Gc backing
1787//     Boxed(HeapRef),
1788// }
1789
1790#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1791#[repr(C)]
1792pub struct SteelString(pub(crate) Gc<String>);
1793
1794impl Deref for SteelString {
1795    type Target = crate::gc::Shared<String>;
1796
1797    fn deref(&self) -> &Self::Target {
1798        &self.0 .0
1799    }
1800}
1801
1802#[cfg(not(feature = "sync"))]
1803impl From<Arc<String>> for SteelString {
1804    fn from(value: Arc<String>) -> Self {
1805        SteelString(Gc(Rc::new((*value).clone())))
1806    }
1807}
1808
1809#[cfg(all(feature = "sync", feature = "triomphe", not(feature = "biased")))]
1810impl From<Arc<String>> for SteelString {
1811    fn from(value: Arc<String>) -> Self {
1812        SteelString(Gc(triomphe::Arc::new((*value).clone())))
1813    }
1814}
1815
1816#[cfg(all(feature = "sync", feature = "biased", not(feature = "triomphe")))]
1817impl From<Arc<String>> for SteelString {
1818    fn from(value: Arc<String>) -> Self {
1819        SteelString(Gc(steel_rc::BiasedRc::new((*value).clone())))
1820    }
1821}
1822
1823impl From<&str> for SteelString {
1824    fn from(val: &str) -> Self {
1825        SteelString(Gc::new(val.to_string()))
1826    }
1827}
1828
1829impl From<&String> for SteelString {
1830    fn from(val: &String) -> Self {
1831        SteelString(Gc::new(val.to_owned()))
1832    }
1833}
1834
1835impl From<String> for SteelString {
1836    fn from(val: String) -> Self {
1837        SteelString(Gc::new(val))
1838    }
1839}
1840
1841impl From<crate::gc::Shared<String>> for SteelString {
1842    fn from(val: crate::gc::Shared<String>) -> Self {
1843        SteelString(Gc(val))
1844    }
1845}
1846
1847impl From<Gc<String>> for SteelString {
1848    fn from(val: Gc<String>) -> Self {
1849        SteelString(val)
1850    }
1851}
1852
1853impl From<SteelString> for crate::gc::Shared<String> {
1854    fn from(value: SteelString) -> Self {
1855        value.0 .0
1856    }
1857}
1858
1859impl From<SteelString> for Gc<String> {
1860    fn from(value: SteelString) -> Self {
1861        value.0
1862    }
1863}
1864
1865impl core::fmt::Display for SteelString {
1866    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1867        write!(f, "{}", self.0.as_str())
1868    }
1869}
1870
1871impl core::fmt::Debug for SteelString {
1872    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1873        write!(f, "{:?}", self.0.as_str())
1874    }
1875}
1876
1877// Check that steel values aren't growing without us knowing
1878const _ASSERT_SMALL: () = assert!(core::mem::size_of::<SteelVal>() <= 16);
1879
1880#[test]
1881fn check_size_of_steelval() {
1882    assert_eq!(core::mem::size_of::<SteelVal>(), 16);
1883}
1884
1885pub struct Chunks {
1886    remaining: IntoIter<char>,
1887}
1888
1889impl Chunks {
1890    fn new(s: SteelString) -> Self {
1891        Chunks {
1892            remaining: s.chars().collect::<Vec<_>>().into_iter(),
1893        }
1894    }
1895}
1896
1897pub struct OpaqueIterator {
1898    pub(crate) root: SteelVal,
1899    iterator: BuiltInDataStructureIterator,
1900}
1901
1902impl Custom for OpaqueIterator {
1903    fn fmt(&self) -> Option<core::result::Result<String, core::fmt::Error>> {
1904        Some(Ok("#<iterator>".to_owned()))
1905    }
1906}
1907
1908// TODO: Convert this to just a generic custom type. This does not have to be
1909// a special enum variant.
1910pub enum BuiltInDataStructureIterator {
1911    List(crate::values::lists::ConsumingIterator<SteelVal>),
1912    Vector(VectorConsumingIter<SteelVal>),
1913    Set(HashSetConsumingIter<SteelVal>),
1914    Map(HashMapConsumingIter<SteelVal, SteelVal>),
1915    String(Chunks),
1916    #[cfg(not(feature = "sync"))]
1917    Opaque(Box<dyn Iterator<Item = SteelVal>>),
1918    #[cfg(feature = "sync")]
1919    Opaque(Box<dyn Iterator<Item = SteelVal> + Send + Sync + 'static>),
1920}
1921
1922impl BuiltInDataStructureIterator {
1923    pub fn into_boxed_iterator(self, value: SteelVal) -> SteelVal {
1924        SteelVal::BoxedIterator(Gc::new_mut(OpaqueIterator {
1925            root: value,
1926            iterator: self,
1927        }))
1928    }
1929}
1930
1931impl BuiltInDataStructureIterator {
1932    pub fn from_iterator<
1933        T: IntoSteelVal + MaybeSendSyncStatic,
1934        I: Iterator<Item = T> + MaybeSendSyncStatic,
1935        S: IntoIterator<Item = T, IntoIter = I> + MaybeSendSyncStatic,
1936    >(
1937        value: S,
1938    ) -> Self {
1939        Self::Opaque(Box::new(
1940            value
1941                .into_iter()
1942                .map(|x| x.into_steelval().expect("This shouldn't fail!")),
1943        ))
1944    }
1945}
1946
1947impl Iterator for BuiltInDataStructureIterator {
1948    type Item = SteelVal;
1949
1950    fn next(&mut self) -> Option<SteelVal> {
1951        match self {
1952            Self::List(l) => l.next(),
1953            Self::Vector(v) => v.next(),
1954            Self::String(s) => s.remaining.next().map(SteelVal::CharV),
1955            Self::Set(s) => s.next(),
1956            Self::Map(s) => s
1957                .next()
1958                .map(|x| SteelVal::Pair(Gc::new(Pair::cons(x.0, x.1)))),
1959            Self::Opaque(s) => s.next(),
1960        }
1961    }
1962}
1963
1964pub fn value_into_iterator(val: SteelVal) -> Option<SteelVal> {
1965    let root = val.clone();
1966    match val {
1967        SteelVal::ListV(l) => Some(BuiltInDataStructureIterator::List(l.into_iter())),
1968        SteelVal::VectorV(v) => Some(BuiltInDataStructureIterator::Vector(
1969            (*v).clone().into_iter(),
1970        )),
1971        SteelVal::StringV(s) => Some(BuiltInDataStructureIterator::String(Chunks::new(s))),
1972        SteelVal::HashSetV(s) => Some(BuiltInDataStructureIterator::Set((*s).clone().into_iter())),
1973        SteelVal::HashMapV(m) => Some(BuiltInDataStructureIterator::Map((*m).clone().into_iter())),
1974        // TODO: Add byte vectors here
1975        _ => None,
1976    }
1977    .map(|iterator| BuiltInDataStructureIterator::into_boxed_iterator(iterator, root))
1978}
1979
1980thread_local! {
1981    pub static ITERATOR_FINISHED: SteelVal = SteelVal::SymbolV("done".into());
1982}
1983
1984pub fn iterator_next(args: &[SteelVal]) -> Result<SteelVal> {
1985    match &args[0] {
1986        SteelVal::BoxedIterator(b) => match b.write().iterator.next() {
1987            Some(v) => Ok(v),
1988            None => Ok(ITERATOR_FINISHED.with(|x| x.clone())),
1989        },
1990        _ => stop!(TypeMismatch => "Unexpected argument"),
1991    }
1992}
1993
1994impl SteelVal {
1995    pub fn boxed(value: SteelVal) -> SteelVal {
1996        SteelVal::Boxed(Gc::new_mut(value))
1997    }
1998
1999    pub(crate) fn ptr_eq(&self, other: &SteelVal) -> bool {
2000        match (self, other) {
2001            // Integers are a special case of ptr eq -> if integers are equal? they are also eq?
2002            (IntV(l), IntV(r)) => l == r,
2003            (NumV(l), NumV(r)) => l == r,
2004            (BoolV(l), BoolV(r)) => l == r,
2005            (CharV(l), CharV(r)) => l == r,
2006            (VectorV(l), VectorV(r)) => Gc::ptr_eq(&l.0, &r.0),
2007            (Void, Void) => true,
2008            (StringV(l), StringV(r)) => crate::gc::Shared::ptr_eq(l, r),
2009            (FuncV(l), FuncV(r)) => *l as usize == *r as usize,
2010            (SymbolV(l), SymbolV(r)) => crate::gc::Shared::ptr_eq(l, r),
2011            (SteelVal::Custom(l), SteelVal::Custom(r)) => Gc::ptr_eq(l, r),
2012            (HashMapV(l), HashMapV(r)) => Gc::ptr_eq(&l.0, &r.0),
2013            (HashSetV(l), HashSetV(r)) => Gc::ptr_eq(&l.0, &r.0),
2014            (PortV(l), PortV(r)) => Gc::ptr_eq(&l.port, &r.port),
2015            (Closure(l), Closure(r)) => Gc::ptr_eq(l, r),
2016            (IterV(l), IterV(r)) => Gc::ptr_eq(l, r),
2017            (ReducerV(l), ReducerV(r)) => Gc::ptr_eq(l, r),
2018            (FutureFunc(l), FutureFunc(r)) => crate::gc::Shared::ptr_eq(l, r),
2019            (FutureV(l), FutureV(r)) => Gc::ptr_eq(l, r),
2020            (StreamV(l), StreamV(r)) => Gc::ptr_eq(l, r),
2021            (BoxedFunction(l), BoxedFunction(r)) => Gc::ptr_eq(l, r),
2022            (ContinuationFunction(l), ContinuationFunction(r)) => Continuation::ptr_eq(l, r),
2023            (ListV(l), ListV(r)) => {
2024                // Happy path
2025                l.ptr_eq(r) || l.storage_ptr_eq(r) || (l.is_empty() && r.is_empty()) || {
2026                    slow_path_eq_lists(l, r)
2027                }
2028            }
2029            (MutFunc(l), MutFunc(r)) => *l as usize == *r as usize,
2030            (BuiltIn(l), BuiltIn(r)) => *l as usize == *r as usize,
2031            (MutableVector(l), MutableVector(r)) => HeapRef::ptr_eq(l, r),
2032            (BigNum(l), BigNum(r)) => Gc::ptr_eq(l, r),
2033            (ByteVector(l), ByteVector(r)) => Gc::ptr_eq(&l.vec, &r.vec),
2034            (Pair(l), Pair(r)) => Gc::ptr_eq(l, r),
2035            (_, _) => {
2036                // dbg!(pointers);
2037                false
2038            }
2039        }
2040    }
2041}
2042
2043// How can we keep track of the provenance of where the pointers go?
2044// for pointer equality?
2045#[inline]
2046fn slow_path_eq_lists(
2047    _l: &crate::values::lists::List<SteelVal>,
2048    _r: &crate::values::lists::List<SteelVal>,
2049) -> bool {
2050    false
2051
2052    /*
2053
2054    // If the next pointers are the same,
2055    // then we need to check the values of the
2056    // current node for equality. There is now the possibility
2057    // that the previous version of this doesn't match up, and
2058    // we need to keep the history of the previous values in order
2059    // to do this properly.
2060    //
2061    // I think we can only really do this _if_ the next pointer
2062    // exists. Otherwise this doesn't really make sense
2063    let left_next = l.next_ptr_as_usize();
2064    let right_next = r.next_ptr_as_usize();
2065
2066    if left_next.is_some() && right_next.is_some() && left_next == right_next && l.len() == r.len()
2067    {
2068        let left_iter = l.current_node_iter();
2069        let right_iter = r.current_node_iter();
2070
2071        for (l, r) in left_iter.zip(right_iter) {
2072            if l != r {
2073                return false;
2074            }
2075        }
2076
2077        true
2078    } else {
2079        false
2080    }
2081
2082    */
2083}
2084
2085impl Hash for SteelVal {
2086    fn hash<H: Hasher>(&self, state: &mut H) {
2087        core::mem::discriminant(self).hash(state);
2088        match self {
2089            Closure(b) => b.hash(state),
2090            BoolV(b) => b.hash(state),
2091            NumV(n) => n.to_string().hash(state),
2092            IntV(i) => i.hash(state),
2093            Rational(f) => f.hash(state),
2094            CharV(c) => c.hash(state),
2095            VectorV(v) => v.hash(state),
2096            Void => {}
2097            StringV(s) => s.hash(state),
2098            FuncV(s) => s.hash(state),
2099            SymbolV(sym) => sym.hash(state),
2100            #[cfg(feature = "custom-hash")]
2101            Custom(v) => match v.read().try_as_dyn_hash() {
2102                Some(x) => x.dyn_hash(state),
2103                _ => Gc::as_ptr(v).hash(state),
2104            },
2105            #[cfg(not(feature = "custom-hash"))]
2106            Custom(v) => Gc::as_ptr(v).hash(state),
2107            HashMapV(hm) => hm.hash(state),
2108            HashSetV(hs) => hs.hash(state),
2109            CustomStruct(s) => s.hash(state),
2110            PortV(port) => port.hash(state),
2111            IterV(s) => s.hash(state),
2112            ReducerV(r) => r.hash(state),
2113            FutureFunc(fun) => crate::gc::Shared::as_ptr(fun).hash(state),
2114            FutureV(f) => Gc::as_ptr(f).hash(state),
2115            StreamV(s) => Gc::as_ptr(s).hash(state),
2116            BoxedFunction(fun) => Gc::as_ptr(fun).hash(state),
2117            ContinuationFunction(cont) => StandardShared::as_ptr(&cont.inner).hash(state),
2118            ListV(l) => l.hash(state),
2119            Pair(p) => (**p).hash(state),
2120            MutFunc(fun) => fun.hash(state),
2121            BuiltIn(fun) => fun.hash(state),
2122            MutableVector(vec) => vec.get().hash(state),
2123            BoxedIterator(iter) => Gc::as_ptr(iter).hash(state),
2124            SyntaxObject(s) => s.raw.hash(state),
2125            Boxed(val) => val.read().hash(state),
2126            HeapAllocated(v) => v.get().hash(state),
2127            Reference(v) => Gc::as_ptr(v).hash(state),
2128            BigNum(n) => n.hash(state),
2129            BigRational(f) => f.hash(state),
2130            Complex(x) => x.hash(state),
2131            ByteVector(v) => (*v).hash(state),
2132        }
2133    }
2134}
2135
2136impl SteelVal {
2137    #[inline(always)]
2138    pub fn is_truthy(&self) -> bool {
2139        match &self {
2140            SteelVal::BoolV(false) => false,
2141            _ => true,
2142        }
2143    }
2144
2145    #[inline(always)]
2146    pub fn is_future(&self) -> bool {
2147        matches!(self, SteelVal::FutureV(_))
2148    }
2149
2150    pub fn is_function(&self) -> bool {
2151        matches!(
2152            self,
2153            BoxedFunction(_)
2154                | Closure(_)
2155                | FuncV(_)
2156                // | ContractedFunction(_)
2157                | BuiltIn(_)
2158                | MutFunc(_)
2159        )
2160    }
2161
2162    // pub fn is_contract(&self) -> bool {
2163    //     matches!(self, Contract(_))
2164    // }
2165
2166    pub fn empty_hashmap() -> SteelVal {
2167        SteelVal::HashMapV(Gc::new(HashMap::new()).into())
2168    }
2169}
2170
2171impl SteelVal {
2172    // pub fn res_iterator
2173
2174    pub fn list_or_else<E, F: FnOnce() -> E>(
2175        &self,
2176        err: F,
2177    ) -> core::result::Result<&List<SteelVal>, E> {
2178        match self {
2179            Self::ListV(v) => Ok(v),
2180            _ => Err(err()),
2181        }
2182    }
2183
2184    pub fn list(&self) -> Option<&List<SteelVal>> {
2185        match self {
2186            Self::ListV(l) => Some(l),
2187            _ => None,
2188        }
2189    }
2190
2191    pub fn pair(&self) -> Option<&Gc<crate::values::lists::Pair>> {
2192        match self {
2193            Self::Pair(p) => Some(p),
2194            _ => None,
2195        }
2196    }
2197
2198    pub fn bool_or_else<E, F: FnOnce() -> E>(&self, err: F) -> core::result::Result<bool, E> {
2199        match self {
2200            Self::BoolV(v) => Ok(*v),
2201            _ => Err(err()),
2202        }
2203    }
2204
2205    pub fn int_or_else<E, F: FnOnce() -> E>(&self, err: F) -> core::result::Result<isize, E> {
2206        match self {
2207            Self::IntV(v) => Ok(*v),
2208            _ => Err(err()),
2209        }
2210    }
2211
2212    pub fn num_or_else<E, F: FnOnce() -> E>(&self, err: F) -> core::result::Result<f64, E> {
2213        match self {
2214            Self::NumV(v) => Ok(*v),
2215            _ => Err(err()),
2216        }
2217    }
2218
2219    pub fn char_or_else<E, F: FnOnce() -> E>(&self, err: F) -> core::result::Result<char, E> {
2220        match self {
2221            Self::CharV(v) => Ok(*v),
2222            _ => Err(err()),
2223        }
2224    }
2225
2226    /// Vector does copy on the value to return
2227    pub fn vector_or_else<E, F: FnOnce() -> E>(
2228        &self,
2229        err: F,
2230    ) -> core::result::Result<Vector<SteelVal>, E> {
2231        match self {
2232            Self::VectorV(v) => Ok(v.0.unwrap()),
2233            _ => Err(err()),
2234        }
2235    }
2236
2237    pub fn void_or_else<E, F: FnOnce() -> E>(&self, err: F) -> core::result::Result<(), E> {
2238        match self {
2239            Self::Void => Ok(()),
2240            _ => Err(err()),
2241        }
2242    }
2243
2244    pub fn string_or_else<E, F: FnOnce() -> E>(&self, err: F) -> core::result::Result<&str, E> {
2245        match self {
2246            Self::StringV(v) => Ok(v),
2247            _ => Err(err()),
2248        }
2249    }
2250
2251    pub fn func_or_else<E, F: FnOnce() -> E>(
2252        &self,
2253        err: F,
2254    ) -> core::result::Result<&FunctionSignature, E> {
2255        match self {
2256            Self::FuncV(v) => Ok(v),
2257            _ => Err(err()),
2258        }
2259    }
2260
2261    pub fn boxed_func_or_else<E, F: FnOnce() -> E>(
2262        &self,
2263        err: F,
2264    ) -> core::result::Result<&BoxedDynFunction, E> {
2265        match self {
2266            Self::BoxedFunction(v) => Ok(v),
2267            _ => Err(err()),
2268        }
2269    }
2270
2271    // pub fn contract_or_else<E, F: FnOnce() -> E>(
2272    //     &self,
2273    //     err: F,
2274    // ) -> core::result::Result<Gc<ContractType>, E> {
2275    //     match self {
2276    //         Self::Contract(c) => Ok(c.clone()),
2277    //         _ => Err(err()),
2278    //     }
2279    // }
2280
2281    pub fn closure_or_else<E, F: FnOnce() -> E>(
2282        &self,
2283        err: F,
2284    ) -> core::result::Result<Gc<ByteCodeLambda>, E> {
2285        match self {
2286            Self::Closure(c) => Ok(c.clone()),
2287            _ => Err(err()),
2288        }
2289    }
2290
2291    pub fn symbol_or_else<E, F: FnOnce() -> E>(&self, err: F) -> core::result::Result<&str, E> {
2292        match self {
2293            Self::SymbolV(v) => Ok(v),
2294            _ => Err(err()),
2295        }
2296    }
2297
2298    pub fn clone_symbol_or_else<E, F: FnOnce() -> E>(
2299        &self,
2300        err: F,
2301    ) -> core::result::Result<String, E> {
2302        match self {
2303            Self::SymbolV(v) => Ok(v.to_string()),
2304            _ => Err(err()),
2305        }
2306    }
2307
2308    pub fn as_isize(&self) -> Option<isize> {
2309        match self {
2310            Self::IntV(i) => Some(*i),
2311            _ => None,
2312        }
2313    }
2314
2315    pub fn as_usize(&self) -> Option<usize> {
2316        self.as_isize()
2317            .and_then(|x| if x >= 0 { Some(x as usize) } else { None })
2318    }
2319
2320    pub fn as_bool(&self) -> Option<bool> {
2321        match self {
2322            Self::BoolV(b) => Some(*b),
2323            _ => None,
2324        }
2325    }
2326
2327    pub fn as_future(&self) -> Option<Shared<BoxedFutureResult>> {
2328        match self {
2329            Self::FutureV(v) => Some(v.clone().unwrap().into_shared()),
2330            _ => None,
2331        }
2332    }
2333
2334    pub fn as_string(&self) -> Option<&SteelString> {
2335        match self {
2336            Self::StringV(s) => Some(s),
2337            _ => None,
2338        }
2339    }
2340
2341    pub fn as_symbol(&self) -> Option<&SteelString> {
2342        match self {
2343            Self::SymbolV(s) => Some(s),
2344            _ => None,
2345        }
2346    }
2347
2348    pub fn as_syntax_object(&self) -> Option<&Syntax> {
2349        match self {
2350            Self::SyntaxObject(s) => Some(s),
2351            _ => None,
2352        }
2353    }
2354
2355    // pub fn custom_or_else<E, F: FnOnce() -> E>(
2356    //     &self,
2357    //     err: F,
2358    // ) -> core::result::Result<&Box<dyn CustomType>, E> {
2359    //     match self {
2360    //         Self::Custom(v) => Ok(&v),
2361    //         _ => Err(err()),
2362    //     }
2363    // }
2364
2365    // pub fn struct_or_else<E, F: FnOnce() -> E>(
2366    //     &self,
2367    //     err: F,
2368    // ) -> core::result::Result<&SteelStruct, E> {
2369    //     match self {
2370    //         Self::StructV(v) => Ok(v),
2371    //         _ => Err(err()),
2372    //     }
2373    // }
2374
2375    pub fn closure_arity(&self) -> Option<usize> {
2376        if let SteelVal::Closure(c) = self {
2377            Some(c.arity())
2378        } else {
2379            None
2380        }
2381    }
2382}
2383
2384impl SteelVal {
2385    pub const INT_ZERO: SteelVal = SteelVal::IntV(0);
2386    pub const INT_ONE: SteelVal = SteelVal::IntV(1);
2387    pub const INT_TWO: SteelVal = SteelVal::IntV(2);
2388}
2389
2390impl Eq for SteelVal {}
2391
2392fn integer_float_equality(int: isize, float: f64) -> bool {
2393    let converted = float as isize;
2394
2395    if float == converted as f64 {
2396        int == converted
2397    } else {
2398        false
2399    }
2400}
2401
2402fn bignum_float_equality(bigint: &Gc<BigInt>, float: f64) -> bool {
2403    if float.fract() == 0.0 {
2404        if let Some(promoted) = bigint.to_f64() {
2405            promoted == float
2406        } else {
2407            false
2408        }
2409    } else {
2410        false
2411    }
2412}
2413
2414#[inline(always)]
2415#[steel_derive::function(name = "=", constant = true)]
2416pub fn number_equality(left: &SteelVal, right: &SteelVal) -> Result<SteelVal> {
2417    let result = match (left, right) {
2418        (IntV(l), IntV(r)) => l == r,
2419        (NumV(l), NumV(r)) => l == r,
2420        (IntV(l), NumV(r)) | (NumV(r), IntV(l)) => integer_float_equality(*l, *r),
2421        (Rational(l), Rational(r)) => l == r,
2422        (Rational(l), NumV(r)) | (NumV(r), Rational(l)) => l.to_f64().unwrap() == *r,
2423        (BigNum(l), BigNum(r)) => l == r,
2424        (BigNum(l), NumV(r)) | (NumV(r), BigNum(l)) => bignum_float_equality(l, *r),
2425        (BigRational(l), BigRational(r)) => l == r,
2426        (BigRational(l), NumV(r)) | (NumV(r), BigRational(l)) => l.to_f64().unwrap() == *r,
2427        // The below should be impossible as integers/bignums freely convert into each
2428        // other. Similar for int/bignum/rational/bigrational.
2429        (Rational(_), IntV(_))
2430        | (IntV(_), Rational(_))
2431        | (Rational(_), BigNum(_))
2432        | (BigNum(_), Rational(_))
2433        | (Rational(_), BigRational(_))
2434        | (BigRational(_), Rational(_)) => false,
2435        (BigRational(_), IntV(_))
2436        | (IntV(_), BigRational(_))
2437        | (BigRational(_), BigNum(_))
2438        | (BigNum(_), BigRational(_)) => false,
2439        (IntV(_), BigNum(_)) | (BigNum(_), IntV(_)) => false,
2440        (Complex(x), Complex(y)) => {
2441            number_equality(&x.re, &y.re)? == BoolV(true)
2442                && number_equality(&x.im, &y.re)? == BoolV(true)
2443        }
2444        (Complex(_), _) | (_, Complex(_)) => false,
2445        _ => stop!(TypeMismatch => "= expects two numbers, found: {:?} and {:?}", left, right),
2446    };
2447    Ok(BoolV(result))
2448}
2449
2450impl PartialOrd for SteelVal {
2451    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2452        // TODO: Attempt to avoid converting to f64 for cases below as it may lead to precision loss
2453        // at tiny and large values.
2454        match (self, other) {
2455            // Comparison of matching `SteelVal` variants:
2456            (IntV(x), IntV(y)) => x.partial_cmp(y),
2457            (BigNum(x), BigNum(y)) => x.partial_cmp(y),
2458            (Rational(x), Rational(y)) => x.partial_cmp(y),
2459            (BigRational(x), BigRational(y)) => x.partial_cmp(y),
2460            (NumV(x), NumV(y)) => x.partial_cmp(y),
2461            (StringV(s), StringV(o)) => s.partial_cmp(o),
2462            (CharV(l), CharV(r)) => l.partial_cmp(r),
2463
2464            // Comparison of `IntV`, means promoting to the rhs type
2465            (IntV(x), BigNum(y)) => x
2466                .to_bigint()
2467                .expect("integers are representable by bigint")
2468                .partial_cmp(y),
2469            (IntV(x), Rational(y)) => {
2470                // Since we have platform-dependent type for rational conditional compilation is required to find
2471                // the common ground
2472                #[cfg(target_pointer_width = "32")]
2473                {
2474                    let x_rational = num_rational::Rational32::new_raw(*x as i32, 1);
2475                    x_rational.partial_cmp(y)
2476                }
2477                #[cfg(target_pointer_width = "64")]
2478                {
2479                    let x_rational = num_rational::Rational64::new_raw(*x as i64, 1);
2480                    x_rational.partial_cmp(&num_rational::Rational64::new_raw(
2481                        *y.numer() as i64,
2482                        *y.denom() as i64,
2483                    ))
2484                }
2485            }
2486            (IntV(x), BigRational(y)) => {
2487                let x_rational = BigRational::from_integer(
2488                    x.to_bigint().expect("integers are representable by bigint"),
2489                );
2490                x_rational.partial_cmp(y)
2491            }
2492            (IntV(x), NumV(y)) => (*x as f64).partial_cmp(y),
2493
2494            // BigNum comparisons means promoting to BigInt for integers, BigRational for ratios,
2495            // or Decimal otherwise
2496            (BigNum(x), IntV(y)) => x
2497                .as_ref()
2498                .partial_cmp(&y.to_bigint().expect("integers are representable by bigint")),
2499            (BigNum(x), Rational(y)) => {
2500                let x_big_rational = BigRational::from_integer(x.unwrap());
2501                let y_big_rational = BigRational::new_raw(
2502                    y.numer()
2503                        .to_bigint()
2504                        .expect("integers are representable by bigint"),
2505                    y.denom()
2506                        .to_bigint()
2507                        .expect("integers are representable by bigint"),
2508                );
2509                x_big_rational.partial_cmp(&y_big_rational)
2510            }
2511            (BigNum(x), BigRational(y)) => {
2512                let x_big_rational = BigRational::from_integer(x.unwrap());
2513                x_big_rational.partial_cmp(y)
2514            }
2515            (BigNum(x), NumV(y)) => {
2516                let x_decimal = BigDecimal::new(x.unwrap(), 0);
2517                let y_decimal_opt = BigDecimal::from_f64(*y);
2518                y_decimal_opt.and_then(|y_decimal| x_decimal.partial_cmp(&y_decimal))
2519            }
2520
2521            // Rationals require rationals, regular or bigger versions; for float it will be divided to float as well
2522            (Rational(x), IntV(y)) => {
2523                // Same as before, but opposite direction
2524                #[cfg(target_pointer_width = "32")]
2525                {
2526                    let y_rational = num_rational::Rational32::new_raw(*y as i32, 1);
2527                    x.partial_cmp(&y_rational)
2528                }
2529                #[cfg(target_pointer_width = "64")]
2530                {
2531                    let y_rational = num_rational::Rational64::new_raw(*y as i64, 1);
2532                    num_rational::Rational64::new_raw(*x.numer() as i64, *x.denom() as i64)
2533                        .partial_cmp(&y_rational)
2534                }
2535            }
2536            (Rational(x), BigNum(y)) => {
2537                let x_big_rational = BigRational::new_raw(
2538                    x.numer()
2539                        .to_bigint()
2540                        .expect("integers are representable by bigint"),
2541                    x.denom()
2542                        .to_bigint()
2543                        .expect("integers are representable by bigint"),
2544                );
2545                let y_big_rational = BigRational::from_integer(y.unwrap());
2546                x_big_rational.partial_cmp(&y_big_rational)
2547            }
2548            (Rational(x), BigRational(y)) => {
2549                let x_big_rational = BigRational::new_raw(
2550                    x.numer()
2551                        .to_bigint()
2552                        .expect("integers are representable by bigint"),
2553                    x.denom()
2554                        .to_bigint()
2555                        .expect("integers are representable by bigint"),
2556                );
2557                x_big_rational.partial_cmp(y)
2558            }
2559            (Rational(x), NumV(y)) => (*x.numer() as f64 / *x.denom() as f64).partial_cmp(y),
2560
2561            // The most capacious set, but need to cover float case with BigDecimal anyways
2562            (BigRational(x), IntV(y)) => {
2563                let y_rational = BigRational::from_integer(
2564                    y.to_bigint().expect("integers are representable by bigint"),
2565                );
2566                x.as_ref().partial_cmp(&y_rational)
2567            }
2568            (BigRational(x), BigNum(y)) => {
2569                let y_big_rational = BigRational::from_integer(y.unwrap());
2570                x.as_ref().partial_cmp(&y_big_rational)
2571            }
2572            (BigRational(x), Rational(y)) => {
2573                let y_big_rational = BigRational::new_raw(
2574                    y.numer()
2575                        .to_bigint()
2576                        .expect("integers are representable by bigint"),
2577                    y.denom()
2578                        .to_bigint()
2579                        .expect("integers are representable by bigint"),
2580                );
2581                x.as_ref().partial_cmp(&y_big_rational)
2582            }
2583            (BigRational(x), NumV(y)) => {
2584                let x_decimal =
2585                    BigDecimal::new(x.numer().clone(), 0) / BigDecimal::new(x.denom().clone(), 0);
2586                let y_decimal_opt = BigDecimal::from_f64(*y);
2587                y_decimal_opt.and_then(|y_decimal| x_decimal.partial_cmp(&y_decimal))
2588            }
2589
2590            // The opposite of all float cases above
2591            (NumV(x), IntV(y)) => x.partial_cmp(&(*y as f64)),
2592            (NumV(x), BigNum(y)) => {
2593                let x_decimal_opt = BigDecimal::from_f64(*x);
2594                let y_decimal = BigDecimal::new(y.unwrap(), 0);
2595                x_decimal_opt.and_then(|x_decimal| x_decimal.partial_cmp(&y_decimal))
2596            }
2597            (NumV(x), Rational(y)) => x.partial_cmp(&(*y.numer() as f64 / *y.denom() as f64)),
2598            (NumV(x), BigRational(y)) => {
2599                let x_decimal_opt = BigDecimal::from_f64(*x);
2600                let y_decimal =
2601                    BigDecimal::new(y.numer().clone(), 0) / BigDecimal::new(y.denom().clone(), 0);
2602                x_decimal_opt.and_then(|x_decimal| x_decimal.partial_cmp(&y_decimal))
2603            }
2604
2605            (l, r) => {
2606                // All real numbers (not complex) should have order defined.
2607                debug_assert!(
2608                    !(realp(l) && realp(r)),
2609                    "Numbers {l:?} and {r:?} should implement partial_cmp"
2610                );
2611                // Unimplemented for other types
2612                None
2613            }
2614        }
2615    }
2616}
2617
2618pub(crate) struct SteelValDisplay<'a>(pub(crate) &'a SteelVal);
2619
2620impl<'a> fmt::Display for SteelValDisplay<'a> {
2621    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2622        CycleDetector::detect_and_display_cycles(self.0, f, false)
2623    }
2624}
2625
2626impl fmt::Display for SteelVal {
2627    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2628        CycleDetector::detect_and_display_cycles(self, f, true)
2629    }
2630}
2631
2632impl fmt::Debug for SteelVal {
2633    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2634        // at the top level, print a ' if we are
2635        // trying to print a symbol or list
2636        match self {
2637            SymbolV(_) | ListV(_) | VectorV(_) => write!(f, "'")?,
2638            _ => (),
2639        };
2640        // display_helper(self, f)
2641
2642        CycleDetector::detect_and_display_cycles(self, f, true)
2643    }
2644}
2645
2646#[cfg(test)]
2647mod or_else_tests {
2648
2649    use super::*;
2650
2651    #[cfg(all(feature = "sync", not(feature = "imbl")))]
2652    use im::vector;
2653
2654    #[cfg(all(feature = "sync", feature = "imbl"))]
2655    use steel_imbl::generic_vector as vector;
2656
2657    #[cfg(not(feature = "sync"))]
2658    use im_rc::vector;
2659
2660    #[test]
2661    fn bool_or_else_test_good() {
2662        let input = SteelVal::BoolV(true);
2663        assert_eq!(input.bool_or_else(throw!(Generic => "test")).unwrap(), true);
2664    }
2665
2666    #[test]
2667    fn bool_or_else_test_bad() {
2668        let input = SteelVal::CharV('f');
2669        assert!(input.bool_or_else(throw!(Generic => "test")).is_err());
2670    }
2671
2672    #[test]
2673    fn num_or_else_test_good() {
2674        let input = SteelVal::NumV(10.0);
2675        assert_eq!(input.num_or_else(throw!(Generic => "test")).unwrap(), 10.0);
2676    }
2677
2678    #[test]
2679    fn num_or_else_test_bad() {
2680        let input = SteelVal::CharV('f');
2681        assert!(input.num_or_else(throw!(Generic => "test")).is_err());
2682    }
2683
2684    #[test]
2685    fn char_or_else_test_good() {
2686        let input = SteelVal::CharV('f');
2687        assert_eq!(input.char_or_else(throw!(Generic => "test")).unwrap(), 'f');
2688    }
2689
2690    #[test]
2691    fn char_or_else_test_bad() {
2692        let input = SteelVal::NumV(10.0);
2693        assert!(input.char_or_else(throw!(Generic => "test")).is_err());
2694    }
2695
2696    #[test]
2697    fn vector_or_else_test_good() {
2698        let input: SteelVal = vector![SteelVal::IntV(1)].into();
2699        assert_eq!(
2700            input.vector_or_else(throw!(Generic => "test")).unwrap(),
2701            vector![SteelVal::IntV(1)]
2702        );
2703    }
2704
2705    #[test]
2706    fn vector_or_else_bad() {
2707        let input = SteelVal::CharV('f');
2708        assert!(input.vector_or_else(throw!(Generic => "test")).is_err());
2709    }
2710
2711    #[test]
2712    fn void_or_else_test_good() {
2713        let input = SteelVal::Void;
2714        assert_eq!(input.void_or_else(throw!(Generic => "test")).unwrap(), ())
2715    }
2716
2717    #[test]
2718    fn void_or_else_test_bad() {
2719        let input = SteelVal::StringV("foo".into());
2720        assert!(input.void_or_else(throw!(Generic => "test")).is_err());
2721    }
2722
2723    #[test]
2724    fn string_or_else_test_good() {
2725        let input = SteelVal::StringV("foo".into());
2726        assert_eq!(
2727            input.string_or_else(throw!(Generic => "test")).unwrap(),
2728            "foo".to_string()
2729        );
2730    }
2731
2732    #[test]
2733    fn string_or_else_test_bad() {
2734        let input = SteelVal::Void;
2735        assert!(input.string_or_else(throw!(Generic => "test")).is_err())
2736    }
2737
2738    #[test]
2739    fn symbol_or_else_test_good() {
2740        let input = SteelVal::SymbolV("foo".into());
2741        assert_eq!(
2742            input.symbol_or_else(throw!(Generic => "test")).unwrap(),
2743            "foo".to_string()
2744        );
2745    }
2746
2747    #[test]
2748    fn symbol_or_else_test_bad() {
2749        let input = SteelVal::Void;
2750        assert!(input.symbol_or_else(throw!(Generic => "test")).is_err())
2751    }
2752
2753    #[test]
2754    fn num_and_char_are_not_ordered() {
2755        assert_eq!(SteelVal::IntV(0).partial_cmp(&SteelVal::CharV('0')), None);
2756        assert_eq!(SteelVal::NumV(0.0).partial_cmp(&SteelVal::CharV('0')), None);
2757        assert_eq!(
2758            SteelVal::BigNum(Gc::new(BigInt::default())).partial_cmp(&SteelVal::CharV('0')),
2759            None
2760        );
2761    }
2762
2763    #[test]
2764    fn number_cmp() {
2765        let less_cases = [
2766            (SteelVal::IntV(-10), SteelVal::IntV(1)),
2767            (
2768                SteelVal::IntV(-10),
2769                SteelVal::BigNum(Gc::new(BigInt::from(1))),
2770            ),
2771            (SteelVal::NumV(-10.0), SteelVal::IntV(1)),
2772            (SteelVal::IntV(-10), SteelVal::NumV(1.0)),
2773            (
2774                SteelVal::BigNum(Gc::new(BigInt::from(-10))),
2775                SteelVal::BigNum(Gc::new(BigInt::from(1))),
2776            ),
2777            (
2778                SteelVal::NumV(-10.0),
2779                SteelVal::BigNum(Gc::new(BigInt::from(1))),
2780            ),
2781        ];
2782        for (l, r) in less_cases {
2783            assert_eq!(l.partial_cmp(&r), Some(Ordering::Less));
2784            assert_eq!(r.partial_cmp(&l), Some(Ordering::Greater));
2785        }
2786        let equal_cases = [
2787            SteelVal::IntV(-10),
2788            SteelVal::NumV(-10.0),
2789            SteelVal::BigNum(Gc::new(BigInt::from(-10))),
2790            // Added to test that the number is equal even if it points to a different object.
2791            SteelVal::BigNum(Gc::new(BigInt::from(-10))),
2792        ]
2793        .into_iter();
2794        for (l, r) in equal_cases.clone().zip(equal_cases.clone()) {
2795            assert_eq!(l.partial_cmp(&r), Some(Ordering::Equal));
2796        }
2797    }
2798}