pgmql/lib/dispatchers.zig

127 lines
4.1 KiB
Zig

const std = @import("std");
const zzz = @import("zzz");
const _comptime = @import("utils/comptime.zig");
/// Type of a dispatcher run function.
pub fn DispatchFunction(AuthenticationType: type, PayloadType: type) type {
return *const fn(context: DispatcherContext(AuthenticationType, PayloadType)) void;
}
/// Model dispatcher runtime context structure.
pub fn DispatcherContext(AuthenticationType: type, PayloadType: type) type {
return struct {
/// Payload of the running dispatch.
payload: *const PayloadType,
/// The authenticated account, if there is one. NULL = no authenticated account.
account: ?*AuthenticationType,
};
}
/// Dispatcher builder interface.
pub const DispatcherBuilder = struct {
build: *const fn (comptime modelName: []const u8, comptime dispatchName: []const u8) Dispatcher,
};
/// Compile-time model dispatcher definition structure.
pub fn DispatcherDefinition(AuthenticationType: type, PayloadType: type) type {
return struct {
const Self = @This();
pub const Context = DispatcherContext(AuthenticationType, PayloadType);
pub const Policy = DispatcherPolicy(AuthenticationType, PayloadType);
pub const PolicyContext = DispatcherPolicyContext(AuthenticationType, PayloadType);
pub const Dispatch = DispatchFunction(AuthenticationType, PayloadType);
/// Dispatcher call policy.
policy: Policy,
/// Run function of the dispatcher.
run: Dispatch,
/// HTTP method to use in HTTP API for this dispatcher.
httpMethod: zzz.HTTP.Method = zzz.HTTP.Method.GET,
/// Initialize a dispatcher builder for the defined dispatcher.
pub fn builder(comptime self: *const Self) DispatcherBuilder {
return DispatcherBuilder{
.build = struct {
fn f(comptime modelName: []const u8, comptime dispatchName: []const u8) Dispatcher {
// Build the model identifier from the model name.
const modelIdentifier = comptime _comptime.pascalToKebab(modelName);
return Dispatcher{
._interface = .{
.instance = self,
.getModelIdentifier = struct { pub fn f(_: *const anyopaque) []const u8 {
return modelIdentifier;
} }.f,
.getDispatchName = struct { pub fn f(_: *const anyopaque) []const u8 {
return dispatchName;
} }.f,
.getHttpMethod = struct { pub fn f(opaqueSelf: *const anyopaque) zzz.HTTP.Method {
const impl: *const Self = @ptrCast(@alignCast(opaqueSelf));
return impl.httpMethod;
} }.f,
},
};
}
}.f,
};
}
};
}
/// Compile-time model dispatcher policy definition structure.
pub fn DispatcherPolicy(AuthenticationType: type, PayloadType: type) type {
return union(enum) {
/// Allow / disallow any call to the dispatcher.
any: bool,
/// Allow calls to the dispatcher with any authenticated account.
anyAuthenticated: bool,
/// Allow calls to the dispatcher if the defined function returns true.
func: *const fn(context: DispatcherPolicyContext(AuthenticationType, PayloadType)) bool, //TODO define rules instead of func?
};
}
/// Model dispatcher policy runtime context structure.
pub fn DispatcherPolicyContext(AuthenticationType: type, PayloadType: type) type {
return struct {
/// Payload of the running dispatch.
payload: *const PayloadType,
/// The authenticated account, if there is one. NULL = no authenticated account.
account: ?*AuthenticationType,
};
}
/// Dispatcher interface.
pub const Dispatcher = struct {
const Self = @This();
_interface: struct {
instance: *const anyopaque,
getModelIdentifier: *const fn(instance: *const anyopaque) []const u8,
getDispatchName: *const fn(instance: *const anyopaque) []const u8,
getHttpMethod: *const fn(instance: *const anyopaque) zzz.HTTP.Method,
},
/// Get model identifier.
pub fn getModelIdentifier(self: *const Self) []const u8 {
return self._interface.getModelIdentifier(self._interface.instance);
}
/// Get dispatch name.
pub fn getDispatchName(self: *const Self) []const u8 {
return self._interface.getDispatchName(self._interface.instance);
}
/// Get HTTP API method.
pub fn getHttpMethod(self: *const Self) zzz.HTTP.Method {
return self._interface.getHttpMethod(self._interface.instance);
}
};