mirror of
https://github.com/zigzap/zap.git
synced 2025-10-20 15:14:08 +00:00
refactored endpoint Binder/Bind/Bound/Interface ... namings
This commit is contained in:
parent
458d6ee071
commit
b05004291e
2 changed files with 73 additions and 68 deletions
63
src/App.zig
63
src/App.zig
|
@ -32,7 +32,6 @@ pub fn Create(comptime Context: type) type {
|
|||
context: *Context = undefined,
|
||||
gpa: Allocator = undefined,
|
||||
opts: AppOpts = undefined,
|
||||
// endpoints: std.StringArrayHashMapUnmanaged(*Endpoint.Interface) = .empty,
|
||||
endpoints: std.ArrayListUnmanaged(*Endpoint.Interface) = .empty,
|
||||
|
||||
there_can_be_only_one: bool = false,
|
||||
|
@ -61,64 +60,68 @@ pub fn Create(comptime Context: type) type {
|
|||
path: []const u8,
|
||||
destroy: *const fn (*Interface, Allocator) void = undefined,
|
||||
};
|
||||
pub fn Wrap(T: type) type {
|
||||
pub fn Bind(ArbitraryEndpoint: type) type {
|
||||
return struct {
|
||||
wrapped: *T,
|
||||
endpoint: *ArbitraryEndpoint,
|
||||
interface: Interface,
|
||||
|
||||
// tbh: unnecessary, since we have it in _static
|
||||
app_context: *Context,
|
||||
|
||||
const Wrapped = @This();
|
||||
const Bound = @This();
|
||||
|
||||
pub fn unwrap(interface: *Interface) *Wrapped {
|
||||
const self: *Wrapped = @alignCast(@fieldParentPtr("interface", interface));
|
||||
pub fn unwrap(interface: *Interface) *Bound {
|
||||
const self: *Bound = @alignCast(@fieldParentPtr("interface", interface));
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn destroy(interface: *Interface, allocator: Allocator) void {
|
||||
const self: *Wrapped = @alignCast(@fieldParentPtr("interface", interface));
|
||||
const self: *Bound = @alignCast(@fieldParentPtr("interface", interface));
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
||||
pub fn onRequestWrapped(interface: *Interface, r: Request) !void {
|
||||
var self: *Wrapped = Wrapped.unwrap(interface);
|
||||
pub fn onRequestInterface(interface: *Interface, r: Request) !void {
|
||||
var self: *Bound = Bound.unwrap(interface);
|
||||
var arena = try get_arena();
|
||||
try self.onRequest(arena.allocator(), self.app_context, r);
|
||||
_ = arena.reset(.{ .retain_with_limit = _static.opts.arena_retain_capacity });
|
||||
}
|
||||
|
||||
pub fn onRequest(self: *Wrapped, arena: Allocator, app_context: *Context, r: Request) !void {
|
||||
pub fn onRequest(self: *Bound, arena: Allocator, app_context: *Context, r: Request) !void {
|
||||
const ret = switch (r.methodAsEnum()) {
|
||||
.GET => self.wrapped.*.get(arena, app_context, r),
|
||||
.POST => self.wrapped.*.post(arena, app_context, r),
|
||||
.PUT => self.wrapped.*.put(arena, app_context, r),
|
||||
.DELETE => self.wrapped.*.delete(arena, app_context, r),
|
||||
.PATCH => self.wrapped.*.patch(arena, app_context, r),
|
||||
.OPTIONS => self.wrapped.*.options(arena, app_context, r),
|
||||
.GET => self.endpoint.*.get(arena, app_context, r),
|
||||
.POST => self.endpoint.*.post(arena, app_context, r),
|
||||
.PUT => self.endpoint.*.put(arena, app_context, r),
|
||||
.DELETE => self.endpoint.*.delete(arena, app_context, r),
|
||||
.PATCH => self.endpoint.*.patch(arena, app_context, r),
|
||||
.OPTIONS => self.endpoint.*.options(arena, app_context, r),
|
||||
else => error.UnsupportedHtmlRequestMethod,
|
||||
};
|
||||
if (ret) {
|
||||
// handled without error
|
||||
} else |err| {
|
||||
switch (self.wrapped.*.error_strategy) {
|
||||
switch (self.endpoint.*.error_strategy) {
|
||||
.raise => return err,
|
||||
.log_to_response => return r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505),
|
||||
.log_to_console => zap.debug("Error in {} {s} : {}", .{ Wrapped, r.method orelse "(no method)", err }),
|
||||
.log_to_console => zap.debug(
|
||||
"Error in {} {s} : {}",
|
||||
.{ Bound, r.method orelse "(no method)", err },
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn init(T: type, value: *T) Endpoint.Wrap(T) {
|
||||
checkEndpointType(T);
|
||||
pub fn init(ArbitraryEndpoint: type, endpoint: *ArbitraryEndpoint) Endpoint.Bind(ArbitraryEndpoint) {
|
||||
checkEndpointType(ArbitraryEndpoint);
|
||||
const BoundEp = Endpoint.Bind(ArbitraryEndpoint);
|
||||
return .{
|
||||
.wrapped = value,
|
||||
.endpoint = endpoint,
|
||||
.interface = .{
|
||||
.path = value.path,
|
||||
.call = Endpoint.Wrap(T).onRequestWrapped,
|
||||
.destroy = Endpoint.Wrap(T).destroy,
|
||||
.path = endpoint.path,
|
||||
.call = BoundEp.onRequestInterface,
|
||||
.destroy = BoundEp.destroy,
|
||||
},
|
||||
.app_context = _static.context,
|
||||
};
|
||||
|
@ -262,9 +265,9 @@ pub fn Create(comptime Context: type) type {
|
|||
}
|
||||
const EndpointType = @typeInfo(@TypeOf(endpoint)).pointer.child;
|
||||
Endpoint.checkEndpointType(EndpointType);
|
||||
const wrapper = try _static.gpa.create(Endpoint.Wrap(EndpointType));
|
||||
wrapper.* = Endpoint.init(EndpointType, endpoint);
|
||||
try _static.endpoints.append(_static.gpa, &wrapper.interface);
|
||||
const bound = try _static.gpa.create(Endpoint.Bind(EndpointType));
|
||||
bound.* = Endpoint.init(EndpointType, endpoint);
|
||||
try _static.endpoints.append(_static.gpa, &bound.interface);
|
||||
}
|
||||
|
||||
pub fn listen(_: *App, l: ListenerSettings) !void {
|
||||
|
@ -284,9 +287,9 @@ pub fn Create(comptime Context: type) type {
|
|||
|
||||
fn onRequest(r: Request) !void {
|
||||
if (r.path) |p| {
|
||||
for (_static.endpoints.items) |wrapper| {
|
||||
if (std.mem.startsWith(u8, p, wrapper.path)) {
|
||||
return try wrapper.call(wrapper, r);
|
||||
for (_static.endpoints.items) |interface| {
|
||||
if (std.mem.startsWith(u8, p, interface.path)) {
|
||||
return try interface.call(interface, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,66 +106,68 @@ pub fn checkEndpointType(T: type) void {
|
|||
}
|
||||
}
|
||||
|
||||
pub const Wrapper = struct {
|
||||
pub const Binder = struct {
|
||||
pub const Interface = struct {
|
||||
call: *const fn (*Interface, zap.Request) anyerror!void = undefined,
|
||||
path: []const u8,
|
||||
destroy: *const fn (allocator: std.mem.Allocator, *Interface) void = undefined,
|
||||
destroy: *const fn (*Interface, std.mem.Allocator) void = undefined,
|
||||
};
|
||||
pub fn Wrap(T: type) type {
|
||||
pub fn Bind(ArbitraryEndpoint: type) type {
|
||||
return struct {
|
||||
wrapped: *T,
|
||||
wrapper: Interface,
|
||||
endpoint: *ArbitraryEndpoint,
|
||||
interface: Interface,
|
||||
|
||||
const Wrapped = @This();
|
||||
const Bound = @This();
|
||||
|
||||
pub fn unwrap(wrapper: *Interface) *Wrapped {
|
||||
const self: *Wrapped = @alignCast(@fieldParentPtr("wrapper", wrapper));
|
||||
pub fn unwrap(interface: *Interface) *Bound {
|
||||
const self: *Bound = @alignCast(@fieldParentPtr("interface", interface));
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn destroy(allocator: std.mem.Allocator, wrapper: *Interface) void {
|
||||
const self: *Wrapped = @alignCast(@fieldParentPtr("wrapper", wrapper));
|
||||
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
|
||||
const self: *Bound = @alignCast(@fieldParentPtr("interface", interface));
|
||||
allocator.destroy(self);
|
||||
}
|
||||
|
||||
pub fn onRequestWrapped(wrapper: *Interface, r: zap.Request) !void {
|
||||
var self: *Wrapped = Wrapped.unwrap(wrapper);
|
||||
pub fn onRequestInterface(interface: *Interface, r: zap.Request) !void {
|
||||
var self: *Bound = Bound.unwrap(interface);
|
||||
try self.onRequest(r);
|
||||
}
|
||||
|
||||
pub fn onRequest(self: *Wrapped, r: zap.Request) !void {
|
||||
pub fn onRequest(self: *Bound, r: zap.Request) !void {
|
||||
const ret = switch (r.methodAsEnum()) {
|
||||
.GET => self.wrapped.*.get(r),
|
||||
.POST => self.wrapped.*.post(r),
|
||||
.PUT => self.wrapped.*.put(r),
|
||||
.DELETE => self.wrapped.*.delete(r),
|
||||
.PATCH => self.wrapped.*.patch(r),
|
||||
.OPTIONS => self.wrapped.*.options(r),
|
||||
.GET => self.endpoint.*.get(r),
|
||||
.POST => self.endpoint.*.post(r),
|
||||
.PUT => self.endpoint.*.put(r),
|
||||
.DELETE => self.endpoint.*.delete(r),
|
||||
.PATCH => self.endpoint.*.patch(r),
|
||||
.OPTIONS => self.endpoint.*.options(r),
|
||||
else => error.UnsupportedHtmlRequestMethod,
|
||||
};
|
||||
if (ret) {
|
||||
// handled without error
|
||||
} else |err| {
|
||||
switch (self.wrapped.*.error_strategy) {
|
||||
switch (self.endpoint.*.error_strategy) {
|
||||
.raise => return err,
|
||||
.log_to_response => return r.sendError(err, if (@errorReturnTrace()) |t| t.* else null, 505),
|
||||
.log_to_console => zap.debug("Error in {} {s} : {}", .{ Wrapped, r.method orelse "(no method)", err }),
|
||||
.log_to_console => zap.debug("Error in {} {s} : {}", .{ Bound, r.method orelse "(no method)", err }),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn init(T: type, value: *T) Wrapper.Wrap(T) {
|
||||
checkEndpointType(T);
|
||||
var ret: Wrapper.Wrap(T) = .{
|
||||
.wrapped = value,
|
||||
.wrapper = .{ .path = value.path },
|
||||
pub fn init(ArbitraryEndpoint: type, value: *ArbitraryEndpoint) Binder.Bind(ArbitraryEndpoint) {
|
||||
checkEndpointType(ArbitraryEndpoint);
|
||||
const BoundEp = Binder.Bind(ArbitraryEndpoint);
|
||||
return .{
|
||||
.endpoint = value,
|
||||
.interface = .{
|
||||
.path = value.path,
|
||||
.call = BoundEp.onRequestInterface,
|
||||
.destroy = BoundEp.destroy,
|
||||
},
|
||||
};
|
||||
ret.wrapper.call = Wrapper.Wrap(T).onRequestWrapped;
|
||||
ret.wrapper.destroy = Wrapper.Wrap(T).destroy;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -262,7 +264,7 @@ pub const Listener = struct {
|
|||
allocator: std.mem.Allocator,
|
||||
|
||||
/// Internal static interface struct of member endpoints
|
||||
var endpoints: std.ArrayListUnmanaged(*Wrapper.Interface) = .empty;
|
||||
var endpoints: std.ArrayListUnmanaged(*Binder.Interface) = .empty;
|
||||
|
||||
/// Internal, static request handler callback. Will be set to the optional,
|
||||
/// user-defined request callback that only gets called if no endpoints match
|
||||
|
@ -296,8 +298,8 @@ pub const Listener = struct {
|
|||
/// Registered endpoints will not be de-initialized automatically; just removed
|
||||
/// from the internal map.
|
||||
pub fn deinit(self: *Listener) void {
|
||||
for (endpoints.items) |endpoint_wrapper| {
|
||||
endpoint_wrapper.destroy(self.allocator, endpoint_wrapper);
|
||||
for (endpoints.items) |interface| {
|
||||
interface.destroy(interface, self.allocator);
|
||||
}
|
||||
endpoints.deinit(self.allocator);
|
||||
}
|
||||
|
@ -328,16 +330,16 @@ pub const Listener = struct {
|
|||
}
|
||||
const EndpointType = @typeInfo(@TypeOf(e)).pointer.child;
|
||||
checkEndpointType(EndpointType);
|
||||
const wrapper = try self.allocator.create(Wrapper.Wrap(EndpointType));
|
||||
wrapper.* = Wrapper.init(EndpointType, e);
|
||||
try endpoints.append(self.allocator, &wrapper.wrapper);
|
||||
const bound = try self.allocator.create(Binder.Bind(EndpointType));
|
||||
bound.* = Binder.init(EndpointType, e);
|
||||
try endpoints.append(self.allocator, &bound.interface);
|
||||
}
|
||||
|
||||
fn onRequest(r: Request) !void {
|
||||
if (r.path) |p| {
|
||||
for (endpoints.items) |wrapper| {
|
||||
if (std.mem.startsWith(u8, p, wrapper.path)) {
|
||||
return try wrapper.call(wrapper, r);
|
||||
for (endpoints.items) |interface| {
|
||||
if (std.mem.startsWith(u8, p, interface.path)) {
|
||||
return try interface.call(interface, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue