stak_dynamic/
scheme_value.rs1use super::DynamicError;
2use alloc::string::String;
3use stak_vm::{Memory, Number, Type, Value};
4
5pub trait SchemeValue: Sized {
7 fn from_scheme(memory: &Memory, value: Value) -> Option<Self>;
9
10 fn into_scheme(self, memory: &mut Memory) -> Result<Value, DynamicError>;
12}
13
14impl SchemeValue for bool {
15 fn from_scheme(memory: &Memory, value: Value) -> Option<Self> {
16 Some(value == memory.boolean(false).into())
17 }
18
19 fn into_scheme(self, memory: &mut Memory) -> Result<Value, DynamicError> {
20 Ok(memory.boolean(self).into())
21 }
22}
23
24macro_rules! implement_integer {
25 ($type:ty) => {
26 impl SchemeValue for $type {
27 fn from_scheme(_memory: &Memory, value: Value) -> Option<Self> {
28 Some(value.assume_number().to_i64() as _)
29 }
30
31 fn into_scheme(self, _memory: &mut Memory) -> Result<Value, DynamicError> {
32 Ok(Number::from_i64(self as _).into())
33 }
34 }
35 };
36}
37
38implement_integer!(i8);
39implement_integer!(u8);
40implement_integer!(u16);
41implement_integer!(i16);
42implement_integer!(i32);
43implement_integer!(u32);
44implement_integer!(i64);
45implement_integer!(u64);
46implement_integer!(isize);
47implement_integer!(usize);
48
49macro_rules! implement_float {
50 ($type:ty) => {
51 impl SchemeValue for $type {
52 fn from_scheme(_memory: &Memory, value: Value) -> Option<Self> {
53 Some(value.assume_number().to_f64() as _)
54 }
55
56 fn into_scheme(self, _memory: &mut Memory) -> Result<Value, DynamicError> {
57 Ok(Number::from_f64(self as _).into())
58 }
59 }
60 };
61}
62
63implement_float!(f32);
64implement_float!(f64);
65
66impl SchemeValue for String {
67 fn from_scheme(memory: &Memory, value: Value) -> Option<Self> {
68 let cons = value.assume_cons();
69 let mut string = Self::with_capacity(memory.car(cons).assume_number().to_i64() as _);
70 let mut cons = memory.cdr(cons).assume_cons();
71
72 while cons != memory.null() {
73 string.push(char::from_u32(
74 memory.car(cons).assume_number().to_i64() as _
75 )?);
76 cons = memory.cdr(cons).assume_cons();
77 }
78
79 Some(string)
80 }
81
82 fn into_scheme(self, memory: &mut Memory) -> Result<Value, DynamicError> {
83 let mut length = 0;
84 let mut cons = memory.null();
85
86 for character in self.chars().rev() {
87 cons = memory.cons(Number::from_i64(character as _).into(), cons)?;
88 length += 1;
89 }
90
91 Ok(memory
92 .allocate(
93 Number::from_i64(length).into(),
94 cons.set_tag(Type::String as _).into(),
95 )?
96 .into())
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 mod string {
105 use super::*;
106
107 #[test]
108 fn ascii() {
109 let mut heap = [Default::default(); 256];
110 let mut memory = Memory::new(&mut heap).unwrap();
111 let string = "tomato";
112
113 let value = String::from(string).into_scheme(&mut memory).unwrap();
114
115 assert_eq!(&String::from_scheme(&memory, value).unwrap(), string);
116 }
117
118 #[test]
119 fn unicode() {
120 let mut heap = [Default::default(); 256];
121 let mut memory = Memory::new(&mut heap).unwrap();
122 let string = "γιΏπ";
123
124 let value = String::from(string).into_scheme(&mut memory).unwrap();
125
126 assert_eq!(&String::from_scheme(&memory, value).unwrap(), string);
127 }
128 }
129}