2025-06-09 16:34:20 +00:00
|
|
|
const std = @import("std");
|
|
|
|
|
|
|
|
|
|
const c = @import("c");
|
|
|
|
|
|
|
|
|
|
export fn _upb_MiniTable_StrongReference_dont_copy_me__upb_internal_use_only(mt: *c.upb_MiniTable) callconv(.c) void {
|
|
|
|
|
const unused: *volatile c.upb_MiniTable = mt;
|
|
|
|
|
_ = &unused;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub const SerializeOptions = packed struct(c_int) {
|
|
|
|
|
deterministic: bool = false,
|
|
|
|
|
skip_unknown: bool = false,
|
|
|
|
|
check_required: bool = false,
|
|
|
|
|
_ignored: u29 = 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pub const SerializeError = error{
|
|
|
|
|
MaxDepthExceeded,
|
|
|
|
|
MissingRequired,
|
|
|
|
|
Unknown,
|
|
|
|
|
} || std.mem.Allocator.Error;
|
|
|
|
|
|
|
|
|
|
pub const ParseOptions = packed struct {
|
|
|
|
|
alias_string: bool = false,
|
|
|
|
|
check_required: bool = false,
|
|
|
|
|
experimental_allow_unlinked: bool = false,
|
|
|
|
|
always_validate_utf8: bool = false,
|
|
|
|
|
disable_fast_table: bool = false,
|
|
|
|
|
_ignored: u27 = 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
pub const ParseError = error{
|
|
|
|
|
Malformed,
|
|
|
|
|
BadUtf8,
|
|
|
|
|
MaxDepthExceeded,
|
|
|
|
|
MissingRequired,
|
|
|
|
|
UnlinkedSubMessage,
|
|
|
|
|
Unknown,
|
|
|
|
|
} || std.mem.Allocator.Error;
|
|
|
|
|
|
2025-07-15 15:26:03 +00:00
|
|
|
pub fn deepClone(comptime UpbType: type, arena: *c.upb_Arena, msg: *const UpbType) std.mem.Allocator.Error!*UpbType {
|
|
|
|
|
return @ptrCast(c.upb_Message_DeepClone(@ptrCast(msg), Minitable(UpbType), arena) orelse return std.mem.Allocator.Error.OutOfMemory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn shallowClone(comptime UpbType: type, arena: *c.upb_Arena, msg: *const UpbType) std.mem.Allocator.Error!*UpbType {
|
|
|
|
|
return @ptrCast(c.upb_Message_ShallowClone(@ptrCast(msg), Minitable(UpbType), arena) orelse return std.mem.Allocator.Error.OutOfMemory);
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-09 16:34:20 +00:00
|
|
|
pub fn stringView(data: ?[]const u8) c.upb_StringView {
|
|
|
|
|
return if (data) |d| c.upb_StringView_FromDataAndSize(d.ptr, d.len) else .{};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn slice(sv: c.upb_StringView) ?[]const u8 {
|
|
|
|
|
return if (sv.data) |d| d[0..sv.size] else null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn ProtoName(comptime UpbType: type) []const u8 {
|
|
|
|
|
const needle = ".struct_";
|
|
|
|
|
const type_name = @typeName(UpbType);
|
|
|
|
|
const idx = std.mem.indexOf(u8, type_name, needle) orelse @compileError("Type name is invalid");
|
|
|
|
|
return type_name[idx + needle.len ..];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn Minitable(comptime UpbType: type) *const c.upb_MiniTable {
|
|
|
|
|
const field_name = comptime blk: {
|
|
|
|
|
const name = ProtoName(UpbType);
|
|
|
|
|
var it = std.mem.tokenizeScalar(u8, name, '_');
|
|
|
|
|
while (it.next()) |_| {
|
|
|
|
|
const new_name = name[0..it.index] ++ "_" ++ name[it.index..] ++ "_msg_init";
|
|
|
|
|
if (@hasDecl(c, new_name)) {
|
|
|
|
|
break :blk new_name;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
@compileError("Unable to find minitable for type:" ++ @typeName(UpbType));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
return &@field(c, field_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn serializeEx(ptr: anytype, arena: *c.upb_Arena, opts: SerializeOptions) SerializeError![]const u8 {
|
|
|
|
|
var buf: [*c]u8 = undefined;
|
|
|
|
|
var size: usize = undefined;
|
|
|
|
|
return switch (c.upb_Encode(@ptrCast(ptr), Minitable(@TypeOf(ptr.*)), @bitCast(opts), arena, &buf, &size)) {
|
|
|
|
|
c.kUpb_EncodeStatus_Ok => buf[0..size],
|
|
|
|
|
c.kUpb_EncodeStatus_OutOfMemory => std.mem.Allocator.Error.OutOfMemory,
|
|
|
|
|
c.kUpb_EncodeStatus_MaxDepthExceeded => SerializeError.MaxDepthExceeded,
|
|
|
|
|
c.kUpb_EncodeStatus_MissingRequired => SerializeError.MissingRequired,
|
|
|
|
|
else => return SerializeError.Unknown,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn serialize(ptr: anytype, arena: *c.upb_Arena) SerializeError![]const u8 {
|
|
|
|
|
return try serializeEx(ptr, arena, .{});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn parseEx(comptime UpbType: type, arena: *c.upb_Arena, data: []const u8, opts: ParseOptions) ParseError!*UpbType {
|
|
|
|
|
const obj = try new(UpbType, arena);
|
|
|
|
|
return switch (c.upb_Decode(@ptrCast(@constCast(data)), data.len, @alignCast(@ptrCast(obj)), Minitable(UpbType), null, @bitCast(opts), arena)) {
|
|
|
|
|
c.kUpb_DecodeStatus_Ok => obj,
|
|
|
|
|
c.kUpb_DecodeStatus_Malformed => ParseError.Malformed,
|
|
|
|
|
c.kUpb_DecodeStatus_OutOfMemory => std.mem.Allocator.Error.OutOfMemory,
|
|
|
|
|
c.kUpb_DecodeStatus_BadUtf8 => ParseError.BadUtf8,
|
|
|
|
|
c.kUpb_DecodeStatus_MaxDepthExceeded => ParseError.MaxDepthExceeded,
|
|
|
|
|
c.kUpb_DecodeStatus_MissingRequired => ParseError.MissingRequired,
|
|
|
|
|
c.kUpb_DecodeStatus_UnlinkedSubMessage => ParseError.UnlinkedSubMessage,
|
|
|
|
|
else => ParseError.Unknown,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn parse(comptime UpbType: type, arena: *c.upb_Arena, data: []const u8) ParseError!*UpbType {
|
2025-07-15 15:26:03 +00:00
|
|
|
return parseEx(UpbType, arena, data, .{});
|
2025-06-09 16:34:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn new(comptime UpbType: type, arena: *c.upb_Arena) std.mem.Allocator.Error!*UpbType {
|
|
|
|
|
const new_fn = @field(c, ProtoName(UpbType) ++ "_new");
|
|
|
|
|
return @ptrCast(new_fn(arena) orelse return std.mem.Allocator.Error.OutOfMemory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub const Allocator = struct {
|
|
|
|
|
upb_alloc: c.upb_alloc,
|
|
|
|
|
allocator: std.mem.Allocator,
|
|
|
|
|
|
|
|
|
|
pub fn init(allocator: std.mem.Allocator) Allocator {
|
|
|
|
|
return .{
|
|
|
|
|
.upb_alloc = .{
|
|
|
|
|
.func = &alloc_impl,
|
|
|
|
|
},
|
|
|
|
|
.allocator = allocator,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn inner(self: *Allocator) *c.upb_alloc {
|
|
|
|
|
return &self.upb_alloc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn alloc_impl(alloc: [*c]c.upb_alloc, ptr: ?*anyopaque, oldsize: usize, size: usize, actual_size: [*c]usize) callconv(.c) ?*anyopaque {
|
2025-06-19 09:30:29 +00:00
|
|
|
const PointerAlignedSlice = [*c]align(@alignOf(*anyopaque)) u8;
|
2025-06-09 16:34:20 +00:00
|
|
|
const upb_alloc: *c.upb_alloc = alloc orelse return null;
|
|
|
|
|
const self: *Allocator = @fieldParentPtr("upb_alloc", upb_alloc);
|
|
|
|
|
defer {
|
|
|
|
|
if (actual_size) |as| {
|
|
|
|
|
as.* = size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ptr) |ptr_| {
|
2025-06-19 09:30:29 +00:00
|
|
|
const ptr_as_slice: []u8 = @as(PointerAlignedSlice, @ptrCast(@alignCast(ptr_)))[0..oldsize];
|
2025-06-09 16:34:20 +00:00
|
|
|
if (size == 0) {
|
|
|
|
|
self.allocator.free(ptr_as_slice);
|
|
|
|
|
return null;
|
|
|
|
|
} else if (size != oldsize) {
|
|
|
|
|
return (self.allocator.realloc(ptr_as_slice, size) catch return null).ptr;
|
|
|
|
|
}
|
|
|
|
|
@panic("Unsupported case");
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-28 13:54:28 +00:00
|
|
|
return @ptrCast(self.allocator.alignedAlloc(u8, std.mem.Alignment.of(*anyopaque), size) catch return null);
|
2025-06-09 16:34:20 +00:00
|
|
|
}
|
|
|
|
|
};
|