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

Commit b9bbbec

Browse files
committed
add documentation for wrapper class
1 parent 0681a98 commit b9bbbec

1 file changed

Lines changed: 113 additions & 0 deletions

File tree

ext/v8/wrapper.h

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// -*- mode: c++ -*-
2+
#ifndef RR_WRAPPER_H
3+
#define RR_WRAPPER_H
4+
5+
namespace rr {
6+
7+
/**
8+
* A wrapper provides the ability to create a temporary reference to
9+
* a stack-allocated value so that it can be passed to ruby. This is
10+
* normally the case for a callback parameter, where you will be
11+
* calling into Ruby from C++. Ruby should not call methods on this
12+
* object outside the scope of the function call. E.g.
13+
*
14+
* class MyObjectWrapper : public Wrapper<MyObject> {
15+
* // [...]
16+
* };
17+
*
18+
* MyObject foo;
19+
* rb_funcall(object, rb_intern("count"), 1, MyObjectWrapper(foo));
20+
* // ruby should not use anymore, it might crash
21+
*
22+
* Note: This seems dangerous in practice, but since it is only ever
23+
* used by the low-level api, wrapper objects do not escape into the
24+
* wild, and so aren't used beyond their normal lifetime on the C++
25+
* stack.
26+
*
27+
* We may add a destructor that invalidates the pointer,
28+
* and would throw an exception if you tried to use this object at
29+
* some after it leaves scope.
30+
*/
31+
template <class T>
32+
class Wrapper {
33+
public:
34+
/**
35+
* The Ruby Class of this Wrapper
36+
*/
37+
static VALUE Class;
38+
39+
/**
40+
* Package up this wrapper so that it can be accessed from
41+
* Ruby. Use this just before passing to a ruby call. E.g.
42+
*
43+
* MyObject object;
44+
* rb_funcall(thing, rb_intern("take"), 1, MyObjectWrapper(object))
45+
*/
46+
Wrapper(T content) : container(new Container(content)) {}
47+
48+
/**
49+
* Access the underlying object when it has been passed from Ruby
50+
* to a C++ function. E.g.
51+
*
52+
* SomeFunction(VALUE self) {
53+
* MyObjectWrapper object(self);
54+
* }
55+
*/
56+
Wrapper(VALUE self) : container(Container::unwrap(self)) {}
57+
58+
/**
59+
* Access the wrapped value via pointer dereference:
60+
*
61+
* MyObjectWrapper object(self);
62+
* object->SomeMethod();
63+
*/
64+
inline T* operator ->() {
65+
return &container->content;
66+
}
67+
68+
/**
69+
* Convert this Wrapper into a Ruby VALUE so that it can be
70+
* transparently passed to methods expecting a VALUE. This means
71+
* you can do things like:
72+
*
73+
* MyObjectWrapper wrapper(self);
74+
* rb_inspect(wrapper);
75+
*
76+
* Even though MyObjectWrapper is not a VALUE
77+
*/
78+
inline operator VALUE() {
79+
return Container::wrap(container, Class);
80+
}
81+
82+
/**
83+
* This is the struct that will be held inside the Ruby T_DATA
84+
* object. It mainly serves to keep a reference to the stack value.
85+
*/
86+
struct Container {
87+
88+
Container(T content_) : content(content_) {}
89+
90+
static inline VALUE wrap(Container* container, VALUE rb_class) {
91+
return Data_Wrap_Struct(rb_class, 0, &destroy, container);
92+
}
93+
94+
static inline Container* unwrap(VALUE object) {
95+
Container* container;
96+
Data_Get_Struct(object, struct Container, container);
97+
return container;
98+
}
99+
100+
static void destroy(Container* container) {
101+
delete container;
102+
}
103+
T content;
104+
};
105+
106+
Container* container;
107+
};
108+
109+
template <class T>
110+
VALUE Wrapper<T>::Class;
111+
}
112+
113+
#endif /* RR_WRAPPER_H */

0 commit comments

Comments
 (0)