steel/
rvals.rs

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