From 49a0f86e44bb9100bd19c18d4bbb5c3d2f47a803 Mon Sep 17 00:00:00 2001 From: Jeeves Date: Tue, 29 Apr 2025 11:59:55 -0600 Subject: [PATCH] finish some TODOs --- src/main.zig | 131 ++++++++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 59 deletions(-) diff --git a/src/main.zig b/src/main.zig index 265996c..8786d29 100644 --- a/src/main.zig +++ b/src/main.zig @@ -198,8 +198,8 @@ pub const Circuit = struct { // i.e. it hasn't already been added to the process list, but all its inputs have. if (visited[new_idx]) continue :connections; for (connection.component.inputs.items) |input| { - if (input.connection) |input_component| { - if (!visited[self.componentIndex(input_component).?]) { + if (input.connection) |input_connection| { + if (!visited[self.componentIndex(input_connection.component).?]) { continue :connections; } } @@ -245,11 +245,13 @@ pub const Component = struct { deinitFn: *const fn (*Component, std.mem.Allocator) void, pub const Input = struct { - // TODO just allow this to be null and handle that codepath in a user-configurable way - signal: *Signal = &null_signal, - // TODO update this to match the Output.Connection interface (without the ArrayList) - connection: ?*Component = null, - idx: usize = 0, + signal: ?*Signal = null, + connection: ?Connection = null, + + pub const Connection = struct { + component: *Component, + idx: usize, + }; }; pub const Output = struct { signal: Signal = .{}, @@ -325,8 +327,10 @@ pub const Component = struct { fn connect(self: *Component, allocator: std.mem.Allocator, self_idx: usize, to: *Component, to_idx: usize) !void { const input = &to.inputs.items[to_idx]; input.signal = &self.outputs.items[self_idx].signal; - input.connection = self; - input.idx = self_idx; + input.connection = .{ + .component = self, + .idx = self_idx, + }; const output = &self.outputs.items[self_idx]; try output.connections.append(allocator, .{ @@ -445,12 +449,13 @@ pub const Not = struct { pub fn process(component: *Component) AllocatorError!void { const self: *Not = @fieldParentPtr("component", component); + const input = if (component.inputs.items[0].signal) |s| s else &Signal{}; if (self.invert_output) { - component.outputs.items[0].signal.digital = 1 - @as(i2, @intCast(@abs(component.inputs.items[0].signal.digital))); - component.outputs.items[0].signal.analog = 1.0 - @abs(component.inputs.items[0].signal.analog); + component.outputs.items[0].signal.digital = 1 - @as(i2, @intCast(@abs(input.digital))); + component.outputs.items[0].signal.analog = 1.0 - @abs(input.analog); } else { - component.outputs.items[0].signal.digital = component.inputs.items[0].signal.digital; - component.outputs.items[0].signal.analog = component.inputs.items[0].signal.analog; + component.outputs.items[0].signal.digital = input.digital; + component.outputs.items[0].signal.analog = input.analog; } component.outputs.items[0].signal.analog = std.math.clamp(component.outputs.items[0].signal.analog, -1.0, 1.0); } @@ -479,22 +484,25 @@ pub const And = struct { // TODO check implementation pub fn process(component: *Component) AllocatorError!void { const self: *And = @fieldParentPtr("component", component); + const input0 = if (component.inputs.items[0].signal) |s| s else &Signal{}; if (self.arithmetic_mode) { - component.outputs.items[0].signal.digital = component.inputs.items[0].signal.digital; - component.outputs.items[0].signal.analog = component.inputs.items[0].signal.analog; - for (component.inputs.items[1..]) |input| { + component.outputs.items[0].signal.digital = input0.digital; + component.outputs.items[0].signal.analog = input0.analog; + for (component.inputs.items[1..]) |opt_input| { + const input = if (opt_input.signal) |s| s else &Signal{}; component.outputs.items[0].signal.digital = 0; // TODO - component.outputs.items[0].signal.analog *= input.signal.analog; + component.outputs.items[0].signal.analog *= input.analog; } } else { - component.outputs.items[0].signal.digital = component.inputs.items[0].signal.digital; - component.outputs.items[0].signal.analog = component.inputs.items[0].signal.analog; - for (component.inputs.items[1..]) |input| { + component.outputs.items[0].signal.digital = input0.digital; + component.outputs.items[0].signal.analog = input0.analog; + for (component.inputs.items[1..]) |opt_input| { + const input = if (opt_input.signal) |s| s else &Signal{}; component.outputs.items[0].signal.digital = 0; // TODO - component.outputs.items[0].signal.analog = switch (std.math.order(@abs(component.outputs.items[0].signal.analog), @abs(input.signal.analog))) { + component.outputs.items[0].signal.analog = switch (std.math.order(@abs(component.outputs.items[0].signal.analog), @abs(input.analog))) { .lt => component.outputs.items[0].signal.analog, - .eq => @min(component.outputs.items[0].signal.analog, input.signal.analog), // TODO what does this *actually* do? - .gt => input.signal.analog, + .eq => @min(component.outputs.items[0].signal.analog, input.analog), // TODO what does this *actually* do? + .gt => input.analog, }; } } @@ -502,22 +510,23 @@ pub const And = struct { } }; -// TODO update test to use new Component interface -// test "min" { -// var a = Signal{ .analog = 0.0 }; -// var b = Signal{ .analog = 1.0 }; +test "min" { + var a = Signal{ .analog = 0.0 }; + var b = Signal{ .analog = 1.0 }; -// var inputs = [_]*Signal{ &a, &b }; -// var and1 = And{ .inputs = &inputs }; + var and1 = try And.init(std.testing.allocator); + defer and1.component.deinit(std.testing.allocator); + and1.component.inputs.items[0].signal = &a; + and1.component.inputs.items[1].signal = &b; -// and1.process(); -// try std.testing.expectEqual(0.0, and1.output.analog); + try and1.component.process(); + try std.testing.expectEqual(0.0, and1.component.outputs.items[0].signal.analog); -// a.analog = -0.5; -// b.analog = -0.2; -// and1.process(); -// try std.testing.expectEqual(-0.2, and1.output.analog); -// } + a.analog = -0.5; + b.analog = -0.2; + try and1.component.process(); + try std.testing.expectEqual(-0.2, and1.component.outputs.items[0].signal.analog); +} pub const Or = struct { component: Component, @@ -542,21 +551,24 @@ pub const Or = struct { // TODO check implementation pub fn process(component: *Component) AllocatorError!void { const self: *Or = @fieldParentPtr("component", component); + const input0 = if (component.inputs.items[0].signal) |s| s else &Signal{}; if (self.arithmetic_mode) { - component.outputs.items[0].signal.digital = component.inputs.items[0].signal.digital; - component.outputs.items[0].signal.analog = component.inputs.items[0].signal.analog; - for (component.inputs.items[1..]) |input| { + component.outputs.items[0].signal.digital = input0.digital; + component.outputs.items[0].signal.analog = input0.analog; + for (component.inputs.items[1..]) |opt_input| { + const input = if (opt_input.signal) |s| s else &Signal{}; component.outputs.items[0].signal.digital = 0; // TODO - component.outputs.items[0].signal.analog += input.signal.analog; + component.outputs.items[0].signal.analog += input.analog; } } else { - component.outputs.items[0].signal.digital = component.inputs.items[0].signal.digital; - component.outputs.items[0].signal.analog = component.inputs.items[0].signal.analog; - for (component.inputs.items[1..]) |input| { + component.outputs.items[0].signal.digital = input0.digital; + component.outputs.items[0].signal.analog = input0.analog; + for (component.inputs.items[1..]) |opt_input| { + const input = if (opt_input.signal) |s| s else &Signal{}; component.outputs.items[0].signal.digital = 0; // TODO - component.outputs.items[0].signal.analog = switch (std.math.order(@abs(component.outputs.items[0].signal.analog), @abs(input.signal.analog))) { - .lt => input.signal.analog, - .eq => @max(component.outputs.items[0].signal.analog, input.signal.analog), // TODO what does this *actually* do? + component.outputs.items[0].signal.analog = switch (std.math.order(@abs(component.outputs.items[0].signal.analog), @abs(input.analog))) { + .lt => input.analog, + .eq => @max(component.outputs.items[0].signal.analog, input.analog), // TODO what does this *actually* do? .gt => component.outputs.items[0].signal.analog, }; } @@ -565,21 +577,22 @@ pub const Or = struct { } }; -// TODO update test to use new Component interface -// test "max" { -// var a = Signal{ .analog = 0.0 }; -// var b = Signal{ .analog = 1.0 }; +test "max" { + var a = Signal{ .analog = 0.0 }; + var b = Signal{ .analog = 1.0 }; -// var inputs = [_]*Signal{ &a, &b }; -// var or1 = Or{ .inputs = &inputs }; + var or1 = try Or.init(std.testing.allocator); + defer or1.component.deinit(std.testing.allocator); + or1.component.inputs.items[0].signal = &a; + or1.component.inputs.items[1].signal = &b; -// or1.process(); -// try std.testing.expectEqual(1.0, or1.output.analog); + try or1.component.process(); + try std.testing.expectEqual(1.0, or1.component.outputs.items[0].signal.analog); -// a.analog = -0.5; -// b.analog = -0.2; -// or1.process(); -// try std.testing.expectEqual(-0.5, or1.output.analog); -// } + a.analog = -0.5; + b.analog = -0.2; + try or1.component.process(); + try std.testing.expectEqual(-0.5, or1.component.outputs.items[0].signal.analog); +} const AllocatorError = std.mem.Allocator.Error;