diff --git a/crates/backend/src/codegen/fn.rs b/crates/backend/src/codegen/fn.rs index 3fd41b48..a2f3d42b 100644 --- a/crates/backend/src/codegen/fn.rs +++ b/crates/backend/src/codegen/fn.rs @@ -272,11 +272,6 @@ impl NapiFn { }); skipped_arg_count += 1; continue; - } else { - bail_span!( - p, - "The `T` of Reference type must be the same as the class type" - ) } } } diff --git a/crates/backend/src/typegen/fn.rs b/crates/backend/src/typegen/fn.rs index ff798139..5fd6be9e 100644 --- a/crates/backend/src/typegen/fn.rs +++ b/crates/backend/src/typegen/fn.rs @@ -141,7 +141,24 @@ impl NapiFn { if let syn::Type::Path(path) = path.ty.as_ref() { if let Some(PathSegment { ident, arguments }) = path.path.segments.last() { if ident == "Reference" || ident == "WeakReference" { - return None; + if let Some(parent) = &self.parent { + if let PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + args: angle_bracketed_args, + .. + }) = arguments + { + if let Some(syn::GenericArgument::Type(ty)) = angle_bracketed_args.first() { + if let syn::Type::Path(syn::TypePath { path, .. }) = ty { + if let Some(segment) = path.segments.first() { + if segment.ident.to_string() == parent.to_string() { + // If we have a Reference in an impl A block, it shouldn't be an arg + return None; + } + } + } + } + } + } } if ident == "This" || ident == "this" { if self.kind != FnKind::Normal { diff --git a/crates/napi/src/bindgen_runtime/js_values/value_ref.rs b/crates/napi/src/bindgen_runtime/js_values/value_ref.rs index 18479379..d325bddb 100644 --- a/crates/napi/src/bindgen_runtime/js_values/value_ref.rs +++ b/crates/napi/src/bindgen_runtime/js_values/value_ref.rs @@ -2,8 +2,10 @@ use std::cell::{Cell, RefCell}; use std::collections::HashMap; use std::ffi::c_void; use std::ops::{Deref, DerefMut}; +use std::ptr; use std::rc::{Rc, Weak}; +use crate::bindgen_prelude::FromNapiValue; use crate::{bindgen_runtime::ToNapiValue, check_status, Env, Error, Result, Status}; type RefInformation = ( @@ -94,7 +96,7 @@ impl Reference { impl ToNapiValue for Reference { unsafe fn to_napi_value(env: crate::sys::napi_env, val: Self) -> Result { - let mut result = std::ptr::null_mut(); + let mut result = ptr::null_mut(); check_status!( unsafe { crate::sys::napi_get_reference_value(env, val.napi_ref, &mut result) }, "Failed to get reference value" @@ -103,6 +105,21 @@ impl ToNapiValue for Reference { } } +impl FromNapiValue for Reference { + unsafe fn from_napi_value( + env: crate::sys::napi_env, + napi_val: crate::sys::napi_value, + ) -> Result { + let mut value = ptr::null_mut(); + check_status!( + unsafe { crate::sys::napi_unwrap(env, napi_val, &mut value) }, + "Unwrap value [{}] from class Reference failed", + std::any::type_name::(), + )?; + unsafe { Reference::from_value_ptr(value.cast(), env) } + } +} + impl Reference { pub fn clone(&self, env: Env) -> Result { let mut ref_count = 0; @@ -188,7 +205,7 @@ impl ToNapiValue for WeakReference { ), )); }; - let mut result = std::ptr::null_mut(); + let mut result = ptr::null_mut(); check_status!( unsafe { crate::sys::napi_get_reference_value(env, val.napi_ref, &mut result) }, "Failed to get reference value" @@ -276,7 +293,7 @@ impl SharedReference { impl ToNapiValue for SharedReference { unsafe fn to_napi_value(env: crate::sys::napi_env, val: Self) -> Result { - let mut result = std::ptr::null_mut(); + let mut result = ptr::null_mut(); check_status!( unsafe { crate::sys::napi_get_reference_value(env, val.owner.napi_ref, &mut result) }, "Failed to get reference value" diff --git a/examples/napi/__tests__/__snapshots__/typegen.spec.ts.md b/examples/napi/__tests__/__snapshots__/typegen.spec.ts.md index c9d8768e..e1a4e7ac 100644 --- a/examples/napi/__tests__/__snapshots__/typegen.spec.ts.md +++ b/examples/napi/__tests__/__snapshots__/typegen.spec.ts.md @@ -174,6 +174,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ export class JsRemote {␊ + constructor(repo: JsRepo)␊ name(): string␊ }␊ ␊ diff --git a/examples/napi/__tests__/__snapshots__/typegen.spec.ts.snap b/examples/napi/__tests__/__snapshots__/typegen.spec.ts.snap index 25cdfede..65024907 100644 Binary files a/examples/napi/__tests__/__snapshots__/typegen.spec.ts.snap and b/examples/napi/__tests__/__snapshots__/typegen.spec.ts.snap differ diff --git a/examples/napi/__tests__/__snapshots__/values.spec.ts.snap b/examples/napi/__tests__/__snapshots__/values.spec.ts.snap index 84b41386..f693200f 100644 Binary files a/examples/napi/__tests__/__snapshots__/values.spec.ts.snap and b/examples/napi/__tests__/__snapshots__/values.spec.ts.snap differ diff --git a/examples/napi/__tests__/values.spec.ts b/examples/napi/__tests__/values.spec.ts index 493f27b2..ecc6458b 100644 --- a/examples/napi/__tests__/values.spec.ts +++ b/examples/napi/__tests__/values.spec.ts @@ -134,6 +134,7 @@ const { bufferPassThrough, arrayBufferPassThrough, JsRepo, + JsRemote, CssStyleSheet, CatchOnConstructor, CatchOnConstructor2, @@ -409,6 +410,7 @@ test('custom finalize class', (t) => { test('should be able to create object reference and shared reference', (t) => { const repo = new JsRepo('.') t.is(repo.remote().name(), 'origin') + t.is(new JsRemote(repo).name(), 'origin') }) test('should be able to into_reference', (t) => { diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index 2f305b25..7874fe39 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -164,6 +164,7 @@ export class JsClassForEither { } export class JsRemote { + constructor(repo: JsRepo) name(): string } diff --git a/examples/napi/src/reference.rs b/examples/napi/src/reference.rs index c87af198..d9519c2b 100644 --- a/examples/napi/src/reference.rs +++ b/examples/napi/src/reference.rs @@ -51,6 +51,13 @@ pub struct JsRemote { #[napi] impl JsRemote { + #[napi(constructor)] + pub fn new(repo: Reference, env: Env) -> Result { + Ok(Self { + inner: repo.share_with(env, |repo| Ok(repo.inner.remote()))?, + }) + } + #[napi] pub fn name(&self) -> String { self.inner.name()