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) -> Result<Option<Self>, DynamicError>;
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) -> Result<Option<Self>, DynamicError> {
16 Ok(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) -> Result<Option<Self>, DynamicError> {
28 Ok(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) -> Result<Option<Self>, DynamicError> {
53 Ok(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) -> Result<Option<Self>, DynamicError> {
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 let Some(character) = char::from_u32(memory.car(cons)?.assume_number().to_i64() as _)
74 else {
75 return Ok(None);
76 };
77 string.push(character);
78 cons = memory.cdr(cons)?.assume_cons();
79 }
80
81 Ok(Some(string))
82 }
83
84 fn into_scheme(self, memory: &mut Memory) -> Result<Value, DynamicError> {
85 let mut length = 0;
86 let mut cons = memory.null()?;
87
88 for character in self.chars().rev() {
89 cons = memory.cons(Number::from_i64(character as _).into(), cons)?;
90 length += 1;
91 }
92
93 Ok(memory
94 .allocate(
95 Number::from_i64(length).into(),
96 cons.set_tag(Type::String as _).into(),
97 )?
98 .into())
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 mod string {
107 use super::*;
108
109 #[test]
110 fn ascii() {
111 let mut heap = [Default::default(); 256];
112 let mut memory = Memory::new(&mut heap).unwrap();
113 let string = "tomato";
114
115 let value = String::from(string).into_scheme(&mut memory).unwrap();
116
117 assert_eq!(
118 &String::from_scheme(&memory, value).unwrap().unwrap(),
119 string
120 );
121 }
122
123 #[test]
124 fn unicode() {
125 let mut heap = [Default::default(); 256];
126 let mut memory = Memory::new(&mut heap).unwrap();
127 let string = "γιΏπ";
128
129 let value = String::from(string).into_scheme(&mut memory).unwrap();
130
131 assert_eq!(
132 &String::from_scheme(&memory, value).unwrap().unwrap(),
133 string
134 );
135 }
136 }
137}