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#[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#[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
129pub(crate) fn poll_future(mut fut: Shared<BoxedFutureResult>) -> Option<Result<SteelVal>> {
133 if let Some(output) = fut.peek() {
135 return Some(output.clone());
136 }
137
138 let waker = noop_waker_ref();
141 let context = &mut Context::from_waker(waker);
142
143 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
152pub 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 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 = 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
334impl<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 = 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
363pub trait IntoSteelVal: Sized {
369 fn into_steelval(self) -> Result<SteelVal>;
370}
371
372pub 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
470pub 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
487pub 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 } 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 } 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 match &value.syntax {
587 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 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 } _ => {}
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 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 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 pub fn to_exprkind(&self) -> Result<ExprKind> {
759 let span = self.span;
760 match &self.syntax {
762 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 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
830pub 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 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 pub values_to_fill_in: &'a mut std::collections::HashMap<usize, HeapRef<SteelVal>>,
876
877 pub built_functions: &'a mut std::collections::HashMap<u32, Gc<ByteCodeLambda>>,
879}
880
881pub 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 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 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 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 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 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
1019pub 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 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 SteelVal::HeapAllocated(h) => {
1089 if visited.contains(&h.as_ptr_usize())
1091 && !serialized_heap.contains_key(&h.as_ptr_usize())
1092 {
1093 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 Ok(SerializableSteelVal::HeapAllocated(h.as_ptr_usize()))
1103 } else {
1104 let value = into_serializable_value(h.get(), serialized_heap, visited);
1107
1108 let value = match value {
1109 Ok(v) => v,
1110 Err(e) => {
1111 return Err(e);
1113 }
1114 };
1115
1116 serialized_heap.insert(h.as_ptr_usize(), value);
1117
1118 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#[derive(Clone)]
1214pub enum SteelVal {
1215 Closure(Gc<ByteCodeLambda>),
1217 BoolV(bool),
1219 NumV(f64),
1221 IntV(isize),
1223 Rational(Rational32),
1225 CharV(char),
1227 VectorV(SteelVector),
1230 Void,
1232 StringV(SteelString),
1234 FuncV(FunctionSignature),
1236 SymbolV(SteelString),
1238 Custom(GcMut<Box<dyn CustomType>>), HashMapV(SteelHashMap),
1242 HashSetV(SteelHashSet),
1244 CustomStruct(Gc<UserDefinedStruct>),
1246 PortV(SteelPort),
1248 IterV(Gc<Transducer>),
1250 ReducerV(Gc<Reducer>),
1252 FutureFunc(BoxedAsyncFunctionSignature),
1254 FutureV(Gc<FutureResult>),
1256 StreamV(Gc<LazyStream>),
1258 BoxedFunction(Gc<BoxedDynFunction>),
1260 ContinuationFunction(Continuation),
1262 ListV(crate::values::lists::List<SteelVal>),
1267 Pair(Gc<crate::values::lists::Pair>),
1269 MutFunc(MutFunctionSignature),
1271 BuiltIn(BuiltInSignature),
1273 MutableVector(HeapRef<Vec<SteelVal>>),
1275 BoxedIterator(GcMut<OpaqueIterator>),
1278 SyntaxObject(Gc<Syntax>),
1280 Boxed(GcMut<SteelVal>),
1283 HeapAllocated(HeapRef<SteelVal>),
1285 Reference(Gc<OpaqueReference<'static>>),
1287 BigNum(Gc<BigInt>),
1289 BigRational(Gc<BigRational>),
1291 Complex(Gc<SteelComplex>),
1293 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#[derive(Clone, Debug, Hash, PartialEq)]
1339pub struct SteelComplex {
1340 pub re: SteelVal,
1342 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 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 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 CustomStruct(c) => Some(c.as_ptr() as usize),
1444 ListV(l) => Some(l.as_ptr_usize()),
1453 HeapAllocated(h) => Some(h.as_ptr_usize()),
1460 _ => None,
1463 }
1464 }
1465
1466 }
1479
1480#[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
1646const _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
1677pub 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 (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 | 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 | BuiltIn(_)
1876 | MutFunc(_)
1877 )
1878 }
1879
1880 pub fn empty_hashmap() -> SteelVal {
1885 SteelVal::HashMapV(Gc::new(HashMap::new()).into())
1886 }
1887}
1888
1889impl SteelVal {
1890 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 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 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 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 (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 match (self, other) {
2172 (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 (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 #[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(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 (Rational(x), IntV(y)) => {
2240 #[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 (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 (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 debug_assert!(
2325 !(realp(l) && realp(r)),
2326 "Numbers {l:?} and {r:?} should implement partial_cmp"
2327 );
2328 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 match self {
2346 SymbolV(_) | ListV(_) | VectorV(_) => write!(f, "'")?,
2347 _ => (),
2348 };
2349 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 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}