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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
use std::borrow::BorrowMut;

use emacs_module::emacs_value;
use emacs_macros;

use crate::{Env, Value, Result, IntoLisp, global::{GlobalRef, OnceGlobalRef}};

// TODO: Seal this trait, for safety reasons.
pub unsafe trait IntoLispArgs<'e> {
    type LispArgs: BorrowMut<[emacs_value]>;

    fn into_lisp_args(self, env: &'e Env) -> Result<Self::LispArgs>;
}

impl<'e> Value<'e> {
    /// Calls this value with the given arguments. An error is signaled if it is actually not a
    /// Lisp's callable.
    ///
    /// `args` should be an array/slice of `Value`, or a tuple of different types, each implementing
    /// [`IntoLisp`].
    ///
    /// # Examples
    ///
    /// ```
    /// # use emacs::{defun, Value, Result, Vector};
    /// #[defun]
    /// fn mapc_enumerate_vec(function: Value, vector: Vector) -> Result<()> {
    ///     for (nth, elem) in vector.into_iter().enumerate() {
    ///         function.call((nth, elem))?;
    ///     }
    ///     Ok(())
    /// }
    /// ```
    ///
    /// [`IntoLisp`]: trait.IntoLisp.html
    #[inline]
    pub fn call<A>(self, args: A) -> Result<Value<'e>> where A: IntoLispArgs<'e> {
        // Safety: The returned value is explicitly protected.
        unsafe { self.call_unprotected(args).map(|v| v.protect()) }
    }

    /// Like [`call`], except that the returned `Value` is not protected against
    /// Emacs GC's [bug #31238], which caused [issue #2].
    ///
    /// # Safety
    ///
    /// This can be used as an optimization, in situations when the returned `Value` is unused,
    /// or when its usage is shorter than the lifespan of the underlying Lisp object.
    ///
    /// [`call`]: #method.call
    /// [bug #31238]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31238
    /// [issue #2]: https://github.com/ubolonton/emacs-module-rs/issues/2
    #[allow(unused_unsafe)]
    pub unsafe fn call_unprotected<A>(self, args: A) -> Result<Value<'e>> where A: IntoLispArgs<'e> {
        let env = self.env;
        let mut lisp_args = args.into_lisp_args(env)?;
        let lisp_args: &mut [emacs_value] = lisp_args.borrow_mut();
        let ptr = lisp_args.as_mut_ptr();
        let length = lisp_args.len() as isize;
        // Safety:
        // - ptr comes from a locally-owned value.
        // - length is ensured to be valid by IntoLispArgs implementation.
        unsafe_raw_call_value_unprotected!(env, funcall, self.raw, length, ptr)
    }
}

pub trait IntoLispCallable<'e> {
    fn into_lisp_callable(self, env: &'e Env) -> Result<Value<'e>>;
}

impl Env {
    /// Calls a Lisp function, passing the given arguments.
    ///
    /// - `func` should be a string, or a Lisp's callable [`Value`] (in which case [`func.call`]
    /// is preferable). An error is signaled otherwise.
    /// - `args` should be an array/slice of [`Value`], or a tuple of different types, each
    /// implementing [`IntoLisp`].
    ///
    /// # Examples
    ///
    /// ```
    /// # use emacs::{defun, Value, Result, Vector};
    /// #[defun]
    /// fn listify_vec(vector: Vector) -> Result<Value> {
    ///     let env = vector.value().env;
    ///     let mut args = vec![];
    ///     for elem in vector {
    ///         args.push(elem)
    ///     }
    ///     env.call("list", &args)
    /// }
    /// ```
    ///
    /// [`Value`]: struct.Value.html
    /// [`func.call`]: struct.Value.html#method.call
    /// [`IntoLisp`]: trait.IntoLisp.html
    #[inline]
    pub fn call<'e, F, A>(&'e self, func: F, args: A) -> Result<Value<'_>>
        where
            F: IntoLispCallable<'e>,
            A: IntoLispArgs<'e>,
    {
        func.into_lisp_callable(self)?.call(args)
    }

    /// Like [`call`], except that the returned [`Value`] is not protected against
    /// Emacs GC's [bug #31238], which caused [issue #2].
    ///
    /// # Safety
    ///
    /// This can be used as an optimization, in situations when the returned [`Value`] is unused,
    /// or when its usage is shorter than the lifespan of the underlying Lisp object.
    ///
    /// [`call`]: #method.call
    /// [`Value`]: struct.Value.html
    /// [bug #31238]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31238
    /// [issue #2]: https://github.com/ubolonton/emacs-module-rs/issues/2
    #[inline]
    pub unsafe fn call_unprotected<'e, F, A>(&'e self, func: F, args: A) -> Result<Value<'_>>
        where
            F: IntoLispCallable<'e>,
            A: IntoLispArgs<'e>,
    {
        func.into_lisp_callable(self)?.call_unprotected(args)
    }
}

