1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use std::{
cell::RefCell,
ffi::CString,
mem::MaybeUninit,
};
use once_cell::sync::OnceCell;
use emacs_module::{emacs_env, emacs_runtime, emacs_value};
use crate::{subr, error, Value, Result, IntoLisp, call::IntoLispArgs, GlobalRef};
pub static HAS_FIXED_GC_BUG_31238: OnceCell<bool> = OnceCell::new();
#[derive(Debug)]
pub struct Env {
pub(crate) raw: *mut emacs_env,
pub(crate) protected: Option<RefCell<Vec<emacs_value>>>,
}
impl Env {
#[doc(hidden)]
pub unsafe fn new(raw: *mut emacs_env) -> Self {
let protected = if *HAS_FIXED_GC_BUG_31238.get().unwrap_or(&false) {
None
} else {
Some(RefCell::new(vec![]))
};
Self { raw, protected }
}
#[doc(hidden)]
pub unsafe fn from_runtime(runtime: *mut emacs_runtime) -> Self {
let get_env = (*runtime).get_environment.expect("Cannot get Emacs environment");
let raw = get_env(runtime);
Self::new(raw)
}
#[doc(hidden)]
pub fn raw(&self) -> *mut emacs_env {
self.raw
}
#[doc(hidden)]
pub unsafe fn free_last_protected(&self) -> Result<()>{
if let Some(protected) = &self.protected {
let gr = GlobalRef::from_raw(*protected.borrow().last().unwrap());
gr.free(self)?;
}
Ok(())
}
pub fn intern(&self, name: &str) -> Result<Value<'_>> {
unsafe_raw_call_value!(self, intern, CString::new(name)?.as_ptr())
}
pub fn type_of<'e>(&'e self, value: Value<'e>) -> Result<Value<'_>> {
unsafe_raw_call_value!(self, type_of, value.raw)
}
#[deprecated(since = "0.10.0", note = "Please use `value.is_not_nil()` instead")]
pub fn is_not_nil<'e>(&'e self, value: Value<'e>) -> bool {
unsafe_raw_call_no_exit!(self, is_not_nil, value.raw)
}
#[deprecated(since = "0.10.0", note = "Please use `value1.eq(value2)` instead")]
pub fn eq<'e>(&'e self, a: Value<'e>, b: Value<'e>) -> bool {
unsafe_raw_call_no_exit!(self, eq, a.raw, b.raw)
}
pub fn cons<'e, A, B>(&'e self, car: A, cdr: B) -> Result<Value<'_>> where A: IntoLisp<'e>, B: IntoLisp<'e> {
self.call(subr::cons, (car, cdr))
}
pub fn list<'e, A>(&'e self, args: A) -> Result<Value<'_>> where A: IntoLispArgs<'e> {
self.call(subr::list, args)
}
pub fn provide(&self, name: &str) -> Result<Value<'_>> {
let name = self.intern(name)?;
self.call("provide", [name])
}
pub fn message<T: AsRef<str>>(&self, text: T) -> Result<Value<'_>> {
self.call(subr::message, (text.as_ref(),))
}
}
impl Drop for Env {
fn drop(&mut self) {
if let Some(protected) = &self.protected {
#[cfg(build = "debug")]
println!("Unrooting {} values protected by {:?}", protected.borrow().len(), self);
let mut symbol = MaybeUninit::uninit();
let mut data = MaybeUninit::uninit();
let status = self.non_local_exit_get(&mut symbol, &mut data);
if status == error::SIGNAL || status == error::THROW {
self.non_local_exit_clear();
}
for raw in protected.borrow().iter() {
unsafe_raw_call_no_exit!(self, free_global_ref, *raw);
}
match status {
error::SIGNAL => unsafe { self.signal(symbol.assume_init(), data.assume_init()); }
error::THROW => unsafe { self.throw(symbol.assume_init(), data.assume_init()); }
_ => ()
}
}
}
}