diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8be365f..dada8fe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,10 +19,10 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: mlugg/setup-zig@v2 with: - version: 0.15.2 + version: 0.16.0 - name: Build all examples run: zig build @@ -35,9 +35,9 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: mlugg/setup-zig@v2 with: - version: 0.15.2 + version: 0.16.0 - name: Build all examples run: zig build test --summary all diff --git a/README.md b/README.md index a7a98e5..0c6d329 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,13 @@ ## Installing -Compatible Zig Version: `0.15.2` +Compatible Zig Version: `0.16.0` -Compatible [tardy](https://github.com/tardy-org/tardy) Version is `v0.3.1` and [secsock](https://github.com/tardy-org/secsock) `v0.1.1` +Compatible [tardy](https://github.com/tardy-org/tardy) Version is `v0.3.2` and [secsock](https://github.com/tardy-org/secsock) `v0.1.2` -Latest Release: `0.3.1` +Latest Release: `0.3.2` ``` -zig fetch --save git+https://github.com/tardy-org/zzz#v0.3.1 +zig fetch --save git+https://github.com/tardy-org/zzz#v0.3.2 ``` You can then add the dependency in your `build.zig` file: diff --git a/build.zig.zon b/build.zig.zon index ea560b9..0e411db 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -2,15 +2,15 @@ .name = .zzz, .fingerprint = 0xc3273dca261a7ae0, .version = "0.3.1", - .minimum_zig_version = "0.15.2", + .minimum_zig_version = "0.16.0", .dependencies = .{ .tardy = .{ - .url = "git+https://github.com/tardy-org/tardy?ref=v0.3.1#f36525f9b36159bb9196ccb1734a67b55ba2c1ca", - .hash = "tardy-0.3.1-69wrgn77AwCO0ma2a0hOPgreoJogu-uYWlcgo2TgkgBO", + .url = "https://github.com/tardy-org/tardy/archive/refs/tags/v0.3.2.tar.gz", + .hash = "tardy-0.3.2-69wrgkTEBQCi4u4sNr63s5V2TzHXw3iLkkiGXVMGhupi", }, .secsock = .{ - .url = "git+https://github.com/tardy-org/secsock?ref=0.1.1#c70d26cdf6ce7c23967b1b86c3f129c93f1b0e1c", - .hash = "secsock-0.1.1-p0qurVNGAQCyOjL0v1wE89Y5VPCqkQY5O3SirlKtP7BC", + .url = "https://github.com/tardy-org/secsock/archive/refs/tags/v0.1.2.tar.gz", + .hash = "secsock-0.1.2-p0qurcxIAQBc3niJem-RKYS6YrcuyAY2aELeoBB0aQdy", }, }, .paths = .{ diff --git a/docs/getting_started.md b/docs/getting_started.md index d8a885a..e1a9e9e 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -4,7 +4,7 @@ zzz is a networking framework (HTTP) that allows for modularity and flexibility For this guide, we will assume that you are running on a supported platform. This is the current latest release. -`zig fetch --save git+https://github.com/mookums/zzz#v0.3.1` +`zig fetch --save git+https://github.com/mookums/zzz#v0.3.2` ## Hello, World! We can write a quick example that serves out "Hello, World" responses to any client that connects to the server. This example is derived from the one that is provided within the `examples/basic` directory. diff --git a/examples/basic/main.zig b/examples/basic/main.zig index 9a2b008..9b05d72 100644 --- a/examples/basic/main.zig +++ b/examples/basic/main.zig @@ -23,24 +23,20 @@ fn base_handler(ctx: *const Context, _: void) !Respond { }); } -pub fn main() !void { +pub fn main(init: std.process.Init) !void { const host: []const u8 = "0.0.0.0"; const port: u16 = 9862; - var gpa: std.heap.DebugAllocator(.{ .thread_safe = true }) = .init; - const allocator = gpa.allocator(); - defer _ = gpa.deinit(); - - var t: Tardy = try .init(allocator, .{ .threading = .auto }); + var t: Tardy = try .init(init.gpa, init.io, .{ .threading = .auto }); defer t.deinit(); - var router: Router = try .init(allocator, &.{ + var router: Router = try .init(init.gpa, &.{ Route.init("/").get({}, base_handler).layer(), }, .{}); - defer router.deinit(allocator); + defer router.deinit(init.gpa); // create socket for tardy - var socket: Socket = try .init(.{ + var socket: Socket = try .init(init.io, .{ .tcp = .{ .host = host, .port = port }, }); defer socket.close_blocking(); diff --git a/examples/cookies/main.zig b/examples/cookies/main.zig index 7bd6b95..3f60fd8 100644 --- a/examples/cookies/main.zig +++ b/examples/cookies/main.zig @@ -32,24 +32,20 @@ fn base_handler(ctx: *const Context, _: void) !Respond { }); } -pub fn main() !void { +pub fn main(init: std.process.Init) !void { const host: []const u8 = "0.0.0.0"; const port: u16 = 9862; - var gpa: std.heap.DebugAllocator(.{ .thread_safe = true }) = .init; - const allocator = gpa.allocator(); - defer _ = gpa.deinit(); - - var t: Tardy = try .init(allocator, .{ .threading = .single }); + var t: Tardy = try .init(init.gpa, init.io, .{ .threading = .single }); defer t.deinit(); - var router: Router = try .init(allocator, &.{ + var router: Router = try .init(init.gpa, &.{ Route.init("/").get({}, base_handler).layer(), }, .{}); - defer router.deinit(allocator); + defer router.deinit(init.gpa); // create socket for tardy - var socket: Socket = try .init(.{ .tcp = .{ .host = host, .port = port } }); + var socket: Socket = try .init(init.io, .{ .tcp = .{ .host = host, .port = port } }); defer socket.close_blocking(); try socket.bind(); try socket.listen(4096); diff --git a/examples/form/main.zig b/examples/form/main.zig index eeb9f9d..0bb85ac 100644 --- a/examples/form/main.zig +++ b/examples/form/main.zig @@ -76,24 +76,20 @@ fn generate_handler(ctx: *const Context, _: void) !Respond { }); } -pub fn main() !void { +pub fn main(init: std.process.Init) !void { const host: []const u8 = "0.0.0.0"; const port: u16 = 9862; - var gpa: std.heap.DebugAllocator(.{ .thread_safe = true }) = .init; - const allocator = gpa.allocator(); - defer _ = gpa.deinit(); - - var t: Tardy = try .init(allocator, .{ .threading = .auto }); + var t: Tardy = try .init(init.gpa, init.io, .{ .threading = .auto }); defer t.deinit(); - var router: Router = try .init(allocator, &.{ + var router: Router = try .init(init.gpa, &.{ Route.init("/").get({}, base_handler).layer(), Route.init("/generate").get({}, generate_handler).post({}, generate_handler).layer(), }, .{}); - defer router.deinit(allocator); + defer router.deinit(init.gpa); - var socket: Socket = try .init(.{ .tcp = .{ .host = host, .port = port } }); + var socket: Socket = try .init(init.io, .{ .tcp = .{ .host = host, .port = port } }); defer socket.close_blocking(); try socket.bind(); try socket.listen(4096); diff --git a/examples/fs/main.zig b/examples/fs/main.zig index 80f4b58..726be85 100644 --- a/examples/fs/main.zig +++ b/examples/fs/main.zig @@ -36,34 +36,35 @@ fn base_handler(ctx: *const Context, _: void) !Respond { } // Test With: http://localhost:9862/index.html -pub fn main() !void { +pub fn main(init: std.process.Init) !void { const host: []const u8 = "0.0.0.0"; const port: u16 = 9862; - var gpa: std.heap.DebugAllocator(.{ .thread_safe = true }) = .{ - .backing_allocator = std.heap.smp_allocator, - }; - const allocator = gpa.allocator(); - defer _ = gpa.deinit(); - - var t: Tardy = try .init(allocator, .{ .threading = .auto }); + var t: Tardy = try .init(init.gpa, init.io, .{ .threading = .auto }); defer t.deinit(); - const static_dir: Dir = .from_std(try std.fs.cwd().openDir("examples/fs/static", .{})); + const static_dir: Dir = .from_std(try std.Io.Dir.cwd().openDir( + init.io, + "examples/fs/static", + .{}, + )); - var router: Router = try .init(allocator, &.{ + var router: Router = try .init(init.gpa, &.{ Compression(.{ .gzip = .{} }), Route.init("/").get({}, base_handler).layer(), FsDir.serve("/", static_dir), }, .{}); - defer router.deinit(allocator); + defer router.deinit(init.gpa); const EntryParams = struct { router: *const Router, socket: Socket, }; - var socket: Socket = try .init(.{ .tcp = .{ .host = host, .port = port } }); + var socket: Socket = try .init( + init.io, + .{ .tcp = .{ .host = host, .port = port } }, + ); defer socket.close_blocking(); try socket.bind(); try socket.listen(256); diff --git a/examples/middleware/main.zig b/examples/middleware/main.zig index a84cca2..f4f391b 100644 --- a/examples/middleware/main.zig +++ b/examples/middleware/main.zig @@ -55,7 +55,7 @@ fn failing_middleware(next: *Next, _: void) !Respond { return error.FailingMiddleware; } -pub fn main() !void { +pub fn main(init: std.process.Init) !void { const host: []const u8 = "0.0.0.0"; const port: u16 = 9862; @@ -63,12 +63,12 @@ pub fn main() !void { const allocator = gpa.allocator(); defer _ = gpa.deinit(); - var t: Tardy = try .init(allocator, .{ .threading = .single }); + var t: Tardy = try .init(init.gpa, init.io, .{ .threading = .single }); defer t.deinit(); const num: i8 = 12; - var router: Router = try .init(allocator, &.{ + var router: Router = try .init(init.gpa, &.{ Middleware.init({}, passing_middleware).layer(), Route.init("/").get(num, root_handler).layer(), Middleware.init({}, failing_middleware).layer(), @@ -82,7 +82,7 @@ pub fn main() !void { socket: Socket, }; - var socket: Socket = try .init(.{ .tcp = .{ .host = host, .port = port } }); + var socket: Socket = try .init(init.io, .{ .tcp = .{ .host = host, .port = port } }); defer socket.close_blocking(); try socket.bind(); try socket.listen(256); diff --git a/examples/sse/main.zig b/examples/sse/main.zig index 1236ec9..7739fa5 100644 --- a/examples/sse/main.zig +++ b/examples/sse/main.zig @@ -22,30 +22,26 @@ fn sse_handler(ctx: *const Context, _: void) !Respond { while (true) { sse.send(.{ .data = "hello from handler!" }) catch break; - try Timer.delay(ctx.runtime, .{ .seconds = 1 }); + try Timer.delay(ctx.runtime, .{ .nanoseconds = 1 * std.time.ns_per_s }); } return .responded; } -pub fn main() !void { +pub fn main(init: std.process.Init) !void { const host: []const u8 = "0.0.0.0"; const port: u16 = 9862; - var gpa: std.heap.DebugAllocator(.{}) = .init; - const allocator = gpa.allocator(); - defer _ = gpa.deinit(); - - var t: Tardy = try .init(allocator, .{ .threading = .single }); + var t: Tardy = try .init(init.gpa, init.io, .{ .threading = .single }); defer t.deinit(); - const router: Router = try .init(allocator, &.{ + const router: Router = try .init(init.gpa, &.{ Route.init("/").embed_file(.{ .mime = .HTML }, @embedFile("./index.html")).layer(), Route.init("/stream").get({}, sse_handler).layer(), }, .{}); // create socket for tardy - var socket: Socket = try .init(.{ .tcp = .{ .host = host, .port = port } }); + var socket: Socket = try .init(init.io, .{ .tcp = .{ .host = host, .port = port } }); defer socket.close_blocking(); try socket.bind(); try socket.listen(256); diff --git a/examples/tls/main.zig b/examples/tls/main.zig index e0e969a..880ca9e 100644 --- a/examples/tls/main.zig +++ b/examples/tls/main.zig @@ -38,20 +38,14 @@ fn root_handler(ctx: *const Context, _: void) !Respond { }); } -pub fn main() !void { +pub fn main(init: std.process.Init) !void { const host: []const u8 = "0.0.0.0"; const port: u16 = 9862; - var gpa: std.heap.DebugAllocator(.{ .thread_safe = true }) = .{ - .backing_allocator = std.heap.smp_allocator, - }; - const allocator = gpa.allocator(); - defer _ = gpa.deinit(); - - var t: Tardy = try .init(allocator, .{ .threading = .auto }); + var t: Tardy = try .init(init.gpa, init.io, .{ .threading = .auto }); defer t.deinit(); - var router: Router = try .init(allocator, &.{ + var router: Router = try .init(init.gpa, &.{ Route.init("/").get({}, root_handler).layer(), Compression(.{ .gzip = .{} }), Route.init("/embed/pico.min.css").embed_file( @@ -59,15 +53,15 @@ pub fn main() !void { @embedFile("embed/pico.min.css"), ).layer(), }, .{}); - defer router.deinit(allocator); + defer router.deinit(init.gpa); // create socket for tardy - var socket: Socket = try .init(.{ .tcp = .{ .host = host, .port = port } }); + var socket: Socket = try .init(init.io, .{ .tcp = .{ .host = host, .port = port } }); defer socket.close_blocking(); try socket.bind(); try socket.listen(1024); - var bearssl: secsock.BearSSL = .init(allocator); + var bearssl: secsock.BearSSL = .init(init.gpa); defer bearssl.deinit(); try bearssl.add_cert_chain( "CERTIFICATE", diff --git a/examples/unix/main.zig b/examples/unix/main.zig index 06300ff..4e3804c 100644 --- a/examples/unix/main.zig +++ b/examples/unix/main.zig @@ -25,27 +25,24 @@ pub fn root_handler(ctx: *const Context, _: void) !Respond { } // Test With: curl --unix-socket /tmp/zzz.sock http://localhost/ -pub fn main() !void { - var gpa: std.heap.DebugAllocator(.{ .thread_safe = true }) = .init; - const allocator = gpa.allocator(); - defer _ = gpa.deinit(); - - var t: Tardy = try .init(allocator, .{ .threading = .auto }); +pub fn main(init: std.process.Init) !void { + var t: Tardy = try .init(init.gpa, init.io, .{ .threading = .auto }); defer t.deinit(); - var router: Router = try .init(allocator, &.{ + var router: Router = try .init(init.gpa, &.{ Route.init("/").get({}, root_handler).layer(), }, .{}); - defer router.deinit(allocator); + defer router.deinit(init.gpa); const EntryParams = struct { router: *const Router, socket: Socket, }; - var socket: Socket = try .init(.{ .unix = "/tmp/zzz.sock" }); - defer std.fs.deleteFileAbsolute("/tmp/zzz.sock") catch unreachable; + var socket: Socket = try .init(init.io, .{ .unix = "/tmp/zzz.sock" }); + defer std.Io.Dir.deleteDirAbsolute(init.io, "/tmp/zzz.sock") catch unreachable; defer socket.close_blocking(); + try socket.bind(); try socket.listen(256); diff --git a/src/core/wrapping.zig b/src/core/wrapping.zig index 5464260..886978a 100644 --- a/src/core/wrapping.zig +++ b/src/core/wrapping.zig @@ -3,54 +3,77 @@ const assert = std.debug.assert; const testing = std.testing; /// Special values for Wrapped types. -const Wrapped = enum(usize) { null = 0, true = 1, false = 2, void = 3 }; +const Wrapped = enum(usize) { + null = 0, + true = 1, + false = 2, + void = 3, +}; + +fn assertValidWrapping(comptime I: type, comptime T: type) void { + assert(@typeInfo(I) == .int); + assert(@typeInfo(I).int.signedness == .unsigned); + + switch (comptime @typeInfo(T)) { + else => { + @branchHint(.likely); + assert(@bitSizeOf(T) <= @bitSizeOf(I)); + }, + .@"struct" => |s| { + switch (s.layout) { + .@"packed" => { + @branchHint(.likely); + assert(@bitSizeOf(T) <= @bitSizeOf(I)); + }, + else => { + @branchHint(.unlikely); + assert(@hasField(T, "handle")); + }, + } + }, + } +} /// Wraps the given value into a specified integer type. /// The value must fit within the size of the given I. pub fn wrap(comptime I: type, value: anytype) I { const T = @TypeOf(value); - assert(@typeInfo(I) == .int); - assert(@typeInfo(I).int.signedness == .unsigned); - - if (comptime @bitSizeOf(@TypeOf(value)) > @bitSizeOf(I)) { - @compileError("type: " ++ @typeName(T) ++ " is larger than given integer (" ++ @typeName(I) ++ ")"); - } + comptime assertValidWrapping(I, T); return context: { switch (comptime @typeInfo(@TypeOf(value))) { .pointer => break :context @intFromPtr(value), .void => break :context @intFromEnum(Wrapped.void), .int => |info| { - const uint = @Type(std.builtin.Type{ - .int = .{ - .signedness = .unsigned, - .bits = info.bits, - }, - }); + const uint = @Int(.unsigned, info.bits); break :context @intCast(@as(uint, @bitCast(value))); }, .comptime_int => break :context @intCast(value), .float => |info| { - const uint = @Type(std.builtin.Type{ - .int = .{ - .signedness = .unsigned, - .bits = info.bits, - }, - }); + const uint = @Int(.unsigned, info.bits); break :context @intCast(@as(uint, @bitCast(value))); }, .comptime_float => break :context @intCast(@as(I, @bitCast(value))), .@"struct" => |info| { - const uint = @Type(std.builtin.Type{ - .int = .{ - .signedness = .unsigned, - .bits = @bitSizeOf(info.backing_integer.?), + switch (info.layout) { + .@"packed" => { + const uint = @Int(.unsigned, @typeInfo(info.backing_integer.?).int.bits); + break :context @intCast(@as(uint, @bitCast(value))); }, - }); - break :context @intCast(@as(uint, @bitCast(value))); + else => { + // auto layout struct must have a handle field + break :context wrap(I, value.handle); + }, + } }, - .bool => break :context if (value) @intFromEnum(Wrapped.true) else @intFromEnum(Wrapped.false), - .optional => break :context if (value) |v| wrap(I, v) else @intFromEnum(Wrapped.null), + .bool => break :context if (value) + @intFromEnum(Wrapped.true) + else + @intFromEnum(Wrapped.false), + .optional => break :context if (value) |v| + wrap(I, v) + else + @intFromEnum(Wrapped.null), else => @compileError("wrapping unsupported type: " ++ @typeName(@TypeOf(value))), } }; @@ -60,47 +83,33 @@ pub fn wrap(comptime I: type, value: anytype) I { /// The value must be an unsigned integer type, typically a usize. pub fn unwrap(comptime T: type, value: anytype) T { const I = @TypeOf(value); - assert(@typeInfo(I) == .int); - assert(@typeInfo(I).int.signedness == .unsigned); - if (comptime @bitSizeOf(@TypeOf(T)) > @bitSizeOf(I)) { - @compileError("type: " ++ @typeName(T) ++ "is larger than given integer (" ++ @typeName(I) ++ ")"); - } + comptime assertValidWrapping(I, T); return context: { switch (comptime @typeInfo(T)) { .pointer => break :context @ptrFromInt(value), .void => break :context {}, .int => |info| { - const uint = @Type(std.builtin.Type{ - .int = .{ - .signedness = .unsigned, - .bits = info.bits, - }, - }); + const uint = @Int(.unsigned, info.bits); break :context @bitCast(@as(uint, @intCast(value))); }, .float => |info| { - const uint = @Type(std.builtin.Type{ - .int = .{ - .signedness = .unsigned, - .bits = info.bits, - }, - }); - const float = @Type(std.builtin.Type{ - .float = .{ - .bits = info.bits, - }, - }); + const uint = @Int(.unsigned, info.bits); + const float = std.meta.Float(info.bits); break :context @as(float, @bitCast(@as(uint, @intCast(value)))); }, .@"struct" => |info| { - const uint = @Type(std.builtin.Type{ - .int = .{ - .signedness = .unsigned, - .bits = @bitSizeOf(info.backing_integer.?), + switch (info.layout) { + .@"packed" => { + const uint = @Int(.unsigned, @typeInfo(info.backing_integer.?).int.bits); + break :context @bitCast(@as(uint, @intCast(value))); }, - }); - break :context @bitCast(@as(uint, @intCast(value))); + else => { + // auto layout struct must have a handle field + const handle: T = .{ .handle = unwrap(@FieldType(T, "handle"), value) }; + break :context handle; + }, + } }, .bool => { assert(value == @intFromEnum(Wrapped.true) or value == @intFromEnum(Wrapped.false)); @@ -116,16 +125,16 @@ pub fn unwrap(comptime T: type, value: anytype) T { } test "wrap/unwrap - integers" { - try testing.expectEqual(@as(usize, 42), wrap(usize, @as(u8, 42))); - try testing.expectEqual(@as(usize, 42), wrap(usize, @as(u16, 42))); - try testing.expectEqual(@as(usize, 42), wrap(usize, @as(u32, 42))); + try testing.expectEqual(42, wrap(usize, @as(u8, 42))); + try testing.expectEqual(42, wrap(usize, @as(u16, 42))); + try testing.expectEqual(42, wrap(usize, @as(u32, 42))); - try testing.expectEqual(@as(usize, 42), wrap(usize, @as(i8, 42))); - try testing.expectEqual(@as(usize, 42), wrap(usize, @as(i16, 42))); - try testing.expectEqual(@as(usize, 42), wrap(usize, @as(i32, 42))); + try testing.expectEqual(42, wrap(usize, @as(i8, 42))); + try testing.expectEqual(42, wrap(usize, @as(i16, 42))); + try testing.expectEqual(42, wrap(usize, @as(i32, 42))); - try testing.expectEqual(@as(u8, 42), unwrap(u8, @as(usize, 42))); - try testing.expectEqual(@as(i16, 42), unwrap(i16, @as(usize, 42))); + try testing.expectEqual(42, unwrap(u8, @as(usize, 42))); + try testing.expectEqual(42, unwrap(i16, @as(usize, 42))); } test "wrap/unwrap - floats" { @@ -140,8 +149,8 @@ test "wrap/unwrap - floats" { } test "wrap/unwrap - booleans" { - try testing.expectEqual(@as(usize, @intFromEnum(Wrapped.true)), wrap(usize, true)); - try testing.expectEqual(@as(usize, @intFromEnum(Wrapped.false)), wrap(usize, false)); + try testing.expectEqual(@intFromEnum(Wrapped.true), wrap(usize, true)); + try testing.expectEqual(@intFromEnum(Wrapped.false), wrap(usize, false)); try testing.expectEqual(true, unwrap(bool, @as(usize, @intFromEnum(Wrapped.true)))); try testing.expectEqual(false, unwrap(bool, @as(usize, @intFromEnum(Wrapped.false)))); @@ -151,15 +160,15 @@ test "wrap/unwrap - optionals" { const optional_int: ?i32 = 42; const optional_none: ?i32 = null; - try testing.expectEqual(@as(usize, 42), wrap(usize, optional_int)); - try testing.expectEqual(@as(usize, 0), wrap(usize, optional_none)); + try testing.expectEqual(42, wrap(usize, optional_int)); + try testing.expectEqual(0, wrap(usize, optional_none)); - try testing.expectEqual(@as(?i32, 42), unwrap(?i32, @as(usize, 42))); - try testing.expectEqual(@as(?i32, null), unwrap(?i32, @as(usize, 0))); + try testing.expectEqual(42, unwrap(?i32, @as(usize, 42))); + try testing.expectEqual(null, unwrap(?i32, @as(usize, 0))); } test "wrap/unwrap - void" { - try testing.expectEqual(@as(usize, @intFromEnum(Wrapped.void)), wrap(usize, {})); + try testing.expectEqual(@intFromEnum(Wrapped.void), wrap(usize, {})); try testing.expectEqual({}, unwrap(void, @as(usize, @intFromEnum(Wrapped.void)))); } @@ -171,5 +180,41 @@ test "wrap/unwrap - pointers" { const unwrapped = unwrap(*i32, wrapped); try testing.expectEqual(&value, unwrapped); - try testing.expectEqual(@as(i32, 42), unwrapped.*); + try testing.expectEqual(42, unwrapped.*); +} + +test "wrap/unwrap - packed/extern/auto struct" { + { + const Handle = packed struct { + handle: i32, + }; + const handle: Handle = .{ .handle = 42 }; + const wrapped = wrap(usize, handle); + const unwrapped = unwrap(Handle, wrapped); + + try testing.expectEqual(handle.handle, unwrapped.handle); + try testing.expectEqual(42, wrapped); + } + { + const Handle = extern struct { + handle: i32, + }; + const handle: Handle = .{ .handle = 42 }; + const wrapped = wrap(usize, handle); + const unwrapped = unwrap(Handle, wrapped); + + try testing.expectEqual(handle.handle, unwrapped.handle); + try testing.expectEqual(42, wrapped); + } + { + const Handle = struct { + handle: i32, + }; + const handle: Handle = .{ .handle = 42 }; + const wrapped = wrap(usize, handle); + const unwrapped = unwrap(Handle, wrapped); + + try testing.expectEqual(handle.handle, unwrapped.handle); + try testing.expectEqual(42, wrapped); + } } diff --git a/src/http/middlewares/compression.zig b/src/http/middlewares/compression.zig index 49ec776..6eba75c 100644 --- a/src/http/middlewares/compression.zig +++ b/src/http/middlewares/compression.zig @@ -7,9 +7,12 @@ const Next = @import("../router/middleware.zig").Next; const Layer = @import("../router/middleware.zig").Layer; const TypedMiddlewareFn = @import("../router/middleware.zig").TypedMiddlewareFn; -const Kind = union(enum) { gzip: struct { - level: flate.Compress.Level = .default, -} }; +const Kind = union(enum) { + gzip: struct { + container: flate.Container = .gzip, + level: flate.Compress.Options = .default, + }, +}; /// Compression Middleware. /// @@ -17,18 +20,23 @@ const Kind = union(enum) { gzip: struct { /// will properly compress the body and add the proper `Content-Encoding` header. pub fn Compression(comptime compression: Kind) Layer { const func: TypedMiddlewareFn(void) = switch (compression) { - .gzip => |_| struct { + .gzip => |gzip| struct { fn gzip_mw(next: *Next, _: void) !Respond { const respond = try next.run(); const response = next.context.response; if (response.body) |body| if (respond == .standard) { - var compressed: std.Io.Writer.Allocating = try .initCapacity(next.context.allocator, body.len); + var compressed: std.Io.Writer.Allocating = try .initCapacity( + next.context.allocator, + body.len, + ); errdefer compressed.deinit(); - var body_stream: flate.Compress = .init(&compressed.writer, &.{}, .{ - .level = compression.gzip.level, - .container = .gzip, - }); + var body_stream: flate.Compress = try .init( + &compressed.writer, + &.{}, + gzip.container, + gzip.level, + ); try body_stream.writer.writeAll(body); try body_stream.writer.flush(); diff --git a/src/http/request.zig b/src/http/request.zig index 9fa1ba4..afbfd9a 100644 --- a/src/http/request.zig +++ b/src/http/request.zig @@ -88,7 +88,7 @@ pub const Request = struct { } else { var header_iter = std.mem.tokenizeScalar(u8, line, ':'); const key = header_iter.next() orelse return HTTPError.MalformedRequest; - const value = std.mem.trimLeft(u8, header_iter.rest(), &.{' '}); + const value = std.mem.trimStart(u8, header_iter.rest(), &.{' '}); if (value.len == 0) return HTTPError.MalformedRequest; try self.headers.put(key, value); } diff --git a/src/http/router/fs_dir.zig b/src/http/router/fs_dir.zig index a6d76b5..73dd08c 100644 --- a/src/http/router/fs_dir.zig +++ b/src/http/router/fs_dir.zig @@ -55,8 +55,7 @@ pub const FsDir = struct { var hash: std.hash.Wyhash = .init(0); hash.update(std.mem.asBytes(&stat.size)); if (stat.modified) |modified| { - hash.update(std.mem.asBytes(&modified.seconds)); - hash.update(std.mem.asBytes(&modified.nanos)); + hash.update(std.mem.asBytes(&modified.nanoseconds)); } const etag_hash = hash.final(); @@ -107,7 +106,7 @@ pub const FsDir = struct { pub fn serve(comptime url_path: []const u8, dir: Dir) Layer { const url_with_match_all = comptime std.fmt.comptimePrint( "{s}/%r", - .{std.mem.trimRight(u8, url_path, "/")}, + .{std.mem.trimEnd(u8, url_path, "/")}, ); log.debug("url with match {s}", .{url_with_match_all}); diff --git a/src/http/router/route.zig b/src/http/router/route.zig index 5004d08..867b38a 100644 --- a/src/http/router/route.zig +++ b/src/http/router/route.zig @@ -34,11 +34,11 @@ pub const Route = struct { path: []const u8, /// Route Handlers. - handlers: [9]?HandlerWithData = .{null} ** 9, + handlers: [9]?HandlerWithData = @splat(null), /// Initialize a route for the given path. pub fn init(path: []const u8) Route { - return Route{ .path = path }; + return .{ .path = path }; } /// Returns a comma delinated list of allowed Methods for this route. This @@ -98,7 +98,10 @@ pub const Route = struct { .data = wrapped, }; - return Route{ .path = self.path, .handlers = new_handlers }; + return .{ + .path = self.path, + .handlers = new_handlers, + }; } /// Set a handler function for all methods. @@ -114,7 +117,7 @@ pub const Route = struct { }; } - return Route{ + return .{ .path = self.path, .handlers = new_handlers, }; diff --git a/src/http/server.zig b/src/http/server.zig index 329f190..24059b3 100644 --- a/src/http/server.zig +++ b/src/http/server.zig @@ -202,7 +202,7 @@ pub const Server = struct { connection_count.* += 1; defer connection_count.* -= 1; - if (secure.socket.addr.any.family != std.posix.AF.UNIX) { + if (secure.socket.addr.family() != .unix) { try Cross.socket.disable_nagle(secure.socket.handle); }