use std::cell::{RefCell, Ref, RefMut};
use std::ffi::CString;
use std::convert::TryInto;
#[doc(inline)]
pub use emacs_macros::{defun, module};
use raw::*;
#[doc(no_inline)]
pub use failure::{self, Error};
#[doc(inline)]
pub use self::error::{ErrorKind, Result, ResultExt};
#[macro_use]
mod macros;
mod convert;
#[doc(hidden)]
pub mod error;
#[doc(hidden)]
pub mod func;
#[doc(hidden)]
pub mod globals;
#[doc(hidden)]
pub mod raw {
pub use emacs_module::{emacs_env, emacs_runtime, emacs_value};
}
#[doc(hidden)]
pub mod deps {
pub use ctor;
pub use lazy_static;
}
#[derive(Debug)]
pub struct Env {
pub(crate) raw: *mut emacs_env,
pub(crate) protected: RefCell<Vec<emacs_value>>,
}
#[doc(hidden)]
#[derive(Debug)]
pub struct CallEnv {
env: Env,
nargs: usize,
args: *mut emacs_value,
}
#[derive(Debug, Clone, Copy)]
pub struct Value<'e> {
pub(crate) raw: emacs_value,
pub env: &'e Env,
}
pub trait FromLisp<'e>: Sized {
fn from_lisp(value: Value<'e>) -> Result<Self>;
}
pub trait IntoLisp<'e> {
fn into_lisp(self, env: &'e Env) -> Result<Value<'e>>;
}
pub trait Transfer: Sized + 'static {
fn type_name() -> &'static str;
}
impl Env {
#[doc(hidden)]
pub unsafe fn new(raw: *mut emacs_env) -> Self {
let protected = 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
}
pub fn intern(&self, name: &str) -> Result<Value<'_>> {
raw_call_value!(self, intern, CString::new(name)?.as_ptr())
}
pub fn type_of(&self, value: Value<'_>) -> Result<Value<'_>> {
raw_call_value!(self, type_of, value.raw)
}
pub fn call(&self, name: &str, args: &[Value<'_>]) -> Result<Value<'_>> {
let symbol = self.intern(name)?;
let mut args: Vec<emacs_value> = args.iter().map(|v| v.raw).collect();
raw_call_value!(self, funcall, symbol.raw, args.len() as isize, args.as_mut_ptr())
}
#[deprecated(since = "0.10.0", note = "Please use `value.is_not_nil()` instead")]
pub fn is_not_nil(&self, value: Value<'_>) -> bool {
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(&self, a: Value<'_>, b: Value<'_>) -> bool {
raw_call_no_exit!(self, eq, a.raw, b.raw)
}
pub fn list(&self, args: &[Value<'_>]) -> Result<Value<'_>> {
self.call("list", args)
}
pub fn provide(&self, name: &str) -> Result<Value<'_>> {
let name = self.intern(name)?;
call_lisp!(self, "provide", name)
}
pub fn message<T: AsRef<str>>(&self, text: T) -> Result<Value<'_>> {
call_lisp!(self, "message", text.as_ref())
}
}
impl Drop for Env {
fn drop(&mut self) {
#[cfg(build = "debug")]
println!("Unrooting {} values protected by {:?}", self.protected.borrow().len(), self);
for raw in self.protected.borrow().iter() {
raw_call_no_exit!(self, free_global_ref, *raw);
}
}
}
impl<'e> Value<'e> {
#[doc(hidden)]
pub unsafe fn new(raw: emacs_value, env: &'e Env) -> Self {
Self { raw, env }
}
#[allow(unused_unsafe)]
#[doc(hidden)]
pub unsafe fn new_protected(raw: emacs_value, env: &'e Env) -> Self {
env.protected.borrow_mut().push(raw_call_no_exit!(env, make_global_ref, raw));
Self::new(raw, env)
}
pub fn is_not_nil(&self) -> bool {
let env = self.env;
raw_call_no_exit!(env, is_not_nil, self.raw)
}
#[allow(clippy::should_implement_trait)]
pub fn eq(&self, other: Value<'e>) -> bool {
let env = self.env;
raw_call_no_exit!(env, eq, self.raw, other.raw)
}
#[inline]
pub fn into_rust<T: FromLisp<'e>>(self) -> Result<T> {
FromLisp::from_lisp(self)
}
#[inline]
pub fn into_ref<T: 'static>(self) -> Result<Ref<'e, T>> {
let container: &RefCell<T> = self.into_rust()?;
Ok(container.try_borrow()?)
}
#[inline]
pub fn into_ref_mut<T: 'static>(self) -> Result<RefMut<'e, T>> {
let container: &RefCell<T> = self.into_rust()?;
Ok(container.try_borrow_mut()?)
}
pub unsafe fn get_mut<T: Transfer>(&mut self) -> Result<&mut T> {
self.env.get_raw_pointer(self.raw).map(|r| &mut *r)
}
}
#[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;
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)?;
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 = raw_call_no_exit!(env, vec_size, v.raw).try_into().expect("invalid size from Emacs");
env.handle_exit(result)
}
}