feat(napi-derive): allow injecting this in class method

This commit is contained in:
LongYinan 2022-07-05 23:09:40 +08:00
parent c3b59c8a12
commit 87fd74cbb6
No known key found for this signature in database
GPG key ID: C3666B7FC82ADAD7
8 changed files with 51 additions and 24 deletions

View file

@ -12,7 +12,7 @@ impl TryToTokens for NapiFn {
let intermediate_ident = get_intermediate_ident(&name_str); let intermediate_ident = get_intermediate_ident(&name_str);
let args_len = self.args.len(); let args_len = self.args.len();
let (arg_conversions, arg_names) = self.gen_arg_conversions(); let (arg_conversions, arg_names) = self.gen_arg_conversions()?;
let receiver = self.gen_fn_receiver(); let receiver = self.gen_fn_receiver();
let receiver_ret_name = Ident::new("_ret", Span::call_site()); let receiver_ret_name = Ident::new("_ret", Span::call_site());
let ret = self.gen_fn_return(&receiver_ret_name); let ret = self.gen_fn_return(&receiver_ret_name);
@ -93,7 +93,7 @@ impl TryToTokens for NapiFn {
} }
impl NapiFn { impl NapiFn {
fn gen_arg_conversions(&self) -> (Vec<TokenStream>, Vec<TokenStream>) { fn gen_arg_conversions(&self) -> BindgenResult<(Vec<TokenStream>, Vec<TokenStream>)> {
let mut arg_conversions = vec![]; let mut arg_conversions = vec![];
let mut args = vec![]; let mut args = vec![];
@ -117,7 +117,7 @@ impl NapiFn {
} }
let mut skipped_arg_count = 0; let mut skipped_arg_count = 0;
self.args.iter().enumerate().for_each(|(i, arg)| { for (i, arg) in self.args.iter().enumerate() {
let i = i - skipped_arg_count; let i = i - skipped_arg_count;
let ident = Ident::new(&format!("arg{}", i), Span::call_site()); let ident = Ident::new(&format!("arg{}", i), Span::call_site());
@ -127,27 +127,41 @@ impl NapiFn {
args.push(quote! { napi::bindgen_prelude::Env::from(env) }); args.push(quote! { napi::bindgen_prelude::Env::from(env) });
skipped_arg_count += 1; skipped_arg_count += 1;
} else { } else {
if self.parent.is_some() { let is_in_class = self.parent.is_some();
if let syn::Type::Path(path) = path.ty.as_ref() { if let syn::Type::Path(path) = path.ty.as_ref() {
if let Some(p) = path.path.segments.last() { if let Some(p) = path.path.segments.last() {
if p.ident == "Reference" { if p.ident == "Reference" {
if let syn::PathArguments::AngleBracketed( if !is_in_class {
syn::AngleBracketedGenericArguments { args: angle_bracketed_args, .. }, bail_span!(p, "`Reference` is only allowed in class methods");
) = &p.arguments }
if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
args: angle_bracketed_args,
..
}) = &p.arguments
{
if let Some(syn::GenericArgument::Type(syn::Type::Path(path))) =
angle_bracketed_args.first()
{ {
if let Some(syn::GenericArgument::Type(syn::Type::Path(path))) = angle_bracketed_args.first() { if let Some(p) = path.path.segments.first() {
if let Some(p) = path.path.segments.first() { if p.ident == *self.parent.as_ref().unwrap() {
if p.ident == *self.parent.as_ref().unwrap() { args.push(
args.push( quote! { napi::bindgen_prelude::Reference::from_value_ptr(this_ptr as *mut std::ffi::c_void, env)? },
quote! { napi::bindgen_prelude::Reference::from_value_ptr(this_ptr as *mut std::ffi::c_void, env)? }, );
); skipped_arg_count += 1;
skipped_arg_count += 1; continue;
return; }
}
}
} }
} }
} }
} else if p.ident == "This" {
if !is_in_class {
bail_span!(p, "`This` is only allowed in class methods");
}
args.push(
quote! { <napi::bindgen_prelude::This as napi::NapiValue>::from_raw_unchecked(env, cb.this) },
);
skipped_arg_count += 1;
continue;
} }
} }
} }
@ -160,9 +174,9 @@ impl NapiFn {
args.push(quote! { #ident }); args.push(quote! { #ident });
} }
} }
}); }
(arg_conversions, args) Ok((arg_conversions, args))
} }
fn gen_ty_arg_conversion( fn gen_ty_arg_conversion(

View file

@ -214,6 +214,7 @@ static KNOWN_TYPES: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
("unknown", "unknown"), ("unknown", "unknown"),
("Unknown", "unknown"), ("Unknown", "unknown"),
("JsUnknown", "unknown"), ("JsUnknown", "unknown"),
("This", "this")
]); ]);
map map

View file

@ -2,7 +2,9 @@ use std::any::type_name;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::ptr; use std::ptr;
use crate::{bindgen_runtime::FromNapiValue, check_status, sys, NapiRaw}; use crate::{bindgen_runtime::FromNapiValue, check_status, sys, JsObject, NapiRaw};
pub type This = JsObject;
pub struct ClassInstance<T: 'static> { pub struct ClassInstance<T: 'static> {
pub value: sys::napi_value, pub value: sys::napi_value,

View file

@ -254,6 +254,7 @@ Generated by [AVA](https://avajs.dev).
static newRaph(): NinjaTurtle␊ static newRaph(): NinjaTurtle␊
getMaskColor(): string␊ getMaskColor(): string␊
getName(): string␊ getName(): string␊
returnThis(this: this): this␊
}␊ }␊
export type JsAssets = Assets␊ export type JsAssets = Assets␊
export class Assets {␊ export class Assets {␊

View file

@ -21,6 +21,7 @@ import {
getCwd, getCwd,
Animal, Animal,
Kind, Kind,
NinjaTurtle,
ClassWithFactory, ClassWithFactory,
CustomNumEnum, CustomNumEnum,
Context, Context,
@ -173,6 +174,8 @@ test('class', (t) => {
t.is(dog.type, Kind.Cat) t.is(dog.type, Kind.Cat)
const assets = new Assets() const assets = new Assets()
t.is(assets.get(1)?.filePath, 1) t.is(assets.get(1)?.filePath, 1)
const turtle = NinjaTurtle.newRaph()
t.is(turtle.returnThis(), turtle)
}) })
test('class factory', (t) => { test('class factory', (t) => {

View file

@ -244,6 +244,7 @@ export class NinjaTurtle {
static newRaph(): NinjaTurtle static newRaph(): NinjaTurtle
getMaskColor(): string getMaskColor(): string
getName(): string getName(): string
returnThis(this: this): this
} }
export type JsAssets = Assets export type JsAssets = Assets
export class Assets { export class Assets {

View file

@ -1,5 +1,5 @@
use napi::{ use napi::{
bindgen_prelude::{Buffer, ClassInstance}, bindgen_prelude::{Buffer, ClassInstance, This},
Env, Result, Env, Result,
}; };
@ -229,6 +229,11 @@ impl NinjaTurtle {
pub fn get_name(&self) -> &str { pub fn get_name(&self) -> &str {
self.name.as_str() self.name.as_str()
} }
#[napi]
pub fn return_this(&self, this: This) -> This {
this
}
} }
#[napi(js_name = "Assets")] #[napi(js_name = "Assets")]