Skip to content
This repository was archived by the owner on Dec 4, 2023. It is now read-only.

Commit 60f6069

Browse files
committed
Move object wrapping for Object callbacks to a separate class
1 parent 7491cc6 commit 60f6069

5 files changed

Lines changed: 146 additions & 93 deletions

File tree

ext/v8/object.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ namespace rr {
9090
return Bool::Maybe(object->SetAccessor(
9191
context,
9292
Name(name),
93-
&PropertyCallbackInfo::Value::invoke,
94-
RTEST(setter) ? &PropertyCallbackInfo::Void::invoke : 0,
95-
v8::MaybeLocal<v8::Value>(PropertyCallbackInfo::Base<v8::Value>::wrapData(isolate, getter, setter, data)),
93+
&PropertyCallback::invokeGetter,
94+
RTEST(setter) ? &PropertyCallback::invokeSetter : 0,
95+
v8::MaybeLocal<v8::Value>(PropertyCallback::wrapData(isolate, getter, setter, data)),
9696
Enum<v8::AccessControl>(settings, v8::DEFAULT),
9797
Enum<v8::PropertyAttribute>(attribute, v8::None)
9898
));

ext/v8/property-callback-info.h

Lines changed: 4 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// -*- mode: c++ -*-
2-
#ifndef RR_PROPERTY_CALLBACK_H
3-
#define RR_PROPERTY_CALLBACK_H
2+
#ifndef RR_PROPERTY_CALLBACK_INFO_H
3+
#define RR_PROPERTY_CALLBACK_INFO_H
44

55
namespace rr {
66

@@ -16,30 +16,6 @@ namespace rr {
1616

1717
inline Base(VALUE self) : Wrapper<v8::PropertyCallbackInfo<T>>(self) {}
1818

19-
/**
20-
* Package up the callback data for this object so that it can
21-
* invoke Ruby callables.
22-
*
23-
* Each accessor can have one `v8::Value` associated with it
24-
* that is passed to the `SetAccessor` method. To support this
25-
* same API from ruby, we take the passed data constructor *and*
26-
* the callbacks and store them *both* in a single `v8::Object`
27-
* which we use for the C++ level callback data.
28-
*/
29-
static v8::Local<v8::Value> wrapData(v8::Isolate* isolate, VALUE r_getter, VALUE r_setter, VALUE r_data) {
30-
v8::Local<v8::Object> holder = v8::Object::New(isolate);
31-
32-
v8::Local<v8::String> getter_key = v8::String::NewFromUtf8(isolate, "rr::getter");
33-
v8::Local<v8::String> setter_key = v8::String::NewFromUtf8(isolate, "rr::setter");
34-
v8::Local<v8::String> data_key = v8::String::NewFromUtf8(isolate, "rr::data");
35-
36-
holder->SetHiddenValue(getter_key, External::wrap(isolate, r_getter));
37-
holder->SetHiddenValue(setter_key, External::wrap(isolate, r_setter));
38-
holder->SetHiddenValue(data_key, rr::Value(r_data));
39-
40-
return holder;
41-
}
42-
4319
static VALUE This(VALUE self) {
4420
Base<T> info(self);
4521
Locker lock(info->GetIsolate());
@@ -51,11 +27,7 @@ namespace rr {
5127
Isolate isolate(info->GetIsolate());
5228
Locker lock(isolate);
5329

54-
v8::Local<v8::Object> holder = v8::Local<v8::Object>::Cast<v8::Value>(info->Data());
55-
v8::Local<v8::String> data_key = v8::String::NewFromUtf8(isolate, "rr::data");
56-
v8::Local<v8::Value> data(holder->GetHiddenValue(data_key));
57-
58-
return rr::Value::handleToRubyObject(info->GetIsolate(), data);
30+
return PropertyCallback::unwrapData(isolate, info->Data()) ;
5931
}
6032

6133
static VALUE GetIsolate(VALUE self) {
@@ -73,32 +45,6 @@ namespace rr {
7345

7446
inline Value(VALUE self) : Base<v8::Value>(self) {}
7547

76-
/**
77-
* Call the Ruby code associated with this callback.
78-
*
79-
* Unpack the Ruby code, and the callback data from the C++
80-
* callback data, and then invoke that code.
81-
*
82-
* Note: This function implements the `v8::AccessorNameGetterCallback` API.
83-
*/
84-
static void invoke(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
85-
v8::Isolate* isolate = info.GetIsolate();
86-
v8::Local<v8::Object> holder = v8::Local<v8::Object>::Cast<v8::Value>(info.Data());
87-
v8::Local<v8::String> callback_key = v8::String::NewFromUtf8(isolate, "rr::getter");
88-
89-
VALUE code(External::unwrap(holder->GetHiddenValue(callback_key)));
90-
91-
VALUE rb_property;
92-
if (property->IsSymbol()) {
93-
rb_property = Symbol(isolate, v8::Local<v8::Symbol>::Cast(property));
94-
} else {
95-
rb_property = String(isolate, property->ToString());
96-
}
97-
98-
Unlocker unlock(info.GetIsolate());
99-
rb_funcall(code, rb_intern("call"), 2, rb_property, (VALUE)Value(info));
100-
}
101-
10248
static VALUE GetReturnValue(VALUE self) {
10349
Value info(self);
10450
Locker lock(info->GetIsolate());
@@ -124,38 +70,6 @@ namespace rr {
12470

12571
inline Void(VALUE self) : Base<void>(self) {}
12672

127-
/**
128-
* Call the Ruby code associated with this callback.
129-
*
130-
* Unpack the Ruby code, and the callback data from the C++
131-
* callback data, and then invoke that code.
132-
*
133-
* Note: This function implements the `v8::AccessorNameSetterCallback` API.
134-
*/
135-
static void invoke(v8::Local<v8::Name> property, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info) {
136-
v8::Isolate* isolate = info.GetIsolate();
137-
138-
v8::Local<v8::Object> holder = v8::Local<v8::Object>::Cast<v8::Value>(info.Data());
139-
v8::Local<v8::String> callback_key = v8::String::NewFromUtf8(isolate, "rr::setter");
140-
141-
VALUE code(External::unwrap(holder->GetHiddenValue(callback_key)));
142-
143-
VALUE rb_property;
144-
if (property->IsSymbol()) {
145-
rb_property = Symbol(isolate, v8::Local<v8::Symbol>::Cast(property));
146-
} else {
147-
rb_property = String(isolate, property->ToString());
148-
}
149-
150-
Unlocker unlock(info.GetIsolate());
151-
rb_funcall(
152-
code, rb_intern("call"), 3,
153-
rb_property,
154-
(VALUE)rr::Value::handleToRubyObject(isolate, value),
155-
(VALUE)Void(info)
156-
);
157-
}
158-
15973
static VALUE GetReturnValue(VALUE self) {
16074
Value info(self);
16175
Locker lock(info->GetIsolate());
@@ -187,4 +101,4 @@ namespace rr {
187101

188102
}
189103

190-
#endif /* RR_PROPERTY_CALLBACK_H */
104+
#endif /* RR_PROPERTY_CALLBACK_INFO_H */

ext/v8/property-callback.cc

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#include "rr.h"
2+
3+
namespace rr {
4+
5+
v8::Local<v8::Value> PropertyCallback::wrapData(v8::Isolate* isolate, VALUE r_getter, VALUE r_setter, VALUE r_data) {
6+
v8::Local<v8::Object> holder = v8::Object::New(isolate);
7+
8+
v8::Local<v8::String> getter_key = v8::String::NewFromUtf8(isolate, "rr::getter");
9+
v8::Local<v8::String> setter_key = v8::String::NewFromUtf8(isolate, "rr::setter");
10+
v8::Local<v8::String> data_key = v8::String::NewFromUtf8(isolate, "rr::data");
11+
12+
holder->SetHiddenValue(getter_key, External::wrap(isolate, r_getter));
13+
holder->SetHiddenValue(setter_key, External::wrap(isolate, r_setter));
14+
holder->SetHiddenValue(data_key, rr::Value(r_data));
15+
16+
return holder;
17+
}
18+
19+
VALUE PropertyCallback::unwrapData(v8::Isolate* isolate, v8::Local<v8::Value> value) {
20+
v8::Local<v8::Object> holder = v8::Local<v8::Object>::Cast<v8::Value>(value);
21+
v8::Local<v8::String> data_key = v8::String::NewFromUtf8(isolate, "rr::data");
22+
23+
return Value(isolate, holder->GetHiddenValue(data_key));
24+
}
25+
26+
VALUE PropertyCallback::unwrapGetter(v8::Isolate* isolate, v8::Local<v8::Value> value) {
27+
v8::Local<v8::Object> holder = v8::Local<v8::Object>::Cast<v8::Value>(value);
28+
v8::Local<v8::String> callback_key = v8::String::NewFromUtf8(isolate, "rr::getter");
29+
30+
return External::unwrap(holder->GetHiddenValue(callback_key));
31+
}
32+
33+
VALUE PropertyCallback::unwrapSetter(v8::Isolate* isolate, v8::Local<v8::Value> value) {
34+
v8::Local<v8::Object> holder = v8::Local<v8::Object>::Cast<v8::Value>(value);
35+
v8::Local<v8::String> callback_key = v8::String::NewFromUtf8(isolate, "rr::setter");
36+
37+
return External::unwrap(holder->GetHiddenValue(callback_key));
38+
}
39+
40+
void PropertyCallback::invokeGetter(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
41+
v8::Isolate* isolate = info.GetIsolate();
42+
43+
VALUE code(unwrapGetter(isolate, info.Data()));
44+
45+
VALUE rb_property;
46+
if (property->IsSymbol()) {
47+
rb_property = Symbol(isolate, v8::Local<v8::Symbol>::Cast(property));
48+
} else {
49+
rb_property = String(isolate, property->ToString());
50+
}
51+
52+
Unlocker unlock(info.GetIsolate());
53+
rb_funcall(code, rb_intern("call"), 2, rb_property, (VALUE)PropertyCallbackInfo::Value(info));
54+
}
55+
56+
void PropertyCallback::invokeSetter(v8::Local<v8::Name> property, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info) {
57+
v8::Isolate* isolate = info.GetIsolate();
58+
59+
VALUE code(unwrapSetter(isolate, info.Data()));
60+
61+
VALUE rb_property;
62+
if (property->IsSymbol()) {
63+
rb_property = Symbol(isolate, v8::Local<v8::Symbol>::Cast(property));
64+
} else {
65+
rb_property = String(isolate, property->ToString());
66+
}
67+
68+
Unlocker unlock(info.GetIsolate());
69+
rb_funcall(
70+
code, rb_intern("call"), 3,
71+
rb_property,
72+
(VALUE)Value(isolate, value),
73+
(VALUE)PropertyCallbackInfo::Void(info)
74+
);
75+
}
76+
77+
}

ext/v8/property-callback.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// -*- mode: c++ -*-
2+
#ifndef RR_PROPERTY_CALLBACK_H
3+
#define RR_PROPERTY_CALLBACK_H
4+
5+
namespace rr {
6+
7+
class PropertyCallback {
8+
public:
9+
10+
/**
11+
* Package up the callback data for this object so that it can
12+
* invoke Ruby callables.
13+
*
14+
* Each accessor can have one `v8::Value` associated with it
15+
* that is passed to the `SetAccessor` method. To support this
16+
* same API from ruby, we take the passed data constructor *and*
17+
* the callbacks and store them *both* in a single `v8::Object`
18+
* which we use for the C++ level callback data.
19+
*/
20+
static v8::Local<v8::Value> wrapData(v8::Isolate* isolate, VALUE r_getter, VALUE r_setter, VALUE r_data);
21+
22+
/**
23+
* Get the data packaged in the object.
24+
*/
25+
static VALUE unwrapData(v8::Isolate* isolate, v8::Local<v8::Value> holder);
26+
27+
/**
28+
* Get the getter packaged in the object.
29+
*/
30+
static VALUE unwrapGetter(v8::Isolate* isolate, v8::Local<v8::Value> holder);
31+
32+
/**
33+
* Get the setter packaged in the object.
34+
*/
35+
static VALUE unwrapSetter(v8::Isolate* isolate, v8::Local<v8::Value> holder);
36+
37+
/**
38+
* Call the Ruby code associated with this callback.
39+
*
40+
* Unpack the Ruby code, and the callback data from the C++
41+
* callback data, and then invoke that code.
42+
*
43+
* Note: This function implements the `v8::AccessorNameGetterCallback` API.
44+
*/
45+
static void invokeGetter(v8::Local<v8::Name> property, const v8::PropertyCallbackInfo<v8::Value>& info);
46+
47+
/**
48+
* Call the Ruby code associated with this callback.
49+
*
50+
* Unpack the Ruby code, and the callback data from the C++
51+
* callback data, and then invoke that code.
52+
*
53+
* Note: This function implements the `v8::AccessorNameSetterCallback` API.
54+
*/
55+
static void invokeSetter(v8::Local<v8::Name> property, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info);
56+
57+
};
58+
59+
}
60+
61+
#endif /* RR_PROPERTY_CALLBACK_H */

ext/v8/rr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ inline VALUE not_implemented(const char* message) {
5353

5454
#include "object.h"
5555
#include "return-value.h"
56+
#include "property-callback.h"
5657
#include "property-callback-info.h"
5758
#include "array.h"
5859

0 commit comments

Comments
 (0)