const video = @import("video.zig"); const audio = @import("audio.zig"); const input = @import("input.zig"); const storage = @import("storage.zig"); pub const Spec = struct { name: []const u8, video_outputs: []const video.VideoOutputSpec = &.{}, audio_outputs: []const audio.StreamSpec = &.{}, audio_inputs: []const audio.StreamSpec = &.{}, input_devices: []const input.DeviceSpec = &.{}, storage_devices: []const storage.Spec = &.{}, }; pub fn validate(comptime System: type) void { comptime { if (!@hasDecl(System, "spec")) { @compileError( "System must expose `pub const spec: contract.SystemSpec`", ); } if (@TypeOf(System.spec) != Spec) { @compileError( "`System.spec` must have type contract.SystemSpec", ); } requireFunction( System, "reset", fn (*System) void, ); requireFunction( System, "runFrame", fn (*System) void, ); if (System.spec.video_outputs.len != 0) { requireFunction( System, "videoFrame", fn (*const System, usize) video.VideoFrame, ); } if (System.spec.audio_outputs.len != 0) { requireFunction( System, "audioBuffer", fn (*const System, usize) audio.Buffer, ); } if (System.spec.audio_inputs.len != 0) { requireFunction( System, "submitAudioInput", fn (*System, usize, audio.Buffer) void, ); } if (System.spec.input_devices.len != 0) { requireFunction( System, "setInput", fn (*System, usize, input.DeviceInput) void, ); } var has_haptics = false; for (System.spec.input_devices) |device| { if (device.haptic_count != 0) { has_haptics = true; break; } } if (has_haptics) { requireFunction( System, "deviceFeedback", fn (*const System, usize) input.DeviceFeedback, ); } if (System.spec.storage_devices.len != 0) { requireFunction( System, "storageView", fn (*const System, usize) storage.View, ); requireFunction( System, "loadStorage", fn ( *System, usize, []const u8, ) storage.LoadError!void, ); } } } fn requireFunction( comptime System: type, comptime name: []const u8, comptime Expected: type, ) void { if (!@hasDecl(System, name)) { @compileError( "System must implement `" ++ name ++ "`", ); } const Actual = @TypeOf(@field(System, name)); if (Actual != Expected) { @compileError( "`" ++ name ++ "` has an invalid signature", ); } }