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
use std::convert::TryInto;

use super::*;
use crate::call::IntoLispArgs;

/// A type that represents Lisp vectors. This is a newtype wrapper around [`Value`] that provides
/// vector-specific methods.
///
/// Arguments to #[[`defun`]] having this type will be type-checked. This type checking can be
/// omitted by manually wrapping a [`Value`]. Note that Emacs still does type checking when calling
/// methods on the vector.
///
/// ```
/// use emacs::{defun, Value, Vector, Result};
///
/// #[defun]
/// fn must_pass_vector(vector: Vector) -> Result<Vector> {
///     Ok(vector)
/// }
///
/// #[defun]
/// fn no_type_check(value: Value) -> Result<Vector> {
///     Ok(Vector(value))
/// }
/// ```
///
/// [`Value`]: struct.Value.html
/// [`defun`]: /emacs-macros/*/emacs_macros/attr.defun.html
#[derive(Debug, Clone, Copy)]
pub struct Vector<'e>(pub Value<'e>);

impl<'e> Vector<'e> {
    pub fn get<T: FromLisp<'e>>(&self, i: usize) -> Result<T> {
        let v = self.0;
        let env = v.env;
        // Safety: Same lifetime. Emacs does bound checking.
        unsafe_raw_call_value!(env, vec_get, v.raw, i as isize)?.into_rust()
    }

    pub fn set<T: IntoLisp<'e>>(&self, i: usize, value: T) -> Result<()> {
        let v = self.0;
        let env = v.env;
        let value = value.into_lisp(env)?;
        // Safety: Same lifetime. Emacs does bound checking.
        unsafe_raw_call!(env, vec_set, v.raw, i as isize, value.raw)
    }

    pub fn size(&self) -> Result<usize> {
        let v = self.0;
        let env = v.env;
        let result =
            unsafe_raw_call_no_exit!(env, vec_size, v.raw).try_into().expect("invalid size from Emacs");
        env.handle_exit(result)
    }
}

impl<'a, 'e: 'a> FromLisp<'e> for Vector<'a> {
    fn from_lisp(value: Value<'e>) -> Result<Vector<'a>> {
        let vector = Vector(value);
        // TODO: Confirm that this is indeed cheaper than calling vectorp and signaling error.
        vector.size()?;
        Ok(vector)
    }
}

impl<'e> IntoLisp<'e> for Vector<'e> {
    #[inline(always)]
    fn into_lisp(self, _: &'e Env) -> Result<Value<'_>> {
        Ok(self.0)
    }
}

impl Env {
    pub fn make_vector<'e, T: IntoLisp<'e>>(&'e self, length: usize, init: T) -> Result<Vector> {
        self.call("make-vector", (length, init)).map(Vector)
    }

    pub fn vector<'e, A: IntoLispArgs<'e>>(&'e self, args: A) -> Result<Vector> {
        self.call("vector", args).map(Vector)
    }
}