DelSkayn / rquickjs

High level bindings to the quickjs javascript engine
MIT License
435 stars 59 forks source link

Wrong method definition result in omission of the whole method under methods attributes #213

Closed stevefan1999-personal closed 9 months ago

stevefan1999-personal commented 9 months ago

Consider an example like this:

#[derive(Trace, Derivative, From, Into, Deref, DerefMut)]
#[derivative(Clone, Debug)]
#[rquickjs::class(rename = "IpAddr")]
pub struct IpAddrWrapper {
    #[qjs(skip_trace)]
    addr: IpAddr,
}

#[rquickjs::methods]
impl IpAddrWrapper {
    #[delegate(self.addr)]
    #[qjs(get, enumerable)]
    pub fn is_unspecified(&self) -> bool;

    #[qjs(get, enumerable)]
    #[delegate(self.addr)]
    pub fn is_loopback(&self) -> bool;

    #[qjs(get, enumerable)]
    #[delegate(self.addr)]
    pub fn is_multicast(&self) -> bool;

    #[qjs(get, enumerable)]
    #[delegate(self.addr)]
    pub fn is_ipv4(&self) -> bool;

    #[qjs(get, enumerable)]
    #[delegate(self.addr)]
    pub fn is_ipv6(&self) -> bool;

    #[qjs(rename = "toString")]
    #[delegate(self.addr)]
    pub fn to_string(&self) -> String;
}

I realized the delegate procedural attributes was not used and looking at the crate expansion, it seems like the function was omitted due to "invalid" parsing. If you lookup upsuper/delegate-attr: Attribute proc-macro to delegate method to a field (github.com), it is really not invalid there so there must be something wrong in the macro expansion phase, likely the AST reader was too strict.

So consider that of course I found out a workaround:

#[derive(Trace, Derivative, From, Into, Deref, DerefMut)]
#[derivative(Clone, Debug)]
#[rquickjs::class(rename = "IpAddr")]
pub struct IpAddrWrapper {
    #[qjs(skip_trace)]
    addr: IpAddr,
}

#[rquickjs::methods]
impl IpAddrWrapper {
    #[delegate(self.addr)]
    #[qjs(get, enumerable)]
    pub fn is_unspecified(&self) -> bool {}

    #[qjs(get, enumerable)]
    #[delegate(self.addr)]
    pub fn is_loopback(&self) -> bool {}

    #[qjs(get, enumerable)]
    #[delegate(self.addr)]
    pub fn is_multicast(&self) -> bool {}

    #[qjs(get, enumerable)]
    #[delegate(self.addr)]
    pub fn is_ipv4(&self) -> bool {}

    #[qjs(get, enumerable)]
    #[delegate(self.addr)]
    pub fn is_ipv6(&self) -> bool {}

    #[qjs(rename = "toString")]
    #[delegate(self.addr)]
    pub fn to_string(&self) -> String {}
}

Which I don't really like, given I would like to save the braces up for the automatic code generator

DelSkayn commented 9 months ago

Because pub fn function() -> bool; is not a valid item of an impl block, the syn crate is unable to parse it and just returns a list of tokens. Supporting this would require manually parsing these types of functions which I find quite a lot of work just to support a macro from a different crate, especially when you have found a work around which is only marginally different.