emacs_native_async/
to_lisp.rs1use std::{
2 mem::{replace, take},
3 ptr::null_mut,
4 sync::{Arc, Mutex, RwLock},
5};
6
7use emacs::{Env, IntoLisp, Transfer, Value};
8use libc::c_void;
9
10pub struct ToLispConvert {
11 inner: ToLispConvertInner,
12}
13
14enum ToLispConvertInner {
15 Unit,
16 I64(i64),
17 ISize(isize),
18 U64(u64),
19 USize(usize),
20 Bool(bool),
21 F64(f64),
22 Str(&'static str),
23 String(String),
24 Ptr(Option<unsafe extern "C" fn(arg1: *mut c_void)>, *mut c_void),
25 Lazy(Option<Box<dyn Send + Sync + FnOnce(&Env) -> emacs::Result<Value> + Send + Sync>>),
26}
27
28unsafe impl Sync for ToLispConvertInner {}
29unsafe impl Send for ToLispConvertInner {}
30
31impl ToLispConvert {
32 pub fn to_value(mut self, env: &Env) -> emacs::Result<Value> {
33 match &mut self.inner {
34 ToLispConvertInner::Unit => ().into_lisp(env),
35 ToLispConvertInner::I64(v) => v.into_lisp(env),
36 ToLispConvertInner::ISize(v) => v.into_lisp(env),
37 ToLispConvertInner::U64(v) => v.into_lisp(env),
38 ToLispConvertInner::USize(v) => v.into_lisp(env),
39 ToLispConvertInner::Bool(v) => v.into_lisp(env),
40 ToLispConvertInner::F64(v) => v.into_lisp(env),
41 ToLispConvertInner::Str(v) => v.into_lisp(env),
42 ToLispConvertInner::String(v) => take(v).into_lisp(env),
43 ToLispConvertInner::Ptr(fin, val) => unsafe {
44 env.make_user_ptr(take(fin), replace(val, null_mut()))
45 },
46 ToLispConvertInner::Lazy(f) => match take(f) {
47 Some(f) => f(env),
48 None => Err(anyhow::anyhow!("empty value")),
49 },
50 }
51 }
52 pub fn lazy<F: Send + Sync + 'static + FnOnce(&Env) -> emacs::Result<Value> + Send + Sync>(
53 f: F,
54 ) -> ToLispConvert {
55 Self {
56 inner: ToLispConvertInner::Lazy(Some(Box::new(f))),
57 }
58 }
59}
60
61impl From<()> for ToLispConvert {
62 fn from(_: ()) -> Self {
63 Self {
64 inner: ToLispConvertInner::Unit,
65 }
66 }
67}
68impl From<i8> for ToLispConvert {
69 fn from(v: i8) -> Self {
70 ToLispConvert {
71 inner: ToLispConvertInner::I64(v.into()),
72 }
73 }
74}
75impl From<i16> for ToLispConvert {
76 fn from(v: i16) -> Self {
77 ToLispConvert {
78 inner: ToLispConvertInner::I64(v.into()),
79 }
80 }
81}
82impl From<i32> for ToLispConvert {
83 fn from(v: i32) -> Self {
84 ToLispConvert {
85 inner: ToLispConvertInner::I64(v.into()),
86 }
87 }
88}
89impl From<i64> for ToLispConvert {
90 fn from(v: i64) -> Self {
91 ToLispConvert {
92 inner: ToLispConvertInner::I64(v),
93 }
94 }
95}
96impl From<isize> for ToLispConvert {
97 fn from(v: isize) -> Self {
98 ToLispConvert {
99 inner: ToLispConvertInner::ISize(v),
100 }
101 }
102}
103impl From<u8> for ToLispConvert {
104 fn from(v: u8) -> Self {
105 ToLispConvert {
106 inner: ToLispConvertInner::U64(v.into()),
107 }
108 }
109}
110impl From<u16> for ToLispConvert {
111 fn from(v: u16) -> Self {
112 ToLispConvert {
113 inner: ToLispConvertInner::U64(v.into()),
114 }
115 }
116}
117impl From<u32> for ToLispConvert {
118 fn from(v: u32) -> Self {
119 ToLispConvert {
120 inner: ToLispConvertInner::U64(v.into()),
121 }
122 }
123}
124impl From<u64> for ToLispConvert {
125 fn from(v: u64) -> Self {
126 ToLispConvert {
127 inner: ToLispConvertInner::U64(v),
128 }
129 }
130}
131impl From<usize> for ToLispConvert {
132 fn from(v: usize) -> Self {
133 ToLispConvert {
134 inner: ToLispConvertInner::USize(v),
135 }
136 }
137}
138impl From<bool> for ToLispConvert {
139 fn from(v: bool) -> Self {
140 ToLispConvert {
141 inner: ToLispConvertInner::Bool(v),
142 }
143 }
144}
145impl From<f64> for ToLispConvert {
146 fn from(v: f64) -> Self {
147 ToLispConvert {
148 inner: ToLispConvertInner::F64(v),
149 }
150 }
151}
152impl From<&'static str> for ToLispConvert {
153 fn from(v: &'static str) -> Self {
154 ToLispConvert {
155 inner: ToLispConvertInner::Str(v),
156 }
157 }
158}
159impl From<String> for ToLispConvert {
160 fn from(v: String) -> Self {
161 ToLispConvert {
162 inner: ToLispConvertInner::String(v),
163 }
164 }
165}
166
167unsafe extern "C" fn finalize<T: Transfer>(ptr: *mut c_void) {
172 #[cfg(build = "debug")]
173 println!("Finalizing {:#?} {}", ptr, T::type_name());
174 drop(Box::from_raw(ptr as *mut T));
175}
176
177impl<T: Transfer + Send + Sync> From<Box<T>> for ToLispConvert {
178 fn from(v: Box<T>) -> Self {
179 ToLispConvert {
180 inner: ToLispConvertInner::Ptr(
181 Some(finalize::<T>),
182 std::boxed::Box::<T>::into_raw(v).cast(),
183 ),
184 }
185 }
186}
187
188impl<T: 'static+Send> From<Mutex<T>> for ToLispConvert {
189 fn from(v: Mutex<T>) -> Self {
190 Box::new(v).into()
191 }
192}
193impl<T: 'static+Send+Sync> From<RwLock<T>> for ToLispConvert {
194 fn from(v: RwLock<T>) -> Self {
195 Box::new(v).into()
196 }
197}
198impl<T: 'static+Send+Sync> From<Arc<T>> for ToLispConvert {
199 fn from(v: Arc<T>) -> Self {
200 Box::new(v).into()
201 }
202}
203
204impl<'e> IntoLisp<'e> for ToLispConvert {
205 fn into_lisp(self, env: &'e Env) -> emacs::Result<Value<'e>> {
206 self.to_value(env)
207 }
208}
209
210impl Drop for ToLispConvertInner {
211 fn drop(&mut self) {
212 match self {
213 &mut Self::Ptr(Some(fin), val) => unsafe { fin(val) },
214 _ => {}
215 }
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use super::ToLispConvert;
222
223 #[allow(unused)]
224 struct IsSendSync<T: Send + Sync + 'static> {
225 t: T,
226 }
227
228 #[allow(unused)]
229 fn test_is_send_sync(_: IsSendSync<ToLispConvert>) -> () {
230 return ();
231 }
232}