Skip to content

Commit

Permalink
Support Private accessors
Browse files Browse the repository at this point in the history
  • Loading branch information
kkoopa committed Dec 21, 2016
1 parent c93fd1d commit a86255c
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 35 deletions.
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ LINT_SOURCES = \
nan_object_wrap.h \
nan_persistent_12_inl.h \
nan_persistent_pre_12_inl.h \
nan_private.h \
nan_string_bytes.h \
nan_weak.h \
test/cpp/accessors.cpp \
Expand Down Expand Up @@ -59,6 +60,7 @@ LINT_SOURCES = \
test/cpp/news.cpp \
test/cpp/objectwraphandle.cpp \
test/cpp/persistent.cpp \
test/cpp/private.cpp \
test/cpp/returnemptystring.cpp \
test/cpp/returnnull.cpp \
test/cpp/returnundefined.cpp \
Expand Down Expand Up @@ -99,6 +101,6 @@ $(ADDONS): nan.h nan_new.h nan_implementation_pre_12_inl.h nan_implementation_12
nan_callbacks.h nan_callbacks_12_inl.h nan_callbacks_pre_12_inl.h \
nan_converters.h nan_converters_43_inl.h nan_converters_pre_43_inl.h \
nan_maybe_43_inl.h nan_maybe_pre_43_inl.h \
nan_persistent_12_inl.h nan_persistent_pre_12_inl.h nan_weak.h \
nan_string_bytes.h test/binding.gyp $(SOURCES)
nan_persistent_12_inl.h nan_persistent_pre_12_inl.h nan_private.h \
nan_weak.h nan_string_bytes.h test/binding.gyp $(SOURCES)
cd test/ && ../node_modules/.bin/node-gyp rebuild
48 changes: 48 additions & 0 deletions doc/maybe_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ The `Nan::MaybeLocal` and `Nan::Maybe` types are monads that encapsulate `v8::Lo
- <a href="#api_nan_get_start_column"><b><code>Nan::GetStartColumn()</code></b></a>
- <a href="#api_nan_get_end_column"><b><code>Nan::GetEndColumn()</code></b></a>
- <a href="#api_nan_clone_element_at"><b><code>Nan::CloneElementAt()</code></b></a>
- <a href="#api_nan_has_private"><b><code>Nan::HasPrivate()</code></b></a>
- <a href="#api_nan_get_private"><b><code>Nan::GetPrivate()</code></b></a>
- <a href="#api_nan_set_private"><b><code>Nan::SetPrivate()</code></b></a>
- <a href="#api_nan_delete_private"><b><code>Nan::DeletePrivate()</code></b></a>
- <a href="#api_nan_make_maybe"><b><code>Nan::MakeMaybe()</code></b></a>

<a name="api_nan_maybe_local"></a>
Expand Down Expand Up @@ -492,6 +496,50 @@ Signature:
Nan::MaybeLocal<v8::Object> Nan::CloneElementAt(v8::Local<v8::Array> array, uint32_t index);
```

<a name="api_nan_has_private"></a>
### Nan::HasPrivate()

