Skip to content

Commit 5192286

Browse files
authored
Support static field for class (#24)
1 parent f670177 commit 5192286

2 files changed

Lines changed: 69 additions & 1 deletion

File tree

examples/basic/src/class.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const Test = struct {
99
const TestWithInit = struct {
1010
name: []u8,
1111
age: i32,
12+
pub const hello = "Hello";
1213

1314
pub fn init(age: i32, name: []u8) TestWithInit {
1415
return TestWithInit{ .name = name, .age = age };

src/napi/wrapper/class.zig

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ var class_constructors: std.StringHashMap(napi.napi_value) = std.StringHashMap(n
1111

1212
pub fn ClassWrapper(comptime T: type, comptime HasInit: bool) type {
1313
const type_info = @typeInfo(T);
14+
1415
if (type_info != .@"struct") {
1516
@compileError("Class() only support struct type");
1617
}
@@ -143,9 +144,31 @@ pub fn ClassWrapper(comptime T: type, comptime HasInit: bool) type {
143144
}
144145
}
145146

147+
// Helper function to check if a declaration is a const field
148+
fn isConstDecl(comptime decl_name: []const u8) bool {
149+
if (!@hasDecl(T, decl_name)) return false;
150+
const decl_type = @TypeOf(@field(T, decl_name));
151+
const decl_type_info = @typeInfo(decl_type);
152+
// Check if it's not a function and not a type
153+
return decl_type_info != .@"fn" and decl_type_info != .type;
154+
}
155+
156+
// Count const declarations at compile time
157+
fn countConstDecls() usize {
158+
var count: usize = 0;
159+
for (decls) |decl| {
160+
if (comptime isConstDecl(decl.name)) {
161+
count += 1;
162+
}
163+
}
164+
return count;
165+
}
166+
146167
fn define_class(env: napi.napi_env) !napi.napi_value {
168+
// Count instance properties and methods
147169
comptime var property_count: usize = fields.len;
148170

171+
// Count methods
149172
inline for (decls) |decl| {
150173
const decl_type = @TypeOf(@field(T, decl.name));
151174
if (@typeInfo(decl_type) == .@"fn") {
@@ -158,9 +181,14 @@ pub fn ClassWrapper(comptime T: type, comptime HasInit: bool) type {
158181
}
159182
}
160183

161-
var properties: [property_count]napi.napi_property_descriptor = undefined;
184+
// Add const declarations count
185+
const const_count = comptime countConstDecls();
186+
const total_property_count = comptime property_count + const_count;
187+
188+
var properties: [total_property_count]napi.napi_property_descriptor = undefined;
162189
var prop_idx: usize = 0;
163190

191+
// Process instance fields
164192
inline for (fields) |field| {
165193
const FieldAccessor = struct {
166194
fn getter(getter_env: napi.napi_env, info: napi.napi_callback_info) callconv(.c) napi.napi_value {
@@ -203,6 +231,45 @@ pub fn ClassWrapper(comptime T: type, comptime HasInit: bool) type {
203231
prop_idx += 1;
204232
}
205233

234+
// Process const declarations as static value properties
235+
// Following napi-rs pattern: use value field with static attribute
236+
inline for (decls) |decl| {
237+
if (comptime isConstDecl(decl.name)) {
238+
const const_value = @field(T, decl.name);
239+
240+
// Create a static value property descriptor
241+
// The value is converted at define_class time
242+
const StaticValueHolder = struct {
243+
var cached_value: ?napi.napi_value = null;
244+
245+
fn getValue(holder_env: napi.napi_env) napi.napi_value {
246+
if (cached_value) |val| {
247+
return val;
248+
}
249+
const val = Napi.to_napi_value(holder_env, const_value, decl.name) catch return null;
250+
cached_value = val;
251+
return val;
252+
}
253+
};
254+
255+
// Get the static value
256+
const static_value = StaticValueHolder.getValue(env);
257+
258+
properties[prop_idx] = napi.napi_property_descriptor{
259+
.utf8name = @ptrCast(decl.name.ptr),
260+
.name = null,
261+
.method = null,
262+
.getter = null,
263+
.setter = null,
264+
.value = static_value,
265+
.attributes = napi.napi_static | napi.napi_enumerable,
266+
.data = null,
267+
};
268+
prop_idx += 1;
269+
}
270+
}
271+
272+
// Process methods
206273
inline for (decls) |decl| {
207274
const decl_type = @TypeOf(@field(T, decl.name));
208275
if (@typeInfo(decl_type) == .@"fn") {

0 commit comments

Comments
 (0)