@@ -825,6 +825,58 @@ void Reference::WeakCallback(const v8::WeakCallbackInfo<Reference>& data) {
825825 reference->env_ ->InvokeFinalizerFromGC (reference);
826826}
827827
828+ /* *
829+ * A wrapper for `v8::External` to support type-tagging. `v8::External` doesn't
830+ * support defining any properties and private properties on it, even though it
831+ * is an object. This wrapper is used to store the type tag and the data of the
832+ * external value.
833+ */
834+ class ExternalWrapper {
835+ private:
836+ explicit ExternalWrapper (void * data) : data_(data) {}
837+
838+ static void WeakCallback (const v8::WeakCallbackInfo<ExternalWrapper>& data) {
839+ ExternalWrapper* wrapper = data.GetParameter ();
840+ delete wrapper;
841+ }
842+
843+ public:
844+ static v8::Local<v8::External> New (napi_env env, void * data) {
845+ ExternalWrapper* wrapper = new ExternalWrapper (data);
846+ v8::Local<v8::External> external = v8::External::New (env->isolate , wrapper);
847+ wrapper->persistent_ .Reset (env->isolate , external);
848+ wrapper->persistent_ .SetWeak (
849+ wrapper, WeakCallback, v8::WeakCallbackType::kParameter );
850+
851+ return external;
852+ }
853+
854+ static ExternalWrapper* From (v8::Local<v8::External> external) {
855+ return static_cast <ExternalWrapper*>(external->Value ());
856+ }
857+
858+ void * Data () { return data_; }
859+
860+ bool TypeTag (const napi_type_tag* type_tag) {
861+ if (type_tag_ != nullptr ) {
862+ return false ;
863+ }
864+ type_tag_ = type_tag;
865+ return true ;
866+ }
867+
868+ bool CheckTypeTag (const napi_type_tag* type_tag) {
869+ return type_tag == type_tag_ ||
870+ (type_tag_ && type_tag->lower == type_tag_->lower &&
871+ type_tag->upper == type_tag_->upper );
872+ }
873+
874+ private:
875+ v8impl::Persistent<v8::Value> persistent_;
876+ void * data_;
877+ const napi_type_tag* type_tag_ = nullptr ;
878+ };
879+
828880} // end of namespace v8impl
829881
830882// Warning: Keep in-sync with napi_status enum
@@ -2517,9 +2569,8 @@ napi_status NAPI_CDECL napi_create_external(napi_env env,
25172569 NAPI_PREAMBLE (env);
25182570 CHECK_ARG (env, result);
25192571
2520- v8::Isolate* isolate = env->isolate ;
2521-
2522- v8::Local<v8::Value> external_value = v8::External::New (isolate, data);
2572+ v8::Local<v8::External> external_value =
2573+ v8impl::ExternalWrapper::New (env, data);
25232574
25242575 if (finalize_cb) {
25252576 // The Reference object will delete itself after invoking the finalizer
@@ -2539,12 +2590,24 @@ napi_status NAPI_CDECL napi_create_external(napi_env env,
25392590}
25402591
25412592napi_status NAPI_CDECL napi_type_tag_object (napi_env env,
2542- napi_value object ,
2593+ napi_value object_or_external ,
25432594 const napi_type_tag* type_tag) {
25442595 NAPI_PREAMBLE (env);
25452596 v8::Local<v8::Context> context = env->context ();
2597+
2598+ CHECK_ARG (env, object_or_external);
2599+ v8::Local<v8::Value> val =
2600+ v8impl::V8LocalValueFromJsValue (object_or_external);
2601+ if (val->IsExternal ()) {
2602+ v8impl::ExternalWrapper* wrapper =
2603+ v8impl::ExternalWrapper::From (val.As <v8::External>());
2604+ RETURN_STATUS_IF_FALSE_WITH_PREAMBLE (
2605+ env, wrapper->TypeTag (type_tag), napi_invalid_arg);
2606+ return GET_RETURN_STATUS (env);
2607+ }
2608+
25462609 v8::Local<v8::Object> obj;
2547- CHECK_TO_OBJECT_WITH_PREAMBLE (env, context, obj, object );
2610+ CHECK_TO_OBJECT_WITH_PREAMBLE (env, context, obj, object_or_external );
25482611 CHECK_ARG_WITH_PREAMBLE (env, type_tag);
25492612
25502613 auto key = NAPI_PRIVATE_KEY (context, type_tag);
@@ -2566,13 +2629,24 @@ napi_status NAPI_CDECL napi_type_tag_object(napi_env env,
25662629}
25672630
25682631napi_status NAPI_CDECL napi_check_object_type_tag (napi_env env,
2569- napi_value object ,
2632+ napi_value object_or_external ,
25702633 const napi_type_tag* type_tag,
25712634 bool * result) {
25722635 NAPI_PREAMBLE (env);
25732636 v8::Local<v8::Context> context = env->context ();
2637+
2638+ CHECK_ARG (env, object_or_external);
2639+ v8::Local<v8::Value> obj_val =
2640+ v8impl::V8LocalValueFromJsValue (object_or_external);
2641+ if (obj_val->IsExternal ()) {
2642+ v8impl::ExternalWrapper* wrapper =
2643+ v8impl::ExternalWrapper::From (obj_val.As <v8::External>());
2644+ *result = wrapper->CheckTypeTag (type_tag);
2645+ return GET_RETURN_STATUS (env);
2646+ }
2647+
25742648 v8::Local<v8::Object> obj;
2575- CHECK_TO_OBJECT_WITH_PREAMBLE (env, context, obj, object );
2649+ CHECK_TO_OBJECT_WITH_PREAMBLE (env, context, obj, object_or_external );
25762650 CHECK_ARG_WITH_PREAMBLE (env, type_tag);
25772651 CHECK_ARG_WITH_PREAMBLE (env, result);
25782652
@@ -2617,7 +2691,7 @@ napi_status NAPI_CDECL napi_get_value_external(napi_env env,
26172691 RETURN_STATUS_IF_FALSE (env, val->IsExternal (), napi_invalid_arg);
26182692
26192693 v8::Local<v8::External> external_value = val.As <v8::External>();
2620- *result = external_value-> Value ();
2694+ *result = v8impl::ExternalWrapper::From ( external_value)-> Data ();
26212695
26222696 return napi_clear_last_error (env);
26232697}
0 commit comments