-
Notifications
You must be signed in to change notification settings - Fork 308
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
Port 'string-lessp' to Rust #217
Changes from 2 commits
9527486
e0b5f93
c21e4d5
be284af
420ab03
0bc4752
ae8d366
010b742
1d61ce8
cf859d5
bf956b9
f169c24
adaf0ef
cdef968
567941d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,11 +14,12 @@ use libc::{c_void, intptr_t}; | |
|
||
use marker::{LispMarker, marker_position}; | ||
use multibyte::{LispStringRef, MAX_CHAR}; | ||
use symbols::LispSymbolRef; | ||
use vectors::LispVectorlikeRef; | ||
use buffers::LispBufferRef; | ||
|
||
use remacs_sys::{EmacsInt, EmacsUint, EmacsDouble, EMACS_INT_MAX, EMACS_INT_SIZE, | ||
EMACS_FLOAT_SIZE, USE_LSB_TAG, GCTYPEBITS, wrong_type_argument, Qstringp, | ||
EMACS_FLOAT_SIZE, USE_LSB_TAG, GCTYPEBITS, wrong_type_argument, Qstringp, Qsymbolp, | ||
Qnumber_or_marker_p, Qt, make_float, Qlistp, Qintegerp, Qconsp, circular_list, | ||
internal_equal, Fcons, CHECK_IMPURE, Qnumberp, Qfloatp, Qwholenump, Qvectorp, | ||
SYMBOL_NAME, PseudovecType}; | ||
|
@@ -150,14 +151,28 @@ impl LispObject { | |
} | ||
|
||
// Symbol support (LispType == Lisp_Symbol == 0) | ||
|
||
impl LispObject { | ||
#[inline] | ||
pub fn is_symbol(self) -> bool { | ||
self.get_type() == LispType::Lisp_Symbol | ||
} | ||
|
||
pub fn symbol_name(&self) -> LispObject { | ||
unsafe { LispObject::from_raw(SYMBOL_NAME(self.to_raw())) } | ||
#[inline] | ||
pub fn as_symbol(&self) -> Option<LispSymbolRef> { | ||
if self.is_symbol() { | ||
Some(LispSymbolRef::new(unsafe { mem::transmute(self.get_untaggedptr()) })) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks to be incorrect. The code in lisp.h for XSYMBOL looks like
and it looks like we will have to emulate this logic for getting the address to mem::transmute. |
||
} else { | ||
None | ||
} | ||
} | ||
|
||
#[inline] | ||
pub fn as_symbol_or_error(&self) -> LispSymbolRef { | ||
if self.is_symbol() { | ||
LispSymbolRef::new(unsafe { mem::transmute(self.get_untaggedptr()) }) | ||
} else { | ||
unsafe { wrong_type_argument(Qsymbolp, self.to_raw()) } | ||
} | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
//! Functions operating on strings. | ||
|
||
use std::{ptr, cmp}; | ||
use std::ptr; | ||
|
||
use libc::{self, c_char, c_void, ptrdiff_t}; | ||
|
||
|
@@ -202,10 +202,9 @@ fn string_to_unibyte(string: LispObject) -> LispObject { | |
} | ||
} | ||
|
||
// @TODO need to rework this function to use new as_symbol_or_error API | ||
fn get_string_or_symbol(mut string: LispObject) -> multibyte::LispStringRef { | ||
if string.is_symbol() { | ||
string = string.symbol_name() | ||
string = string.as_symbol_or_error().symbol_name() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This still duplicates the symbol check. I'd make it
If you like, you can also make |
||
} | ||
|
||
string.as_string_or_error() | ||
|
@@ -216,16 +215,14 @@ fn string_lessp(string1: LispObject, string2: LispObject) -> LispObject { | |
let lispstr1 = get_string_or_symbol(string1); | ||
let lispstr2 = get_string_or_symbol(string2); | ||
|
||
let mut count = 0; | ||
let zip = lispstr1.iter().zip(lispstr2.iter()); | ||
for ((codept1, _), (codept2, _)) in zip { | ||
count += 1; | ||
if codept1 != codept2 { | ||
return LispObject::from_bool(codept1 < codept2); | ||
} | ||
} | ||
|
||
LispObject::from_bool(count < lispstr2.len_chars()) | ||
LispObject::from_bool(lispstr1.len_chars() < lispstr2.len_chars()) | ||
} | ||
|
||
/// Return t if OBJECT is a multibyte string. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gcmarkbit, redirect ...etc are missing ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is my understanding of the situation re: the mentioned variables. If anyone spots any incorrect information please do not hesitate to correct me:
Lisp_Symbol has the following definition in lisp.h (I've stripped out the comments for clarity):
This struct is using the C notation for bit fields. According to my research, Rust does not (rust-lang/rfcs#314, https://users.rust-lang.org/t/c-structs-with-bit-fields-and-ffi/1429) support setting up an equivalent for C bitfieldsin it's
#[repr(C)]
directive.On my system (64-bit Ubuntu 16.04), no matter what the typedef of bf_bool or ENUM_BF, the bit field section of the struct takes 4 bytes. Due to alignment, the struct is padded, and offsetof(struct Lisp_Symbol, name) reports 8. My initial solution to representing this struct in Rust was to represent the bit field block as a u32, taking up the 4 bytes I mentioned earlier. I have not fully convinced myself that this is 100% the correct and portable thing to do.
Even if we can safely represent this block with a u32 on every system we support, it seems that there are 'gotcha's with accessing these bit fields via the bit wise operators (due to endianness, and compiler differences w.r.t bit field implementation.)
Overall I am not sure the best way to handle the interop for C structs that use bit fields that we need to access in Rust. It seems that one option is to simply pad the Rust struct as best we can, and if we need to access these fields, we will need to maintain C bindings that access them for us.