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

Port fontp to Rust #248

Merged
merged 6 commits into from
Jul 24, 2017
Merged

Port fontp to Rust #248

merged 6 commits into from
Jul 24, 2017

Conversation

atheriel
Copy link
Contributor

@atheriel atheriel commented Jul 17, 2017

This is my first pass at porting fontp to Rust, and should be considered a work in progress. I have a few questions:

  1. Should I change the naming convention for the font_property_index enum?
  2. Is there a convention for calling intern from Rust code? See Adds intern and an intern_static! macro #255.
  3. Can or should I add is_font_spec() (etc) methods to LispObject in lisp.rs, so that the checking can be moved out of fontp and into those methods?

This should close #233.

// See font_property_index in font.h for details.
#[allow(non_camel_case_types, dead_code)]
#[repr(C)]
enum font_property_index {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This enum will probably want to be defined in the remacs-sys crate instead of here. That crate is where we house the code related to FFI and representing structures that are defined in the C layer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I will move it there.

Copy link
Collaborator

Choose a reason for hiding this comment

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

use camelcase names.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved, with a new camelcase name.

if v.is_pseudovector(PseudovecType::PVEC_FONT) {
if extra_type.eq(Qnil) {
LispObject::constant_t()
} else if extra_type.eq(LispObject::from_raw(unsafe { Qfont_spec })) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah I don't like the raw unsafe Q... usage here. Personally I like the idea of having safe methods implemented for LispObject like "is_font_spec", etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thoought it would be "safe enough" to get at these symbols this way -- is there another option?

Copy link
Collaborator

@DavidDeSimone DavidDeSimone Jul 17, 2017

Choose a reason for hiding this comment

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

Let me clarify:

Accessing these symbols the way you are doing is fine, but we have to use unsafe blocks in Lisp binding code. If we have another lisp binding that needs to do similar logic, we will need to add more unsafe blocks. In general, I think a Rust code base is at it's best when it minimizes unsafe code blocks.

We can improve this situation by adding a safe wrapper around unsafe code (since the code here is "unsafe" due to its interaction with C). For example something like:

impl LispObject {
    pub fn is_font_spec(&self) -> bool {
        self.eq(unsafe { /* ... */ });  
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's fair. I think that fontp is the only place that uses of Qfont_spec and friends in this manner in the codebase, though. Is it worth writing a safe interface (for example, creating a FontEntity::from_object()-style enum method)?

Copy link
Collaborator

Choose a reason for hiding this comment

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

That's a fair point, I'm personally fine either way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wrote a little enum to abstract this pattern out.

} else {
// As with the C version, checking that object is a font takes priority
// over checking that extra_type is well-formed.
Qnil
Copy link
Collaborator

Choose a reason for hiding this comment

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

We generally prefer calls to LispObject::constant_nil() over raw Qnil usage.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed.

@DavidDeSimone
Copy link
Collaborator

Thanks for the contribution! This is looking good to me so far, I've left a few inline comments on a couple things I saw.

@atheriel
Copy link
Contributor Author

Ok, I've added some is_font_* methods to LispObject.

@atheriel
Copy link
Contributor Author

I will probably wait on #244 before moving the struct to remacs-sys.

#[lisp_fn(min = "1")]
pub fn fontp(object: LispObject, extra_type: LispObject) -> LispObject {
if object.is_font() {
if extra_type.eq(LispObject::constant_nil()) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

shorter: extra_type.is_nil()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed.

@@ -559,6 +560,27 @@ impl LispObject {
v.is_pseudovector(PseudovecType::PVEC_FONT)
})
}

pub fn is_font_spec(self) -> bool {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of adding these to LispObject, I would create an as_font method on is_vectorlike that returns a "LispFontRef" or similar.

is_spec, is_entity etc can the be methods on that struct.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I've taken this approach.

}

impl FontExtraType {
pub fn from_object_or_error(extra_type: LispObject) -> FontExtraType {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd prefer from_symbol_or_error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

FontExtraType::Object
} else {
// TODO: This should actually be equivalent to
// intern("font-extra-type"), not Qsymbolp.
Copy link
Collaborator

Choose a reason for hiding this comment

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

In order to call intern, you can add it to the imported functions in remacs-sys. Signature should be straightforward.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This turns out to be more difficult than it first appears. See #255.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@@ -1096,3 +1096,47 @@ extern "C" {
nchars_return: *mut ptrdiff_t,
) -> ptrdiff_t;
}

/// Contains C definitions from the font.h header.
pub mod font {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Good idea to add some modules to structure this crate!

@birkenfeld
Copy link
Collaborator

Can be updated to use intern() now.

Signed-off-by: Aaron Jacobs <atheriel@gmail.com>
Signed-off-by: Aaron Jacobs <atheriel@gmail.com>
Signed-off-by: Aaron Jacobs <atheriel@gmail.com>
Signed-off-by: Aaron Jacobs <atheriel@gmail.com>
Signed-off-by: Aaron Jacobs <atheriel@gmail.com>
Signed-off-by: Aaron Jacobs <atheriel@gmail.com>
@atheriel
Copy link
Contributor Author

Updated to use intern(). Is there anything else extant on this PR?

@birkenfeld
Copy link
Collaborator

Nope, looks, good!

use vectors::LispVectorlikeRef;

// A font is not a type in and of itself, it's just a group of three kinds of
// pseudovector. This newtype allows us to define methods that yield the actual
Copy link

Choose a reason for hiding this comment

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

This could be improved.

  • plural of pseudovectors
  • missing space between new and type.
  • First you mention that a font is not a type and then you continue with "This new type"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm glad someone is reading the docstrings :) Not quite sure I agree about the plural -- a font is "one of three kinds of pseudovector", so fonts are "a group of three kinds of pseudovector". Might be wrong here, though.

The term "newtype" refers to the Rust pattern of struct X(Y). It's not a typo. A "font" does not have its own structure in the C code. It refers to three possible structs. Hence a font is not "a type in and of itself". It's just a label for a group of structures. So I'm not actually defining any structure here, I just want to add some methods to LispVectorlikeRef -- hence the newtype.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Port fontp to Rust
5 participants