263 lines
8.0 KiB
Zig
263 lines
8.0 KiB
Zig
|
|
const std = @import("std");
|
||
|
|
|
||
|
|
pub const Value = union(enum) {
|
||
|
|
pub const Slice = struct {
|
||
|
|
pub const ItemType = enum {
|
||
|
|
uint8,
|
||
|
|
int8,
|
||
|
|
uint16,
|
||
|
|
int16,
|
||
|
|
uint32,
|
||
|
|
int32,
|
||
|
|
uint64,
|
||
|
|
int64,
|
||
|
|
float16,
|
||
|
|
float32,
|
||
|
|
float64,
|
||
|
|
boolval,
|
||
|
|
string,
|
||
|
|
// TODO (cryptodeal): gguf/torch/json (safetensors) in theory support nested arrays;
|
||
|
|
// we should support for the sake of completeness, but we have not yet encountered
|
||
|
|
// a model containing these types.
|
||
|
|
// TODO (cryptodeal): array,
|
||
|
|
};
|
||
|
|
|
||
|
|
item_type: ItemType,
|
||
|
|
data: []u8,
|
||
|
|
|
||
|
|
fn isNestedSlice(comptime T: type) bool {
|
||
|
|
const info = @typeInfo(T);
|
||
|
|
if (info != .Pointer or info.Pointer.size != .Slice) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
var child_info = @typeInfo(info.Pointer.child);
|
||
|
|
while (child_info == .Pointer and child_info.Pointer.size == .Slice) : (child_info = @typeInfo(child_info.Pointer.child)) {}
|
||
|
|
return switch (@TypeOf(child_info)) {};
|
||
|
|
}
|
||
|
|
|
||
|
|
fn fromZigType(comptime T: type) ItemType {
|
||
|
|
return switch (T) {
|
||
|
|
u8 => .uint8,
|
||
|
|
i8 => .int8,
|
||
|
|
u16 => .uint16,
|
||
|
|
i16 => .int16,
|
||
|
|
u32 => .uint32,
|
||
|
|
i32 => .int32,
|
||
|
|
u64 => .uint64,
|
||
|
|
i64 => .int64,
|
||
|
|
f16 => .float16,
|
||
|
|
f32 => .float32,
|
||
|
|
f64 => .float64,
|
||
|
|
bool => .boolval,
|
||
|
|
[]const u8 => .string,
|
||
|
|
else => @panic("Unsupported type for LoaderValue.Slice: " ++ @typeName(T)),
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn toZigType(comptime kind: ItemType) type {
|
||
|
|
return switch (kind) {
|
||
|
|
.uint8 => u8,
|
||
|
|
.int8 => i8,
|
||
|
|
.uint16 => u16,
|
||
|
|
.int16 => i16,
|
||
|
|
.uint32 => u32,
|
||
|
|
.int32 => i32,
|
||
|
|
.uint64 => u64,
|
||
|
|
.int64 => i64,
|
||
|
|
.float16 => f16,
|
||
|
|
.float32 => f32,
|
||
|
|
.float64 => f64,
|
||
|
|
.boolval => bool,
|
||
|
|
.string => []const u8,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn cast(self: *Slice, comptime T: type) []T {
|
||
|
|
if (fromZigType(T) != self.item_type) {
|
||
|
|
@panic("Type mismatch in LoaderValue.Slice cast");
|
||
|
|
}
|
||
|
|
return @as([*]T, @ptrCast(@alignCast(self.data.ptr)))[0..self.data.len];
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// TODO: this is overkill we don't need that many different types
|
||
|
|
// to represent metadata. bool, i64, f64, string are enough (like Json).
|
||
|
|
null,
|
||
|
|
uint8: u8,
|
||
|
|
int8: i8,
|
||
|
|
uint16: u16,
|
||
|
|
int16: i16,
|
||
|
|
uint32: u32,
|
||
|
|
int32: i32,
|
||
|
|
uint64: u64,
|
||
|
|
int64: i64,
|
||
|
|
float16: f16,
|
||
|
|
float32: f32,
|
||
|
|
float64: f64,
|
||
|
|
bigint: std.math.big.int.Managed,
|
||
|
|
boolval: bool,
|
||
|
|
array: Slice,
|
||
|
|
string: []const u8,
|
||
|
|
|
||
|
|
pub fn wrap(x: anytype) Value {
|
||
|
|
const tag = switch (@TypeOf(x)) {
|
||
|
|
u8 => .uint8,
|
||
|
|
i8 => .int8,
|
||
|
|
u16 => .uint16,
|
||
|
|
i16 => .int16,
|
||
|
|
u32 => .uint32,
|
||
|
|
i32 => .int32,
|
||
|
|
u64 => .uint64,
|
||
|
|
i64 => .int64,
|
||
|
|
f16 => .float16,
|
||
|
|
f32 => .float32,
|
||
|
|
f64 => .float64,
|
||
|
|
bool => .boolval,
|
||
|
|
[]const u8 => .string,
|
||
|
|
else => @panic("Unsupported type for zml.aio.Value: " ++ @typeName(@TypeOf(x))),
|
||
|
|
};
|
||
|
|
return @unionInit(Value, @tagName(tag), x);
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn @"null"(self: Value) error{IncorrectType}!void {
|
||
|
|
switch (self) {
|
||
|
|
.null => {},
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected `null`, actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn @"u8"(self: Value) error{IncorrectType}!u8 {
|
||
|
|
switch (self) {
|
||
|
|
.uint8 => |v| return v,
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected `u8`, actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn @"i8"(self: Value) error{IncorrectType}!i8 {
|
||
|
|
switch (self) {
|
||
|
|
.int8 => |v| return v,
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected `i8`, actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn @"u16"(self: Value) error{IncorrectType}!u16 {
|
||
|
|
switch (self) {
|
||
|
|
.uint16 => |v| return v,
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected `u16`, actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn @"i16"(self: Value) error{IncorrectType}!i16 {
|
||
|
|
switch (self) {
|
||
|
|
.int16 => |v| return v,
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected `i16`, actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn @"u32"(self: Value) error{IncorrectType}!u32 {
|
||
|
|
switch (self) {
|
||
|
|
.uint32 => |v| return v,
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected `u32`, actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn @"i32"(self: Value) error{IncorrectType}!i32 {
|
||
|
|
switch (self) {
|
||
|
|
.int32 => |v| return v,
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected `i32`, actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn @"u64"(self: Value) error{IncorrectType}!u64 {
|
||
|
|
switch (self) {
|
||
|
|
.uint64 => |v| return v,
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected `u64`, actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn @"i64"(self: Value) error{IncorrectType}!i64 {
|
||
|
|
switch (self) {
|
||
|
|
.int64 => |v| return v,
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected `i64`, actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn @"f16"(self: Value) error{IncorrectType}!f16 {
|
||
|
|
switch (self) {
|
||
|
|
.float16 => |v| return v,
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected `f16`, actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn @"f32"(self: Value) error{IncorrectType}!f32 {
|
||
|
|
switch (self) {
|
||
|
|
.float32 => |v| return v,
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected `f32`, actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn @"f64"(self: Value) error{IncorrectType}!f64 {
|
||
|
|
switch (self) {
|
||
|
|
.float64 => |v| return v,
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected `f64`, actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn @"bool"(self: Value) error{IncorrectType}!bool {
|
||
|
|
switch (self) {
|
||
|
|
.boolval => |v| return v,
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected `bool`, actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn string(self: Value) error{IncorrectType}![]const u8 {
|
||
|
|
switch (self) {
|
||
|
|
.string => |v| return v,
|
||
|
|
inline else => |v| {
|
||
|
|
std.log.err("Expected string (`[]const u8`), actual value is {s}\n", .{@typeName(@TypeOf(v))});
|
||
|
|
return error.IncorrectType;
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|