Meta types - chung-leong/zigar GitHub Wiki
Certain Zig types can be represented in JavaScript in multiple ways. The best example is
[]const u8. Very often the type is used to store a text string. At times it's used to store
opaque binary data, in which case a
Uint8Array
would make better sense. If the u8s are pixel values, then perhaps a
Uint8ClampedArray
is better, since that's what the browser's
ImageData expects. Finally,
the []const u8 could simply be a series of positive numbers that happen to never exceed 255.
By default, Zigar gives you a Zig data object. Through its speical properties and methods, you can obtain the right form for a given situation:
slice.string => "Hello"
slice.typeArray => Uint8Array(5) [ 104, 101, 108, 108, 111 ]
slice.clampedArray => Uint8ClampedArray(5) [ 104, 101, 108, 108, 111 ]
slice.valueOf() => [ 104, 101, 108, 108, 111 ]
To make the transition from Zig to JS more seamless, you can tell Zigar to automatically perform the above operation for you using its meta-type mechanism. It's based on functions declared in a namespace under a special name:
const std = @import("std");
pub const string: []const u8 = "Hello";
pub const typedArray = string;
pub const clampedArray = string;
pub const plain = string;
const module = @This();
pub const @"meta(zigar)" = struct {
pub fn isDeclString(comptime T: type, comptime name: std.meta.DeclEnum(T)) bool {
return T == module and name == .string;
}
pub fn isDeclClampedArray(comptime T: type, comptime name: std.meta.DeclEnum(T)) bool {
return T == module and name == .clampedArray;
}
pub fn isDeclTypedArray(comptime T: type, comptime name: std.meta.DeclEnum(T)) bool {
return T == module and name == .typedArray;
}
pub fn isDeclPlain(comptime T: type, comptime name: std.meta.DeclEnum(T)) bool {
return T == module and name == .plain;
}
};
import { clampedArray, plain, string, typedArray } from './meta-type-example-1.zig';
console.log({ string, clampedArray, typedArray, plain });
{
string: 'Hello',
clampedArray: Uint8ClampedArray(5) [ 72, 101, 108, 108, 111 ],
typedArray: Uint8Array(5) [ 72, 101, 108, 108, 111 ],
plain: [ 72, 101, 108, 108, 111 ]
}
If you're unfamiliar with Zig's @"some name" syntax, all it does is let you use non-alphanumeric
characters in an identifier.
@"meta(zigar) must be in the root namespace. Its functions can impact on all namespaces in-use,
including those in std.
During the export process, these functions are called in the same order as they're listed in the
example above and below. The first to return true determines the meta type:
const std = @import("std");
pub const string: []const u8 = "Hello";
pub const typedArray: []const f32 = &.{ 1, 2, 3, 4 };
const module = @This();
pub const @"meta(zigar)" = struct {
pub fn isDeclString(comptime T: type, comptime _: std.meta.DeclEnum(T)) bool {
return true;
}
pub fn isDeclClampedArray(comptime T: type, comptime _: std.meta.DeclEnum(T)) bool {
return true;
}
pub fn isDeclTypedArray(comptime T: type, comptime _: std.meta.DeclEnum(T)) bool {
return true;
}
pub fn isDeclPlain(comptime T: type, comptime _: std.meta.DeclEnum(T)) bool {
return true;
}
};
import { string, typedArray } from './meta-type-example-2.zig';
console.log({ string, typedArray });
{ string: 'Hello', typedArray: Float32Array(4) [ 1, 2, 3, 4 ] }
The isFieldXXX and isArgumentXXX sets of functions operate in an analogous manner for assigning
meta-type to fields and callback arguments.