4 Validated struct is C struct wrapper for encapsulation and validity check.
6 * Validated Struct Declaration
7 * Constructors, Destructor, Methods
8 * Ownership of validated struct instance
9 * Case 1: Validated struct instance as local variable
10 * Case 2: Validated struct instance as parameter & return
11 * Case 3: Validated struct instance as member variable of other struct
12 * Case 4: Validated struct instance as data of asynchronous execution
14 # Validated Struct Declaration
20 } IOTJS_VALIDATED_STRUCT(iotjs_myclass_t);
23 Above struct will make the member variable encapsulated by wrapping real members with wrapper like below.
29 } iotjs_myclass_t_impl_t;
32 iotjs_myclass_impl_t unsafe;
33 /* More members for struct validity check exist in debug mode */
41 Only wizards will access the members directly by using `x.unsafe.a`, `x.unafe.b`, ... . Otherwize the members are only accessible with its accessor function.
43 See `src/iotjs_def.h` for more details on real implementation.
45 # Constructors, Destructor, Methods
47 You should create C++-like constructors, destructor and methods with provided accessor. Then you can access the encapsulated member variables using `_this` variable, which has almost same role with C++ `this` keyword.
48 You must call `destroy` for every validated structs you've created.
52 iotjs_myclass_t iotjs_myclass_create(int a) {
53 iotjs_myclass_t instance;
54 IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_myclass_t, &instance);
63 void iotjs_myclass_destroy(iotjs_myclass_t* instance) {
64 IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_myclass_t, instance);
69 int iotjs_myclass_get_a(iotjs_myclass_t* instance) {
70 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_myclass_t, instance);
75 /* Validated struct as local variable */
76 iotjs_myclass_t local_instance = iotjs_myclass_create(3);
77 printf("%d\n", iotjs_myclass_get_a(&local_instance));
78 iotjs_myclass_destroy(&local_instance);
83 # Ownership of validated struct instance
87 * Use `iotjs_classname_t` typed variable if the variable *is* responsible for destruction of instance.
88 * Use `iotjs_classname_t*` typed variable if the variable *is not* responsible for destruction of instance.
90 Below Case 1 ~ Case 4 shows the case-by-case example of the ownership rule.
92 ## Case 1: Validated struct instance as local variable
93 The `local_instance` variable in previous example was the local instance of validated struct.
94 Since `local_instance` should be destructed inside the function scope, `iotjs_myclass_t` type was used.
96 ## Case 2: Validated struct instance as parameter & return
97 Previous example also included the example of validated struct instance as parameter and return.
98 When accessing member variable `a` by calling `iotjs_myclass_get_a()`,
99 `iotjs_myclass_t*` type was used as the parameter type, since it *does not* move the responsibility to destruct the instance.
101 And when returning the newly created instance by calling `iotjs_myclass_create()`,
102 `iotjs_myclass_t` type was used as return type, since it *does* move the responsibility to destruct the instance.
104 ## Case 3: Validated struct instance as member variable of other struct
107 /* Validated struct as member variable of other struct */
110 iotjs_myclass_t member_instance;
111 } IOTJS_VALIDATED_STRUCT(iotjs_otherclass_t)
113 iotjs_otherclass_t iotjs_otherclass_create() {
114 /* Initialization steps for iotjs_otherclass_t */
115 _this->member_instance = iotjs_myclass_create(3);
118 void iotjs_otherclass_destroy() {
119 /* Finalization steps for iotjs_otherclass_t */
120 iotjs_myclass_destroy(&_this->member_instance);
124 In the case above, `iotjs_myclass_t` instance is used as member variable of other class.
125 Since `iotjs_otherclass_t` is responsible for finalizing the `member_instance`,
126 it owns the variable as `iotjs_myclass_t` type, not pointer type.
128 ## Case 4: Validated struct instance as data of asynchronous execution
129 Another usecase would be using validated struct as callback data.
130 Currently, our all asynchronous datas are wrapped with `iotjs_*wrap_t` type,
131 and they are destructed automatically.
135 * Public APIs in iotjs_module_fs.h
139 iotjs_reqwrap_t reqwrap;
141 } IOTJS_VALIDATED_STRUCT(iotjs_fsreqwrap_t);
143 iotjs_fsreqwrap_t* iotjs_fsreqwrap_create(const iotjs_jval_t* jcallback);
144 void iotjs_fsreqwrap_dispatched(iotjs_fsreqwrap_t* fsreqwrap);
147 As you can see, constructor returns the `iotjs_fsreqwrap_t*` type,
148 because it does not pass the responsibility to destruct the return value.
149 It is destructed when request is dispatched, which can be informed by calling `iotjs_fsreqwrap_dispatched()`.
150 The destructor `iotjs_fsreqwrap_destroy()` is hidden in c file.
154 * Implementation in iotjs_module_fs.c
157 iotjs_fsreqwrap_t* iotjs_fsreqwrap_create(const iotjs_jval_t* jcallback) {
158 iotjs_fsreqwrap_t* fsreqwrap = IOTJS_ALLOC(iotjs_fsreqwrap_t);
159 IOTJS_VALIDATED_STRUCT_CONSTRUCTOR(iotjs_fsreqwrap_t, fsreqwrap);
160 iotjs_reqwrap_initialize(&_this->reqwrap, jcallback, (uv_req_t*)&_this->req);
164 static void iotjs_fsreqwrap_destroy(iotjs_fsreqwrap_t* fsreqwrap) { // private function
165 IOTJS_VALIDATED_STRUCT_DESTRUCTOR(iotjs_fsreqwrap_t, fsreqwrap);
166 uv_fs_req_cleanup(&_this->req);
167 iotjs_reqwrap_destroy(&_this->reqwrap);
168 IOTJS_RELEASE(fsreqwrap);
171 void iotjs_fsreqwrap_dispatched(iotjs_fsreqwrap_t* fsreqwrap) {
172 IOTJS_VALIDATED_STRUCT_METHOD(iotjs_fsreqwrap_t, fsreqwrap);
173 iotjs_fsreqwrap_destroy(fsreqwrap);
177 * Use of iotjs_fsreqwrap_t
180 void callback(uv_fs_t* req) {
182 iotjs_fsreqwrap_dispatched(req); /* Call iotjs_*reqwrap_dispatched() when callback called */
185 void request(iotjs_jval_t* jcallback) {
186 iotjs_fsreqwrap_t* wrap = iotjs_fsreqwrap_create(jcallback);
187 uv_fs_request(loop, wrap->req, callback);
191 In the case of tuv request wrapper, `iotjs_*reqwrap_dispatched()` should be called when the request has been dispatched.
192 In the case of tuv handle wrapper, `iotjs_handlewrap_close()` should be called when the handle has been closed.
193 in the case of JavaScript object wrapper, you don't have to do anything because JavaScript engine will call the destructor when the object becomes inaccessible.