lib/accy/src/tensor/interpret/spec.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const dispatch = @import("layer.zig");
2
3 pub fn with(impl: anytype) With(@TypeOf(impl)) {
4 return .{ .impl = impl };
5 }
6
7 pub fn bind(impl: anytype) With(@TypeOf(impl)) {
8 return with(impl);
9 }
10
11 pub fn With(comptime Impl: type) type {
12 return struct {
13 impl: Impl,
14
15 pub fn attach(self: @This(), next: anytype) Layer(stateValue(@TypeOf(next)), @TypeOf(next), Impl) {
16 return .{
17 .next = next,
18 .impl = self.impl,
19 };
20 }
21 };
22 }
23
24 pub fn stack(specs: anytype) Stack(@TypeOf(specs)) {
25 return .{ .specs = specs };
26 }
27
28 pub fn Stack(comptime Specs: type) type {
29 _ = stackLength(Specs);
30 return struct {
31 specs: Specs,
32
33 pub fn attach(self: @This(), next: anytype) StackAttach(0, Specs, @TypeOf(next)) {
34 return attachFrom(0, self.specs, next);
35 }
36 };
37 }
38
39 pub fn layer(comptime BoundValue: type, next: anytype, impl: anytype) Layer(BoundValue, @TypeOf(next), @TypeOf(impl)) {
40 return .{
41 .next = next,
42 .impl = impl,
43 };
44 }
45
46 pub fn Layer(comptime BoundValue: type, comptime Next: type, comptime Impl: type) type {
47 return dispatch.Layer(BoundValue, Next, Impl);
48 }
49
50 fn stateValue(comptime StateType: type) type {
51 return switch (@typeInfo(StateType)) {
52 .pointer => |info| info.child.Value,
53 else => StateType.Value,
54 };
55 }
56
57 fn stackLength(comptime Specs: type) comptime_int {
58 const info = @typeInfo(Specs);
59 if (info != .@"struct" or !info.@"struct".is_tuple) {
60 @compileError("tensor.interpret.stack expects a tuple of interpreter specs");
61 }
62 if (info.@"struct".field_names.len == 0) {
63 @compileError("tensor.interpret.stack expects at least one interpreter spec");
64 }
65 return info.@"struct".field_names.len;
66 }
67
68 fn StackAttach(comptime index: usize, comptime Specs: type, comptime Next: type) type {
69 const len = stackLength(Specs);
70 if (index == len) return Next;
71 const Spec = @typeInfo(Specs).@"struct".field_types[index];
72 return @TypeOf(@as(Spec, undefined).attach(@as(StackAttach(index + 1, Specs, Next), undefined)));
73 }
74
75 fn attachFrom(comptime index: usize, specs: anytype, next: anytype) StackAttach(index, @TypeOf(specs), @TypeOf(next)) {
76 if (comptime index == stackLength(@TypeOf(specs))) return next;
77 const inner = attachFrom(index + 1, specs, next);
78 return @field(specs, @typeInfo(@TypeOf(specs)).@"struct".field_names[index]).attach(inner);
79 }