Compare commits
10 commits
c7406520e4
...
a6174af2ec
Author | SHA1 | Date | |
---|---|---|---|
a6174af2ec | |||
e46447c70a | |||
abe06a524d | |||
05c594e552 | |||
53ddddbaa9 | |||
34b2bf28d9 | |||
f0cf0e7aac | |||
687e62466a | |||
d0a05b80f6 | |||
e4c84d6158 |
6 changed files with 71 additions and 167 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/.zig-cache/
|
||||
/zig-out/
|
11
README.md
11
README.md
|
@ -1,9 +1,2 @@
|
|||
# Thespian
|
||||
Fast & flexible actors for Zig, C & C++ applications
|
||||
|
||||
To build:
|
||||
```
|
||||
./zig build
|
||||
```
|
||||
|
||||
See `tests/*` for many interesting examples.
|
||||
# Zig CBOR
|
||||
A Fast & flexible cbor encoding, decoding and matching library for Zig
|
||||
|
|
107
build.zig
107
build.zig
|
@ -1,128 +1,21 @@
|
|||
const std = @import("std");
|
||||
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
|
||||
const cppflags = [_][]const u8{
|
||||
"-DASIO_HAS_THREADS",
|
||||
"-fcolor-diagnostics",
|
||||
"-std=c++20",
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Werror",
|
||||
"-Wpedantic",
|
||||
"-Wno-deprecated-declarations",
|
||||
"-Wno-unqualified-std-cast-call",
|
||||
"-Wno-bitwise-instead-of-logical", //for notcurses
|
||||
"-fno-sanitize=undefined",
|
||||
"-gen-cdb-fragment-path",
|
||||
".cache/cdb",
|
||||
};
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const enable_tracy_option = b.option(bool, "enable_tracy", "Enable tracy client library (default: no)");
|
||||
const tracy_enabled = if (enable_tracy_option) |enabled| enabled else false;
|
||||
|
||||
const options = b.addOptions();
|
||||
options.addOption(bool, "enable_tracy", tracy_enabled);
|
||||
|
||||
const options_mod = options.createModule();
|
||||
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
const mode = .{ .target = target, .optimize = optimize };
|
||||
|
||||
const asio_dep = b.dependency("asio", mode);
|
||||
const tracy_dep = if (tracy_enabled) b.dependency("tracy", mode) else undefined;
|
||||
|
||||
const lib = b.addStaticLibrary(.{
|
||||
.name = "thespian",
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
if (tracy_enabled) {
|
||||
lib.defineCMacro("TRACY_ENABLE", null);
|
||||
lib.defineCMacro("TRACY_CALLSTACK", null);
|
||||
}
|
||||
lib.addIncludePath(b.path("src"));
|
||||
lib.addIncludePath(b.path("include"));
|
||||
lib.addCSourceFiles(.{ .files = &[_][]const u8{
|
||||
"src/backtrace.cpp",
|
||||
"src/c/context.cpp",
|
||||
"src/c/env.cpp",
|
||||
"src/c/file_descriptor.cpp",
|
||||
"src/c/file_stream.cpp",
|
||||
"src/c/handle.cpp",
|
||||
"src/c/instance.cpp",
|
||||
"src/c/metronome.cpp",
|
||||
"src/c/signal.cpp",
|
||||
"src/c/timeout.cpp",
|
||||
"src/c/trace.cpp",
|
||||
"src/cbor.cpp",
|
||||
"src/executor_asio.cpp",
|
||||
"src/hub.cpp",
|
||||
"src/instance.cpp",
|
||||
"src/trace.cpp",
|
||||
}, .flags = &cppflags });
|
||||
if (tracy_enabled) {
|
||||
lib.linkLibrary(tracy_dep.artifact("tracy"));
|
||||
}
|
||||
lib.linkLibrary(asio_dep.artifact("asio"));
|
||||
if (lib.rootModuleTarget().os.tag == .windows) {
|
||||
lib.linkSystemLibrary("mswsock");
|
||||
lib.linkSystemLibrary("ws2_32");
|
||||
}
|
||||
lib.linkLibCpp();
|
||||
b.installArtifact(lib);
|
||||
|
||||
const cbor_mod = b.addModule("cbor", .{
|
||||
.root_source_file = b.path("src/cbor.zig"),
|
||||
});
|
||||
|
||||
const thespian_mod = b.addModule("thespian", .{
|
||||
.root_source_file = b.path("src/thespian.zig"),
|
||||
.imports = &.{
|
||||
.{ .name = "cbor", .module = cbor_mod },
|
||||
},
|
||||
});
|
||||
thespian_mod.addIncludePath(b.path("include"));
|
||||
thespian_mod.linkLibrary(lib);
|
||||
|
||||
const tests = b.addTest(.{
|
||||
.root_source_file = b.path("test/tests.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
tests.root_module.addImport("build_options", options_mod);
|
||||
tests.root_module.addImport("cbor", cbor_mod);
|
||||
tests.root_module.addImport("thespian", thespian_mod);
|
||||
tests.addIncludePath(b.path("test"));
|
||||
tests.addIncludePath(b.path("src"));
|
||||
tests.addIncludePath(b.path("include"));
|
||||
tests.addCSourceFiles(.{ .files = &[_][]const u8{
|
||||
"test/cbor_match.cpp",
|
||||
"test/debug.cpp",
|
||||
"test/endpoint_unx.cpp",
|
||||
"test/endpoint_tcp.cpp",
|
||||
"test/hub_filter.cpp",
|
||||
"test/ip_tcp_client_server.cpp",
|
||||
"test/ip_udp_echo.cpp",
|
||||
"test/metronome_test.cpp",
|
||||
"test/perf_cbor.cpp",
|
||||
"test/perf_hub.cpp",
|
||||
"test/perf_ring.cpp",
|
||||
"test/perf_spawn.cpp",
|
||||
"test/spawn_exit.cpp",
|
||||
"test/tests.cpp",
|
||||
"test/timeout_test.cpp",
|
||||
}, .flags = &cppflags });
|
||||
tests.linkLibrary(lib);
|
||||
tests.linkLibrary(asio_dep.artifact("asio"));
|
||||
tests.linkLibCpp();
|
||||
b.installArtifact(tests);
|
||||
|
||||
const test_run_cmd = b.addRunArtifact(tests);
|
||||
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
test_step.dependOn(&test_run_cmd.step);
|
||||
}
|
||||
|
|
|
@ -1,19 +1,9 @@
|
|||
.{
|
||||
.name = "thespian",
|
||||
.version = "0.0.1",
|
||||
.name = .cbor,
|
||||
.version = "1.0.0",
|
||||
.fingerprint = 0x1feaffc7fc04c445,
|
||||
|
||||
.dependencies = .{
|
||||
.asio = .{
|
||||
.url = "https://github.com/neurocyte/asio/archive/8cc76c9ed4054f45bfc06476d795477096aab7a5.tar.gz",
|
||||
.hash = "12206a4050ebb2e2bf84ed477ea5fe0d0325f9292eef2cb8bd47ccda75a9b3d93516",
|
||||
},
|
||||
.tracy = .{
|
||||
.url = "https://github.com/neurocyte/zig-tracy/archive/80b914d2391209de9ed5a1fd6f440642df55cbd4.tar.gz",
|
||||
.hash = "1220351c8410936854e3baa10aa7bbe775196b3974a3d670808bebbab00631439285",
|
||||
},
|
||||
},
|
||||
.paths = .{
|
||||
"include",
|
||||
"src",
|
||||
"test",
|
||||
"build.zig",
|
||||
|
|
100
src/cbor.zig
100
src/cbor.zig
|
@ -209,12 +209,12 @@ fn writeErrorset(writer: anytype, err: anyerror) @TypeOf(writer).Error!void {
|
|||
pub fn writeValue(writer: anytype, value: anytype) @TypeOf(writer).Error!void {
|
||||
const T = @TypeOf(value);
|
||||
switch (@typeInfo(T)) {
|
||||
.Int, .ComptimeInt => return if (T == u64) writeU64(writer, value) else writeI64(writer, @intCast(value)),
|
||||
.Bool => return writeBool(writer, value),
|
||||
.Optional => return if (value) |v| writeValue(writer, v) else writeNull(writer),
|
||||
.ErrorUnion => return if (value) |v| writeValue(writer, v) else |err| writeValue(writer, err),
|
||||
.ErrorSet => return writeErrorset(writer, value),
|
||||
.Union => |info| {
|
||||
.int, .comptime_int => return if (T == u64) writeU64(writer, value) else writeI64(writer, @intCast(value)),
|
||||
.bool => return writeBool(writer, value),
|
||||
.optional => return if (value) |v| writeValue(writer, v) else writeNull(writer),
|
||||
.error_union => return if (value) |v| writeValue(writer, v) else |err| writeValue(writer, err),
|
||||
.error_set => return writeErrorset(writer, value),
|
||||
.@"union" => |info| {
|
||||
if (info.tag_type) |TagType| {
|
||||
comptime var v = void;
|
||||
inline for (info.fields) |u_field| {
|
||||
|
@ -230,7 +230,7 @@ pub fn writeValue(writer: anytype, value: anytype) @TypeOf(writer).Error!void {
|
|||
try writeArray(writer, .{@typeName(T)});
|
||||
}
|
||||
},
|
||||
.Struct => |info| {
|
||||
.@"struct" => |info| {
|
||||
if (info.is_tuple) {
|
||||
if (info.fields.len == 0) return writeNull(writer);
|
||||
try writeArrayHeader(writer, info.fields.len);
|
||||
|
@ -245,10 +245,10 @@ pub fn writeValue(writer: anytype, value: anytype) @TypeOf(writer).Error!void {
|
|||
}
|
||||
}
|
||||
},
|
||||
.Pointer => |ptr_info| switch (ptr_info.size) {
|
||||
.One => return writeValue(writer, value.*),
|
||||
.Many, .C => @compileError("cannot write type '" ++ @typeName(T) ++ "' to cbor stream"),
|
||||
.Slice => {
|
||||
.pointer => |ptr_info| switch (ptr_info.size) {
|
||||
.one => return writeValue(writer, value.*),
|
||||
.many, .c => @compileError("cannot write type '" ++ @typeName(T) ++ "' to cbor stream"),
|
||||
.slice => {
|
||||
if (ptr_info.child == u8) return writeString(writer, value);
|
||||
if (value.len == 0) return writeNull(writer);
|
||||
try writeArrayHeader(writer, value.len);
|
||||
|
@ -256,22 +256,22 @@ pub fn writeValue(writer: anytype, value: anytype) @TypeOf(writer).Error!void {
|
|||
try writeValue(writer, elem);
|
||||
},
|
||||
},
|
||||
.Array => |info| {
|
||||
.array => |info| {
|
||||
if (info.child == u8) return writeString(writer, &value);
|
||||
if (value.len == 0) return writeNull(writer);
|
||||
try writeArrayHeader(writer, value.len);
|
||||
for (value) |elem|
|
||||
try writeValue(writer, elem);
|
||||
},
|
||||
.Vector => |info| {
|
||||
.vector => |info| {
|
||||
try writeArrayHeader(writer, info.len);
|
||||
var i: usize = 0;
|
||||
while (i < info.len) : (i += 1) {
|
||||
try writeValue(writer, value[i]);
|
||||
}
|
||||
},
|
||||
.Null => try writeNull(writer),
|
||||
.Float => |info| switch (info.bits) {
|
||||
.null => try writeNull(writer),
|
||||
.float => |info| switch (info.bits) {
|
||||
16 => try writeF16(writer, value),
|
||||
32 => try writeF32(writer, value),
|
||||
64 => try writeF64(writer, value),
|
||||
|
@ -380,7 +380,7 @@ fn decodeJsonObject(iter_: *[]const u8, minor: u5, obj: *json.ObjectMap) Error!b
|
|||
var iter = iter_.*;
|
||||
var n = try decodePInt(&iter, minor);
|
||||
while (n > 0) {
|
||||
var key: []u8 = undefined;
|
||||
var key: []const u8 = undefined;
|
||||
var value: json.Value = .null;
|
||||
|
||||
if (!try matchString(&iter, &key))
|
||||
|
@ -522,6 +522,21 @@ fn matchFloatValue(comptime T: type, iter: *[]const u8, val: T) Error!bool {
|
|||
return if (try matchFloat(T, iter, &v)) v == val else false;
|
||||
}
|
||||
|
||||
pub fn matchEnum(comptime T: type, iter_: *[]const u8, val: *T) Error!bool {
|
||||
var iter = iter_.*;
|
||||
var str: []const u8 = undefined;
|
||||
if (try matchString(&iter, &str)) if (std.meta.stringToEnum(T, str)) |val_| {
|
||||
val.* = val_;
|
||||
iter_.* = iter;
|
||||
return true;
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
fn matchEnumValue(comptime T: type, iter: *[]const u8, val: T) Error!bool {
|
||||
return matchStringValue(iter, @tagName(val));
|
||||
}
|
||||
|
||||
fn skipString(iter: *[]const u8, minor: u5) Error!void {
|
||||
const len: usize = @intCast(try decodePInt(iter, minor));
|
||||
if (iter.len < len)
|
||||
|
@ -642,21 +657,22 @@ pub fn matchValue(iter: *[]const u8, value: anytype) Error!bool {
|
|||
if (comptime isExtractor(T))
|
||||
return value.extract(iter);
|
||||
return switch (comptime @typeInfo(T)) {
|
||||
.Int => return matchIntValue(T, iter, value),
|
||||
.ComptimeInt => return matchIntValue(i64, iter, value),
|
||||
.Bool => matchBoolValue(iter, value),
|
||||
.Pointer => |info| switch (info.size) {
|
||||
.One => matchValue(iter, value.*),
|
||||
.Many, .C => matchError(T),
|
||||
.Slice => if (info.child == u8) matchStringValue(iter, value) else matchArray(iter, value, info),
|
||||
.int => return matchIntValue(T, iter, value),
|
||||
.comptime_int => return matchIntValue(i64, iter, value),
|
||||
.bool => matchBoolValue(iter, value),
|
||||
.pointer => |info| switch (info.size) {
|
||||
.one => matchValue(iter, value.*),
|
||||
.many, .c => matchError(T),
|
||||
.slice => if (info.child == u8) matchStringValue(iter, value) else matchArray(iter, value, info),
|
||||
},
|
||||
.Struct => |info| if (info.is_tuple)
|
||||
.@"struct" => |info| if (info.is_tuple)
|
||||
matchArray(iter, value, info)
|
||||
else
|
||||
matchError(T),
|
||||
.Array => |info| if (info.child == u8) matchStringValue(iter, &value) else matchArray(iter, value, info),
|
||||
.Float => return matchFloatValue(T, iter, value),
|
||||
.ComptimeFloat => matchFloatValue(f64, iter, value),
|
||||
.array => |info| if (info.child == u8) matchStringValue(iter, &value) else matchArray(iter, value, info),
|
||||
.float => matchFloatValue(T, iter, value),
|
||||
.comptime_float => matchFloatValue(f64, iter, value),
|
||||
.@"enum" => matchEnumValue(T, iter, value),
|
||||
else => @compileError("cannot match value type '" ++ @typeName(T) ++ "' to cbor stream"),
|
||||
};
|
||||
}
|
||||
|
@ -784,7 +800,7 @@ fn hasExtractorTag(info: anytype) bool {
|
|||
|
||||
fn isExtractor(comptime T: type) bool {
|
||||
return comptime switch (@typeInfo(T)) {
|
||||
.Struct => |info| hasExtractorTag(info),
|
||||
.@"struct" => |info| hasExtractorTag(info),
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
@ -837,15 +853,15 @@ fn Extractor(comptime T: type) type {
|
|||
|
||||
pub fn extract(self: Self, iter: *[]const u8) Error!bool {
|
||||
switch (comptime @typeInfo(T)) {
|
||||
.Int, .ComptimeInt => return matchInt(T, iter, self.dest),
|
||||
.Bool => return matchBool(iter, self.dest),
|
||||
.Pointer => |ptr_info| switch (ptr_info.size) {
|
||||
.Slice => {
|
||||
.int, .comptime_int => return matchInt(T, iter, self.dest),
|
||||
.bool => return matchBool(iter, self.dest),
|
||||
.pointer => |ptr_info| switch (ptr_info.size) {
|
||||
.slice => {
|
||||
if (ptr_info.child == u8) return matchString(iter, self.dest) else extractError(T);
|
||||
},
|
||||
else => extractError(T),
|
||||
},
|
||||
.Optional => |opt_info| {
|
||||
.optional => |opt_info| {
|
||||
var nested: opt_info.child = undefined;
|
||||
const extractor = Extractor(opt_info.child).init(&nested);
|
||||
if (try extractor.extract(iter)) {
|
||||
|
@ -854,7 +870,8 @@ fn Extractor(comptime T: type) type {
|
|||
}
|
||||
return false;
|
||||
},
|
||||
.Float => return matchFloat(T, iter, self.dest),
|
||||
.float => return matchFloat(T, iter, self.dest),
|
||||
.@"enum" => return matchEnum(T, iter, self.dest),
|
||||
else => extractError(T),
|
||||
}
|
||||
}
|
||||
|
@ -863,8 +880,8 @@ fn Extractor(comptime T: type) type {
|
|||
|
||||
fn ExtractorType(comptime T: type) type {
|
||||
const T_type_info = @typeInfo(T);
|
||||
if (T_type_info != .Pointer) @compileError("extract requires a pointer argument");
|
||||
return Extractor(T_type_info.Pointer.child);
|
||||
if (T_type_info != .pointer) @compileError("extract requires a pointer argument");
|
||||
return Extractor(T_type_info.pointer.child);
|
||||
}
|
||||
|
||||
pub fn extract(dest: anytype) ExtractorType(@TypeOf(dest)) {
|
||||
|
@ -897,8 +914,11 @@ pub fn extract_cbor(dest: *[]const u8) CborExtractor {
|
|||
}
|
||||
|
||||
pub fn JsonStream(comptime T: type) type {
|
||||
return JsonStreamWriter(T.Writer);
|
||||
}
|
||||
|
||||
pub fn JsonStreamWriter(comptime Writer: type) type {
|
||||
return struct {
|
||||
const Writer = T.Writer;
|
||||
const JsonWriter = json.WriteStream(Writer, .{ .checked_to_fixed_depth = 256 });
|
||||
|
||||
fn jsonWriteArray(w: *JsonWriter, iter: *[]const u8, minor: u5) !void {
|
||||
|
@ -954,6 +974,12 @@ pub fn toJson(cbor_buf: []const u8, json_buf: []u8) (JsonEncodeError || error{No
|
|||
return fbs.getWritten();
|
||||
}
|
||||
|
||||
pub fn toJsonWriter(cbor_buf: []const u8, writer: anytype, options: std.json.StringifyOptions) !void {
|
||||
var s = json.writeStream(writer, options);
|
||||
var iter: []const u8 = cbor_buf;
|
||||
try JsonStreamWriter(@TypeOf(writer)).jsonWriteValue(&s, &iter);
|
||||
}
|
||||
|
||||
pub fn toJsonAlloc(a: std.mem.Allocator, cbor_buf: []const u8) (JsonEncodeError)![]const u8 {
|
||||
var buf = std.ArrayList(u8).init(a);
|
||||
defer buf.deinit();
|
||||
|
|
|
@ -151,7 +151,7 @@ test "cbor.matchValue(i64) multi" {
|
|||
var buf: [128]u8 = undefined;
|
||||
const iter = fmt(&buf, 7);
|
||||
const iter2 = fmt(buf[iter.len..], 8);
|
||||
var iter3 = buf[0 .. iter.len + iter2.len];
|
||||
var iter3: []const u8 = buf[0 .. iter.len + iter2.len];
|
||||
try expect(try matchValue(&iter3, 7));
|
||||
try expect(try matchValue(&iter3, 8));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue