Remacs Types
Table of Contents
The struct ExternalPtr<T>
allows a more flexible usage of various lisp types.
#[repr(transparent)]
#[derive(Debug)]
pub struct ExternalPtr<T>(*mut T);
This way we can add methods to multiple Emacs types. For example, we implemented PartialEq
.
impl<T> PartialEq for ExternalPtr<T> {
fn eq(&self, other: &Self) -> bool {
self.as_ptr() == other.as_ptr()
}
}
We have introduced aliases for the resulting types that follow Rust naming conventions and are consisting
of the original type name + "Ref".
In case of Lisp_Buffer
the name of the type is LispBufferRef
.
pub type LispBufferRef = ExternalPtr<Lisp_Buffer>;
There are also additional types for some of those types in order to reduce boilerplate code.
Since buffers in elisp are often accessed by name, the type LispBufferOrName
is either a buffer's name
or the buffer itself.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum LispBufferOrName {
Buffer(LispObject),
Name(LispObject),
}
Before we introduced this type, the function get_buffer
looked like this:
#[lisp_fn]
pub fn get_buffer(buffer_or_name: LispObject) -> LispObject {
if buffer_or_name.is_buffer() {
buffer_or_name
} else {
buffer_or_name.as_string_or_error();
cdr(assoc_ignore_text_properties(buffer_or_name, unsafe {
Vbuffer_alist
}))
}
}
Now the lisp function takes a LispBufferOrName
which can be casted to Option<LispBufferRef>
by the method into()
.
#[lisp_fn]
pub fn get_buffer(buffer_or_name: LispBufferOrName) -> Option<LispBufferRef> {
buffer_or_name.into()
}
In many lisp functions a LispObject
can either be a Lisp_Buffer
or Qnil
. The type LispBufferOrCurrent
takes care of this case.
pub struct LispBufferOrCurrent(LispBufferRef);
This check can be seen in the former version of the function buffer_file_name
. When the argument is Qnil
, the buffer will be the current buffer. Otherwise the argument's type will be checked with as_buffer_or_error()
.
#[lisp_fn(min = "0")]
pub fn buffer_file_name(buffer: LispObject) -> LispObject {
let buf = if buffer.is_nil() {
ThreadState::current_buffer()
} else {
buffer.as_buffer_or_error()
};
buf.filename_
}
The updated function looks like this:
#[lisp_fn(min = "0")]
pub fn buffer_file_name(buffer: LispBufferOrCurrent) -> LispObject {
let buf = buffer.unwrap();
buf.filename_
}
pub struct LispWindowOrSelected(LispObject);
pub struct LispWindowLiveOrSelected(LispWindowRef);
pub struct LispWindowValidOrSelected(LispWindowRef);
#[derive(Clone, Copy)]
pub enum LispFrameOrSelected {
Frame(LispFrameRef),
Selected,
}
pub type LispMiscRef = ExternalPtr<Lisp_Misc_Any>;