Meta types ᴾᴴᴾ - chung-leong/zigar GitHub Wiki
JavaScript | PHP
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. 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 you can obtain the right form for a given situation:
$slice->__string => "Hello"
$slice->__type_array => Uint8Array(5) [ 104, 101, 108, 108, 111 ]
$slice->__clamped_array => Uint8ClampedArray(5) [ 104, 101, 108, 108, 111 ]
$slice->__plain => [ 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 typed_array = string;
pub const clamped_array = 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 == .clamped_array;
}
pub fn isDeclTypedArray(comptime T: type, comptime name: std.meta.DeclEnum(T)) bool {
return T == module and name == .typed_array;
}
pub fn isDeclPlain(comptime T: type, comptime name: std.meta.DeclEnum(T)) bool {
return T == module and name == .plain;
}
};
<?php
$m = zigar_use(__DIR__ . '/meta-type-example-1.zig');
print_r([
'string' => $m->string,
'clamped_array' => $m->clamped_array,
'typed_array' => $m->typed_array,
'plain' => $m->plain,
]);
Array
(
[string] => Hello
[clamped_array] => Uint8ClampedArray Object
(
[ITEMS](/chung-leong/zigar/wiki/ITEMS) => Array
(
[0] => 72
[1] => 101
[2] => 108
[3] => 108
[4] => 111
)
[buffer] => ArrayBuffer Object
(
[byteLength] => 5
[detached] =>
[readOnly] => 1
)
[byteLength] => 5
[byteOffset] => 0
[length] => 5
)
[typed_array] => Uint8Array Object
(
[ITEMS](/chung-leong/zigar/wiki/ITEMS) => Array
(
[0] => 72
[1] => 101
[2] => 108
[3] => 108
[4] => 111
)
[buffer] => ArrayBuffer Object
(
[byteLength] => 5
[detached] =>
[readOnly] => 1
)
[byteLength] => 5
[byteOffset] => 0
[length] => 5
)
[plain] => Array
(
[0] => 72
[1] => 101
[2] => 108
[3] => 108
[4] => 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 typed_array: []const f32 = &.{ 1, 2, 3, 4 };
pub const @"meta(zigar)" = struct {
pub fn isDeclString(comptime T: type, comptime _: std.meta.DeclEnum(T)) bool {
return false;
}
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;
}
};
<?php
$m = zigar_use(__DIR__ . '/meta-type-example-2.zig');
print_r([
'string' => $m->string,
'typed_array' => $m->typed_array,
]);
Array
(
[string] => Uint8ClampedArray Object
(
[ITEMS](/chung-leong/zigar/wiki/ITEMS) => Array
(
[0] => 72
[1] => 101
[2] => 108
[3] => 108
[4] => 111
)
[buffer] => ArrayBuffer Object
(
[byteLength] => 5
[detached] =>
[readOnly] => 1
)
[byteLength] => 5
[byteOffset] => 0
[length] => 5
)
[typed_array] => Float32Array Object
(
[ITEMS](/chung-leong/zigar/wiki/ITEMS) => Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
[buffer] => ArrayBuffer Object
(
[byteLength] => 16
[detached] =>
[readOnly] => 1
)
[byteLength] => 16
[byteOffset] => 0
[length] => 4
)
)
In the example above, because isDeclString() returns false, string becomes a
Uint8ClampedArray as that's another possible way to representing a slice of u8 and
isDeclClampedArray() return true. The first function that is called for an f32 slice is
isDeclTypedArray() on the other hand so typed_array becomes a Float32Array.
The isFieldXXX and isArgumentXXX sets of functions operate in an analogous manner for assigning
meta-type to fields and callback arguments.