Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bringing over some hash-table related functions to remacs. #251

Merged
merged 17 commits into from
Jul 29, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 39 additions & 5 deletions rust_src/remacs-sys/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ extern crate libc;

pub mod libm;

use std::isize;
use libc::{c_char, c_uchar, c_short, c_int, c_double, c_void, ptrdiff_t, size_t, off_t, time_t,
timespec};
use libc::{c_char, c_uchar, c_short, c_int, c_double, c_float, c_void, ptrdiff_t, size_t, off_t,
time_t, timespec};


include!(concat!(env!("OUT_DIR"), "/definitions.rs"));

Expand Down Expand Up @@ -94,7 +94,7 @@ pub enum Lisp_Type {
Lisp_Float = 7,
}

#[repr(isize)]
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still need to look into why we were repr(isize) here, and if we need to switch over to repr(C) now that we are invoking a C function with this enum.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on discussions in other threads, I believe that changing this to repr(C) is the right call.

#[repr(C)]
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum PseudovecType {
PVEC_NORMAL_VECTOR = 0,
Expand Down Expand Up @@ -135,7 +135,6 @@ pub enum TextCursorKinds {
HBAR_CURSOR,
}

// XXX: this can also be char on some archs
pub type bits_word = size_t;

/// Representation of an Emacs Lisp function symbol.
Expand Down Expand Up @@ -1205,6 +1204,32 @@ pub struct emacs_globals {
pub f_x_use_underline_position_properties: bool,
}

#[repr(C)]
pub struct hash_table_test {
pub name: Lisp_Object,
pub user_hash_function: Lisp_Object,
pub user_cmp_function: Lisp_Object,
pub cmpfn: extern "C" fn(t: *mut hash_table_test, a: Lisp_Object, b: Lisp_Object) -> bool,
pub hashfn: extern "C" fn(t: *mut hash_table_test, a: Lisp_Object) -> EmacsUint,
}

#[repr(C)]
pub struct Lisp_Hash_Table {
pub header: Lisp_Vectorlike_Header,
pub weak: Lisp_Object,
pub hash: Lisp_Object,
pub next: Lisp_Object,
pub index: Lisp_Object,
pub count: ptrdiff_t,
pub next_free: ptrdiff_t,
pub pure_: bool, // pure is a reserved keyword in Rust
pub rehash_threshold: c_float,
pub rehash_size: c_float,
pub key_and_value: Lisp_Object,
pub test: hash_table_test,
pub next_weak: *mut Lisp_Hash_Table,
}

extern "C" {
pub static mut globals: emacs_globals;
pub static current_thread: *mut thread_state;
Expand Down Expand Up @@ -1256,6 +1281,7 @@ extern "C" {
pub static Qfont_spec: Lisp_Object;
pub static Qfont_entity: Lisp_Object;
pub static Qfont_object: Lisp_Object;
pub static Qhash_table_p: Lisp_Object;
pub static Qwrite_region: Lisp_Object;
pub static Qbuffer_file_coding_system: Lisp_Object;
pub static Qfont_extra_type: Lisp_Object;
Expand All @@ -1277,6 +1303,7 @@ extern "C" {
pub fn Fcons(car: Lisp_Object, cdr: Lisp_Object) -> Lisp_Object;
pub fn Fcurrent_buffer() -> Lisp_Object;
pub fn Fsignal(error_symbol: Lisp_Object, data: Lisp_Object) -> !;
pub fn Fcopy_sequence(seq: Lisp_Object) -> Lisp_Object;
pub fn Fbuffer_file_name(buffer: Lisp_Object) -> Lisp_Object;
pub fn Ffind_operation_coding_system(nargs: ptrdiff_t, args: *mut Lisp_Object) -> Lisp_Object;
pub fn Flocal_variable_p(variable: Lisp_Object, buffer: Lisp_Object) -> Lisp_Object;
Expand Down Expand Up @@ -1358,6 +1385,13 @@ extern "C" {
multibyte: bool,
nchars_return: *mut ptrdiff_t,
) -> ptrdiff_t;

pub fn allocate_pseudovector(
vecsize: c_int,
offset1: c_int,
offset2: c_int,
pvec_type: PseudovecType,
) -> *mut Lisp_Vector;
}

/// Contains C definitions from the font.h header.
Expand Down
90 changes: 90 additions & 0 deletions rust_src/src/hashtable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use remacs_macros::lisp_fn;
use lisp::{LispObject, ExternalPtr};
use remacs_sys::{Lisp_Hash_Table, PseudovecType, Fcopy_sequence};
use std::ptr;

pub type LispHashTableRef = ExternalPtr<Lisp_Hash_Table>;

impl LispHashTableRef {
pub fn allocate() -> LispHashTableRef {
let vec_ptr =
allocate_pseudovector!(Lisp_Hash_Table, count, PseudovecType::PVEC_HASH_TABLE);
LispHashTableRef::new(vec_ptr)
}

pub unsafe fn copy(&mut self, other: LispHashTableRef) {
ptr::copy_nonoverlapping(other.as_ptr(), self.as_mut(), 1);
}

pub fn set_next_weak(&mut self, other: LispHashTableRef) {
self.next_weak = other.as_ptr() as *mut Lisp_Hash_Table;
}

pub fn get_next_weak(&self) -> LispHashTableRef {
LispHashTableRef::new(self.next_weak)
}

pub fn set_hash(&mut self, hash: LispObject) {
self.hash = hash.to_raw();
}

pub fn get_hash(&self) -> LispObject {
LispObject::from_raw(self.hash)
}

pub fn set_next(&mut self, next: LispObject) {
self.next = next.to_raw();
}

pub fn get_next(&self) -> LispObject {
LispObject::from_raw(self.next)
}

pub fn set_index(&mut self, index: LispObject) {
self.index = index.to_raw();
}

pub fn get_index(&self) -> LispObject {
LispObject::from_raw(self.index)
}

pub fn get_key_and_value(&self) -> LispObject {
LispObject::from_raw(self.key_and_value)
}

pub fn set_key_and_value(&mut self, key_and_value: LispObject) {
self.key_and_value = key_and_value.to_raw();
}

pub fn get_weak(&self) -> LispObject {
LispObject::from_raw(self.weak)
}
}

/// Return a copy of hash table TABLE.
/// Keys and values are not copied, only the table itself is.
#[lisp_fn]
fn copy_hash_table(htable: LispObject) -> LispObject {
let mut table = htable.as_hash_table_or_error();
let mut new_table = LispHashTableRef::allocate();
unsafe { new_table.copy(table) };
assert!(new_table.as_ptr() != table.as_ptr());

let key_and_value = LispObject::from_raw(unsafe {
Fcopy_sequence(new_table.get_key_and_value().to_raw())
});
let hash = LispObject::from_raw(unsafe { Fcopy_sequence(new_table.get_hash().to_raw()) });
let next = LispObject::from_raw(unsafe { Fcopy_sequence(new_table.get_next().to_raw()) });
let index = LispObject::from_raw(unsafe { Fcopy_sequence(new_table.get_index().to_raw()) });
new_table.set_key_and_value(key_and_value);
new_table.set_hash(hash);
new_table.set_next(next);
new_table.set_index(index);

if new_table.get_weak().is_not_nil() {
new_table.set_next_weak(table.get_next_weak());
table.set_next_weak(new_table);
}

LispObject::from_hash_table(new_table)
}
3 changes: 3 additions & 0 deletions rust_src/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ mod numbers;
mod objects;
mod strings;
mod symbols;
#[macro_use]
mod vectors;
mod character;
mod base64;
Expand All @@ -41,6 +42,7 @@ mod str2sig;
mod multibyte;
mod buffers;
mod windows;
mod hashtable;
mod interactive;
mod process;
mod fonts;
Expand Down Expand Up @@ -244,6 +246,7 @@ pub extern "C" fn rust_init_syms() {
defsubr(&*vectors::Svector_or_char_table_p);
defsubr(&*vectors::Svectorp);
defsubr(&*vectors::Slength);
defsubr(&*hashtable::Scopy_hash_table);
defsubr(&*fonts::Sfontp);
defsubr(&*crypto::Smd5);
defsubr(&*crypto::Ssecure_hash);
Expand Down
56 changes: 54 additions & 2 deletions rust_src/src/lisp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,24 @@ use std::mem;
use std::slice;
use std::ops::{Deref, DerefMut};
use std::fmt::{Debug, Formatter, Error};
use libc::{c_void, intptr_t};
use libc::{c_void, intptr_t, uintptr_t};

use multibyte::{Codepoint, LispStringRef, MAX_CHAR};
use symbols::LispSymbolRef;
use vectors::LispVectorlikeRef;
use buffers::LispBufferRef;
use windows::LispWindowRef;
use marker::LispMarkerRef;
use hashtable::LispHashTableRef;
use fonts::LispFontRef;

use remacs_sys::{EmacsInt, EmacsUint, EmacsDouble, VALMASK, VALBITS, INTTYPEBITS, INTMASK,
USE_LSB_TAG, MOST_POSITIVE_FIXNUM, MOST_NEGATIVE_FIXNUM, Lisp_Type,
Lisp_Misc_Any, Lisp_Misc_Type, Lisp_Float, Lisp_Cons, Lisp_Object, lispsym,
make_float, circular_list, internal_equal, Fcons, CHECK_IMPURE, Qnil, Qt,
Qnumberp, Qfloatp, Qstringp, Qsymbolp, Qnumber_or_marker_p, Qwholenump, Qvectorp,
Qcharacterp, Qlistp, Qintegerp, Qconsp, SYMBOL_NAME, PseudovecType, EqualKind};
Qcharacterp, Qlistp, Qintegerp, Qhash_table_p, Qconsp, SYMBOL_NAME,
PseudovecType, EqualKind};

// TODO: tweak Makefile to rebuild C files if this changes.

Expand Down Expand Up @@ -96,6 +98,22 @@ impl LispObject {
unsafe { mem::transmute(res) }
}

pub fn tag_ptr<T>(external: ExternalPtr<T>, ty: Lisp_Type) -> LispObject {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Handy!

let raw = external.as_ptr() as intptr_t;
let res;
if USE_LSB_TAG {
let ptr = raw as intptr_t;
let tag = ty as intptr_t;
res = (ptr + tag) as EmacsInt;
} else {
let ptr = raw as EmacsUint as uintptr_t;
let tag = ty as EmacsUint as uintptr_t;
res = ((tag << VALBITS) + ptr) as EmacsInt;
}

LispObject::from_raw(res)
}

#[inline]
pub fn get_untaggedptr(self) -> *mut c_void {
(self.to_raw() & VALMASK) as intptr_t as *mut c_void
Expand Down Expand Up @@ -182,6 +200,10 @@ impl<T> ExternalPtr<T> {
pub fn as_ptr(&self) -> *const T {
self.0
}

pub fn as_mut(&mut self) -> *mut T {
self.0
}
}

impl<T> Deref for ExternalPtr<T> {
Expand Down Expand Up @@ -485,6 +507,36 @@ impl LispObject {
}
}

impl LispObject {
pub fn as_hash_table_or_error(&self) -> LispHashTableRef {
if self.is_hash_table() {
LispHashTableRef::new(unsafe { mem::transmute(self.get_untaggedptr()) })
} else {
wrong_type!(Qhash_table_p, *self);
}
}

pub fn as_hash_table(&self) -> Option<LispHashTableRef> {
if self.is_hash_table() {
Some(LispHashTableRef::new(
unsafe { mem::transmute(self.get_untaggedptr()) },
))
} else {
None
}
}

pub fn from_hash_table(hashtable: LispHashTableRef) -> LispObject {
let object = LispObject::tag_ptr(hashtable, Lisp_Type::Lisp_Vectorlike);
debug_assert!(
object.is_vectorlike() && object.get_untaggedptr() == hashtable.as_ptr() as *mut c_void
);

debug_assert!(object.is_hash_table());
object
}
}

// Cons support (LispType == 6 | 3)

/// From FOR_EACH_TAIL_INTERNAL in lisp.h
Expand Down
40 changes: 40 additions & 0 deletions rust_src/src/vectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,43 @@ pub fn mutexp(object: LispObject) -> LispObject {
pub fn condition_variable_p(object: LispObject) -> LispObject {
LispObject::from_bool(object.is_condition_variable())
}

macro_rules! offset_of {
($ty:ty, $field:ident) => {
&(*(0 as *const $ty)).$field as *const _ as usize
}
}

lazy_static! {
pub static ref HEADER_SIZE: usize = {
unsafe { offset_of!(::remacs_sys::Lisp_Vector, contents) }
};
pub static ref WORD_SIZE: usize = {
::std::mem::size_of::<::remacs_sys::Lisp_Object>()
};
}

/// Equivalent to PSEUDOVECSIZE in C
macro_rules! pseudovecsize {
($ty: ty, $field: ident) => {
((offset_of!($ty, $field) - *::vectors::HEADER_SIZE) / *::vectors::WORD_SIZE)
}
}

/// Equivalent to VECSIZE in C
macro_rules! vecsize {
($ty: ty) => {
((::std::mem::size_of::<$ty>()
- *::vectors::HEADER_SIZE + *::vectors::WORD_SIZE - 1) / *::vectors::WORD_SIZE)
}
}

/// Equivalent to ALLOCATE_PSEUDOVECTOR in C
macro_rules! allocate_pseudovector {
($ty: ty, $field: ident, $vectype: expr) => {
unsafe { ::remacs_sys::allocate_pseudovector(vecsize!($ty) as ::libc::c_int,
pseudovecsize!($ty, $field) as ::libc::c_int,
pseudovecsize!($ty, $field) as ::libc::c_int,
$vectype) as *mut $ty}
}
}
Loading