impl GlobalRef {
    /// Calls this reference's value with the given arguments. An error is signaled if it is
    /// actually not a Lisp's callable.
    ///
    /// `args` should be an array/slice of `Value`, or a tuple of different types, each implementing
    /// [`IntoLisp`].
    ///
    /// [`IntoLisp`]: trait.IntoLisp.html
    #[inline]
    pub fn call<'e, A>(&'e self, env: &'e Env, args: A) -> Result<Value<'_>>
        where
            A: IntoLispArgs<'e>,
    {
        self.bind(env).call(args)
    }

    /// Like [`call`], except that the returned [`Value`] is not protected against
    /// Emacs GC's [bug #31238], which caused [issue #2].
    ///
    /// # Safety
    ///
    /// This can be used as an optimization, in situations when the returned [`Value`] is unused,
    /// or when its usage is shorter than the lifespan of the underlying Lisp object.
    ///
    /// [`call`]: #method.call
    /// [`Value`]: struct.Value.html
    /// [bug #31238]: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31238
    /// [issue #2]: https://github.com/ubolonton/emacs-module-rs/issues/2
    #[inline]
    pub unsafe fn call_unprotected<'e, A>(&'e self, env: &'e Env, args: A) -> Result<Value<'_>>
        where
            A: IntoLispArgs<'e>,
    {
        self.bind(env).call_unprotected(args)
    }
}

// We can implement IntoLispArgs for IntoLisp types (after breaking up this implementation).
// However, that would prevent implementing IntoLisp for arrays and tuples. It is a choice between
// the convenience of not having to use (,) when calling functions with 1 argument, and the
// convenience of not having to use .into_lisp(env)? when returning an array/tuple from a #[defun].
// TODO: Check again when specialization lands: https://github.com/rust-lang/rust/issues/31844.
unsafe impl<'e, T: AsRef<[Value<'e>]> + ?Sized> IntoLispArgs<'e> for &T {
    type LispArgs = Vec<emacs_value>;

    fn into_lisp_args(self, _: &'e Env) -> Result<Self::LispArgs> {
        Ok(self.as_ref().iter().map(|v| v.raw).collect())
    }
}

emacs_macros::impl_lisp_args_for_tuples!(12);

emacs_macros::impl_lisp_args_for_arrays!(12);

impl<'e> IntoLispCallable<'e> for Value<'e> {
    #[inline(always)]
    fn into_lisp_callable(self, _: &'e Env) -> Result<Value<'e>> {
        Ok(self)
    }
}

impl<'e, T: AsRef<str>> IntoLispCallable<'e> for T {
    #[inline(always)]
    fn into_lisp_callable(self, env: &'e Env) -> Result<Value<'e>> {
        env.intern(self.as_ref())
    }
}

impl<'e> IntoLispCallable<'e> for &'e GlobalRef {
    #[inline(always)]
    fn into_lisp_callable(self, env: &'e Env) -> Result<Value<'e>> {
        self.bind(env).into_lisp_callable(env)
    }
}

impl<'e> IntoLispCallable<'e> for &'e OnceGlobalRef {
    #[inline(always)]
    fn into_lisp_callable(self, env: &'e Env) -> Result<Value<'e>> {
        self.bind(env).into_lisp_callable(env)
    }
}