A helper method for calling [`v8::Object#HasPrivate()`](https://v8docs.nodesource.com/node-7.2/db/d85/classv8_1_1_object.html#af68a0b98066cfdeb8f943e98a40ba08d) in a way compatible across supported versions of V8.

Signature:

```c++
Nan::Maybe<bool> Nan::HasPrivate(v8::Local<v8::Object> object, v8::Local<v8::String> key);
```
<a name="api_nan_get_private"></a>
### Nan::GetPrivate()
A helper method for calling [`v8::Object#GetPrivate()`](https://v8docs.nodesource.com/node-7.2/db/d85/classv8_1_1_object.html#a169f2da506acbec34deadd9149a1925a) in a way compatible across supported versions of V8.
Signature:
```c++
Nan::MaybeLocal<v8::Value> Nan::GetPrivate(v8::Local<v8::Object> object, v8::Local<v8::String> key);
```

<a name="api_nan_set_private"></a>
### Nan::SetPrivate()

A helper method for calling [`v8::Object#SetPrivate()`](https://v8docs.nodesource.com/node-7.2/db/d85/classv8_1_1_object.html#ace1769b0f3b86bfe9fda1010916360ee) in a way compatible across supported versions of V8.

Signature:

```c++
Nan::Maybe<bool> Nan::SetPrivate(v8::Local<v8::Object> object, v8::Local<v8::String> key, v8::Local<v8::Value> value);
```
<a name="api_nan_delete_private"></a>
### Nan::DeletePrivate()
A helper method for calling [`v8::Object#DeletePrivate()`](https://v8docs.nodesource.com/node-7.2/db/d85/classv8_1_1_object.html#a138bb32a304f3982be02ad499693b8fd) in a way compatible across supported versions of V8.
Signature:
```c++
Nan::Maybe<bool> Nan::DeletePrivate(v8::Local<v8::Object> object, v8::Local<v8::String> key);
```

<a name="api_nan_make_maybe"></a>
### Nan::MakeMaybe()

Expand Down
34 changes: 1 addition & 33 deletions nan.h
Original file line number Diff line number Diff line change
Expand Up @@ -2195,39 +2195,7 @@ inline void SetCallAsFunctionHandler(

//=== HiddenValue/Private ======================================================

inline v8::Local<v8::Value> GetPrivate(
v8::Local<v8::Object> object,
v8::Local<v8::String> key) {
#if (NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION)
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
v8::Local<v8::Value> value;
v8::Maybe<bool> result = object->HasPrivate(context, private_key);
if (!result.FromMaybe(false))
return v8::Local<v8::Value>();
if (object->GetPrivate(context, private_key).ToLocal(&value))
return value;
return v8::Local<v8::Value>();
#else
return object->GetHiddenValue(key);
#endif
}

inline void SetPrivate(
v8::Local<v8::Object> object,
v8::Local<v8::String> key,
v8::Local<v8::Value> value) {
#if (NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION)
if (value.IsEmpty()) return;
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
object->SetPrivate(context, private_key, value);
#else
object->SetHiddenValue(key, value);
#endif
}
#include "nan_private.h" // NOLINT(build/include)

//=== Export ==================================================================

Expand Down
68 changes: 68 additions & 0 deletions nan_private.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*********************************************************************
* NAN - Native Abstractions for Node.js
*
* Copyright (c) 2016 NAN contributors
*
* MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
********************************************************************/

#ifndef NAN_PRIVATE_H_
#define NAN_PRIVATE_H_

inline Maybe<bool>
HasPrivate(v8::Local<v8::Object> object, v8::Local<v8::String> key) {
HandleScope scope;
#if NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION
v8::Isolate *isolate = v8::Isolate::GetCurrent();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
return object->HasPrivate(context, private_key);
#else
return Just(!object->GetHiddenValue(key).IsEmpty());
#endif
}

inline MaybeLocal<v8::Value>
GetPrivate(v8::Local<v8::Object> object, v8::Local<v8::String> key) {
HandleScope scope;
#if NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION
v8::Isolate *isolate = v8::Isolate::GetCurrent();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
return object->GetPrivate(context, private_key);
#else
v8::Local<v8::Value> v = object->GetHiddenValue(key);
v8::Local<v8::Value> def = Undefined();
return MaybeLocal<v8::Value>(v.IsEmpty() ? def : v);
#endif
}

inline Maybe<bool> SetPrivate(
v8::Local<v8::Object> object,
v8::Local<v8::String> key,
v8::Local<v8::Value> value) {
#if NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION
HandleScope scope;
v8::Isolate *isolate = v8::Isolate::GetCurrent();
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
return object->SetPrivate(context, private_key, value);
#else
return Just(object->SetHiddenValue(key, value));
#endif
}

inline Maybe<bool> DeletePrivate(
v8::Local<v8::Object> object,
v8::Local<v8::String> key) {
#if NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION
v8::Isolate *isolate = v8::Isolate::GetCurrent();
v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
return object->DeletePrivate(isolate->GetCurrentContext(), private_key);
#else
return Just(object->DeleteHiddenValue(key));
#endif
}

#endif // NAN_PRIVATE_H_

4 changes: 4 additions & 0 deletions test/binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,8 @@
"target_name" : "typedarrays"
, "sources" : [ "cpp/typedarrays.cpp" ]
}
, {
"target_name" : "private"
, "sources" : [ "cpp/private.cpp" ]
}
]}
85 changes: 85 additions & 0 deletions test/cpp/private.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*********************************************************************
* NAN - Native Abstractions for Node.js
*
* Copyright (c) 2016 NAN contributors
*
* MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
********************************************************************/

#include <nan.h>

using namespace Nan; // NOLINT(build/namespaces)

NAN_METHOD(HasPrivateYes) {
v8::Local<v8::Object> object = New<v8::Object>();
v8::Local<v8::String> key = New("key").ToLocalChecked();
v8::Local<v8::String> value = New("value").ToLocalChecked();
Maybe<bool> mb = SetPrivate(object, key, value);
bool v1 = mb.IsJust() ? mb.FromJust() : false;
mb = HasPrivate(object, key);
bool v2 = mb.IsJust() ? mb.FromJust() : false;
MaybeLocal<v8::Value> mv = GetPrivate(object, key);
bool v3 = mv.IsEmpty() ? false :
!strcmp(*Utf8String(mv.ToLocalChecked()), "value");
info.GetReturnValue().Set(v1 && v2 && v3);
}

NAN_METHOD(HasPrivateNo) {
v8::Local<v8::Object> object = New<v8::Object>();
Maybe<bool> mb = HasPrivate(object, New("key").ToLocalChecked());
bool v1 = mb.IsJust() ? !mb.FromJust() : false;
MaybeLocal<v8::Value> q = GetPrivate(object, New("key").ToLocalChecked());
bool v2 = !q.IsEmpty() ? q.ToLocalChecked()->IsUndefined() : false;
info.GetReturnValue().Set(v1 && v2);
}

NAN_METHOD(DeletePrivateNo) {
v8::Local<v8::Object> object = New<v8::Object>();
v8::Local<v8::String> key = New("key").ToLocalChecked();
v8::Local<v8::String> value = New("value").ToLocalChecked();
Maybe<bool> mb = DeletePrivate(object, key);
bool v1 = mb.IsJust() ? mb.FromJust() : false;
mb = SetPrivate(object, key, value);
bool v2 = mb.IsJust() ? mb.FromJust() : false;
mb = DeletePrivate(object, key);
bool v3 = mb.IsJust() ? mb.FromJust() : false;
info.GetReturnValue().Set(v1 && v2 && v3);
}

NAN_METHOD(NoConflict) {
v8::Local<v8::Object> object = New<v8::Object>();
v8::Local<v8::String> key = New("key").ToLocalChecked();
v8::Local<v8::String> value = New("value").ToLocalChecked();
v8::Local<v8::String> other_value = New("other_value").ToLocalChecked();
SetPrivate(object, key, value);
Set(object, key, other_value);
v8::Local<v8::Value> got = GetPrivate(object, key).ToLocalChecked();
bool v1 = got.As<v8::String>()->StrictEquals(value);
v8::Local<v8::Value> got_other = Get(object, key).ToLocalChecked();
bool v2 = got_other->StrictEquals(other_value);
DeletePrivate(object, key);
got_other = Get(object, key).ToLocalChecked();
bool v3 = got_other->StrictEquals(other_value);
info.GetReturnValue().Set(v1 && v2 && v3);
}

NAN_MODULE_INIT(Init) {
Set(target
, New<v8::String>("hasPrivateYes").ToLocalChecked()
, GetFunction(New<v8::FunctionTemplate>(HasPrivateYes)).ToLocalChecked()
);
Set(target
, New<v8::String>("hasPrivateNo").ToLocalChecked()
, GetFunction(New<v8::FunctionTemplate>(HasPrivateNo)).ToLocalChecked()
);
Set(target
, New<v8::String>("deletePrivateNo").ToLocalChecked()
, GetFunction(New<v8::FunctionTemplate>(DeletePrivateNo)).ToLocalChecked()
);
Set(target
, New<v8::String>("noConflict").ToLocalChecked()
, GetFunction(New<v8::FunctionTemplate>(NoConflict)).ToLocalChecked()
);
}

NODE_MODULE(private, Init)
23 changes: 23 additions & 0 deletions test/js/private-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*********************************************************************
* NAN - Native Abstractions for Node.js
*
* Copyright (c) 2016 NAN contributors
*
* MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
********************************************************************/

const test = require('tap').test
, testRoot = require('path').resolve(__dirname, '..')
, bindings = require('bindings')({ module_root: testRoot, bindings: 'private' });

test('private', function (t) {
t.plan(8);
t.type(bindings.hasPrivateYes, 'function');
t.type(bindings.hasPrivateNo, 'function');
t.type(bindings.deletePrivateNo, 'function');
t.type(bindings.noConflict, 'function');
t.ok(bindings.hasPrivateYes());
t.ok(bindings.hasPrivateNo());
t.ok(bindings.deletePrivateNo());
t.ok(bindings.noConflict());
});

0 comments on commit a86255c

Please sign in to comment.