1use crate::r8vm::R8VM;
4use crate::nkgc::{PV, SPV, Arena, ObjRef};
5use crate::error::{Error, ErrorKind};
6use crate::{nuke::*, SymID};
7use crate::fmt::{LispFmt, VisitSet};
8use std::convert::{TryInto, TryFrom};
9use std::fmt;
10
11pub trait FromLisp<T>: Sized {
14 #[allow(clippy::wrong_self_convention)]
15 fn from_lisp(self, mem: &mut Arena) -> Result<T, Error>;
16}
17
18pub trait IntoLisp: Sized {
21 fn into_spv(self, mem: &mut Arena) -> Result<SPV, Error> {
22 let pv = self.into_pv(mem)?;
23 Ok(mem.make_extref(pv))
24 }
25
26 fn into_pv(self, mem: &mut Arena) -> Result<PV, Error>;
27}
28
29pub trait RefIntoLisp {
30 fn ref_into_spv(&self, mem: &mut Arena) -> Result<SPV, Error> {
31 let pv = self.ref_into_pv(mem)?;
32 Ok(mem.make_extref(pv))
33 }
34
35 fn ref_into_pv(&self, mem: &mut Arena) -> Result<PV, Error>;
36}
37
38impl<T> RefIntoLisp for T
39 where T: IntoLisp + Clone
40{
41 fn ref_into_pv(&self, mem: &mut Arena) -> Result<PV, Error> {
42 self.clone().into_pv(mem)
43 }
44}
45
46macro_rules! pv_convert {
47 ($pvt:ident, $($from_t:ty),*) => {
48 $(impl IntoLisp for $from_t {
49 fn into_pv(self, _: &mut Arena) -> Result<PV, Error> {
50 Ok(PV::$pvt(self.try_into()?))
51 }
52 })*
53 $(impl TryFrom<PV> for $from_t {
54 type Error = Error;
55 fn try_from(v: PV) -> Result<$from_t, Self::Error> {
56 if let PV::$pvt(x) = v {
57 Ok(x.try_into()?)
58 } else {
59 Err(Error::new(ErrorKind::TypeError {
60 expect: PV::$pvt(Default::default()).bt_type_of(),
61 got: v.bt_type_of(),
62 }))
63 }
64 }
65 }
66 impl TryFrom<PV> for ObjRef<$from_t> {
67 type Error = Error;
68 #[inline(always)]
69 fn try_from(v: PV) -> Result<ObjRef<$from_t>, Self::Error> {
70 Ok(ObjRef(v.try_into()?))
71 }
72 })*
73 };
74}
75
76pv_convert!(Int,
77 i8, u8,
78 i16, u16,
79 i32, u32,
80 i64, u64,
81 i128, u128,
82 isize, usize);
83
84pv_convert!(Real,
85 f32);
86
87pv_convert!(Char,
88 char);
89
90impl IntoLisp for () {
91 fn into_pv(self, _: &mut Arena) -> Result<PV, Error> {
92 Ok(PV::Nil)
93 }
94}
95
96impl TryFrom<PV> for () {
97 type Error = Error;
98 fn try_from(v: PV) -> Result<(), Self::Error> {
99 if let PV::Nil = v {
100 Ok(())
101 } else {
102 Err(Error::new(ErrorKind::TypeError {
103 expect: PV::Nil.bt_type_of(),
104 got: v.bt_type_of(),
105 }))
106 }
107 }
108}
109
110pub struct Ignore;
122
123impl IntoLisp for Ignore {
124 fn into_pv(self, _: &mut Arena) -> Result<PV, Error> {
125 Ok(PV::Nil)
126 }
127}
128
129impl TryFrom<PV> for Ignore {
130 type Error = Error;
131 fn try_from(_v: PV) -> Result<Ignore, Self::Error> {
132 Ok(Ignore)
133 }
134}
135
136impl IntoLisp for bool {
137 fn into_pv(self, _: &mut Arena) -> Result<PV, Error> {
138 Ok(PV::Bool(self))
139 }
140}
141
142impl IntoLisp for &str {
143 fn into_pv(self, mem: &mut Arena) -> Result<PV, Error> {
144 Ok(mem.put_pv(self.to_string()))
145 }
146}
147
148impl IntoLisp for String {
149 fn into_pv(self, mem: &mut Arena) -> Result<PV, Error> {
150 Ok(mem.put_pv(self))
151 }
152}
153
154impl IntoLisp for SymID {
155 fn into_pv(self, _mem: &mut Arena) -> Result<PV, Error> {
156 Ok(PV::Sym(self))
157 }
158}
159
160impl<T> IntoLisp for Vec<T>
161 where T: IntoLisp
162{
163 fn into_pv(self, mem: &mut Arena) -> Result<PV, Error> {
164 let arr = self.into_iter()
165 .map(|v| v.into_pv(mem))
166 .collect::<Result<Vec<PV>, _>>()?;
167 Ok(mem.put_pv(arr))
168 }
169}
170
171impl<T> TryFrom<PV> for Vec<T>
172 where T: TryFrom<PV, Error=Error>
173{
174 type Error = Error;
175 fn try_from(v: PV) -> Result<Vec<T>, Self::Error> {
176 with_ref!(v, Vector(v) => {
177 (*v).iter().map(|&x| x.try_into())
178 .collect::<Result<_, _>>()
179 })
180 }
181}
182
183impl<'a> TryFrom<PV> for &'a str {
187 type Error = Error;
188 fn try_from(v: PV) -> Result<&'a str, Self::Error> {
189 with_ref!(v, String(s) => { Ok(&*s) })
190 }
191}
192
193impl<T, E> IntoLisp for Result<T, E>
194 where T: IntoLisp, E: Into<Error>
195{
196 fn into_pv(self, mem: &mut Arena) -> Result<PV, Error> {
197 match self {
198 Ok(v) => v.into_pv(mem),
199 Err(e) => Err(e.into()),
200 }
201 }
202}
203
204#[cfg(not(feature = "freeze"))]
213pub unsafe trait Subr: CloneSubr + Send + 'static {
214 fn call(&mut self, vm: &mut R8VM, args: &[PV]) -> Result<PV, Error>;
215 fn name(&self) -> &'static str;
216}
217#[cfg(feature = "freeze")]
218pub unsafe trait Subr: CloneSubr + Send + 'static {
219 fn call(&mut self, vm: &mut R8VM, args: &[PV]) -> Result<PV, Error>;
220 fn name(&self) -> &'static str;
221}
222
223pub trait IntoSubr: Subr {
224 fn into_subr(self) -> Box<dyn Subr>;
225}
226
227impl<T> IntoSubr for T where T: Subr + Sized + 'static {
228 fn into_subr(self) -> Box<dyn Subr> {
229 Box::new(self)
230 }
231}
232
233impl fmt::Debug for Box<dyn Subr> {
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
235 write!(f, "(subr {})", self.name())
236 }
237}
238
239impl LispFmt for Box<dyn Subr> {
240 fn lisp_fmt(&self,
241 _: &mut VisitSet,
242 f: &mut fmt::Formatter<'_>) -> fmt::Result {
243 write!(f, "(subr {})", self.name())
244 }
245}
246
247pub trait CloneSubr {
248 fn clone_subr(&self) -> Box<dyn Subr>;
249}
250
251impl<T> CloneSubr for T
252 where T: Subr + Clone + 'static
253{
254 fn clone_subr(&self) -> Box<dyn Subr> {
255 Box::new(self.clone())
256 }
257}
258
259impl Clone for Box<dyn Subr> {
260 fn clone(&self) -> Box<dyn Subr> {
261 self.clone_subr()
262 }
263}
264
265impl IntoLisp for Box<dyn Subr> {
266 fn into_pv(self, mem: &mut Arena) -> Result<PV, Error> {
267 let p = mem.put(self);
268 Ok(NkAtom::make_ref(p))
269 }
270}