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); } };