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

Tracking issue for CustomType derive macro #820

Closed
7 of 8 tasks
schungx opened this issue Jan 25, 2024 · 8 comments
Closed
7 of 8 tasks

Tracking issue for CustomType derive macro #820

schungx opened this issue Jan 25, 2024 · 8 comments

Comments

@schungx
Copy link
Collaborator

schungx commented Jan 25, 2024

PR: https://github.com/rhaiscript/rhai/pull/817

  • Docs docs docs
  • More tests
  • Register a pretty-print name for types
  • Attribute for calling a user-provided function with the TypeBuilder passed in
    • What would it be called?
    • Do we call it before or after registering everything else?
  • Attribute for renaming a field
  • Attribute for skipping a field entirely
  • Support for tuple structs
    • What would the fields be named? field0, field1, etc perhaps?
    • Or use rhai_custom_type_name to name fields?
  • Support for enums as described in the book
@schungx schungx assigned schungx and unassigned schungx Jan 25, 2024
@schungx
Copy link
Collaborator Author

schungx commented Jan 25, 2024

@MavethGH This is the tracking issue for the derive macro.

In #819 I have further refined it:

  • All the attributes now start with rhai_custom_type_ to avoid collision with other attributes.

  • rhai_custom_type_name is added to remap the field to another name.

  • rhai_custom_type_skip is added to skip a field.

@schungx
Copy link
Collaborator Author

schungx commented Jan 25, 2024

This is the example that I intend to put into the Book:

use rhai::{CustomType, TypeBuilder};            // <- necessary imports

#[derive(Debug, Clone)]                         // <- necessary for any custom type
#[derive(CustomType)]                           // <- auto-implement 'CustomType'
struct Foo {
    #[rhai_custom_type_skip]                    // <- not included
    dummy: i64,

    #[rhai_custom_type_readonly]                // <- only auto getter, no setter for 'bar'
    bar: i64,

    #[rhai_custom_type_name("emphasize")]
    baz: bool,                                  // <- auto getter/setter for 'baz'

    #[rhai_custom_type_set(Self::set_hello)]    // <- call custom setter for 'hello'
    hello: String                               // <- auto getter for 'hello'
}

impl Foo {
    pub fn set_hello(&mut self, value: String) {
        self.hello = if self.baz {
            let mut s = self.hello.clone();
            s.push_str(&value);
            for _ in 0..self.bar { s.push('!'); }
            s
        } else {
            value
        };
    }
}

@schungx
Copy link
Collaborator Author

schungx commented Jan 25, 2024

Actually, I dislike how all that rhai_custom_type_ prefix is so long and cumbersome...

It might be better (or not) if we can do this:

#[derive(CustomType)]
struct Foo {
    #[rhai_type(skip)]
    dummy: i64,

    #[rhai_type(readonly)]
    bar: i64,

    #[rhai_type(name="emphasize")]
    baz: bool,

    #[rhai_type(set=Self::set_hello)]
    hello: String
}

@schungx
Copy link
Collaborator Author

schungx commented Jan 26, 2024

In the latest drop I added support for tuple structs -- essentially the same code just tweaked.

Also, the type name is used for pretty-print. That should be slightly better than the default which is the type's full path name.

Docs are being added to the Book.

@schungx
Copy link
Collaborator Author

schungx commented Jan 27, 2024

@MavethGH , the latest drop is now pretty complete.

I have decided to call all the attributes rhai_type_* which should not be too long, but long enough to avoid collisions with other traits.

rhai_type_name can be put on the type or any field to rename them.

rhai_type_extra can specify functions to call (with the TypeBuilder) where you can add new functions.

Also, rhai_type_get now expects a regular getter method with &self, while rhai_type_get_mut takes the standard Rhai getter method with &mut self.

The complete set of attributes are now:

Attribute Applies to Parameter Description
rhai_type_name type, field string expression use this name instead of the type/field name.
rhai_type_skip field none skip this field.
rhai_type_readonly field none only auto-generate getter, no setter.
rhai_type_get field function path use this getter function (with &self) instead of the auto-generated getter.
rhai_type_get_mut field function path use this getter function (with &mut self) instead of the auto-generated getter.
rhai_type_set field function path use this setter function instead of the auto-generated setter.
rhai_type_extra type function path call this function after building the type to add additional API's

@schungx
Copy link
Collaborator Author

schungx commented Jan 29, 2024

In the end, I used a single attribute rhai_type with option fields to make it consistent with plugin module macros.

#[rhai_type(name = "foo", get = Self::get_foo, readonly)]

@schungx
Copy link
Collaborator Author

schungx commented Jan 29, 2024

I'm leaving the last task, auto-derive enums, unimplemented for now.

I'm not sure a derived API is the best way to expose enums in a dynamic scripting language... since every value in Rhai is an unlimited enum.

@schungx
Copy link
Collaborator Author

schungx commented Jan 29, 2024

I'll close off this issue now as I feel the feature is reasonably complete. Thanks for starting this @MavethGH !

In fact, the derive macro will be featured in the Book as the preferred method of registering the API of a type.

@schungx schungx closed this as completed Jan 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant