lib/choir/src/composition/module/serialization/source.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const composition = @import("../../root.zig");
3 const serialization = @import("root.zig");
4
5 const source = composition.source;
6 const Reader = serialization.format.Reader;
7 const Writer = serialization.format.Writer;
8
9 pub fn write(writer: *Writer, module: *const source.PartitionedModule) serialization.SerializeError!void {
10 try writer.writeString(module.name);
11 try writer.writeCount(module.boundaries.items.len);
12 for (module.boundaries.items) |boundary_value| try writeBoundary(writer, boundary_value);
13 try writer.writeCount(module.partitions.items.len);
14 for (module.partitions.items) |partition_value| try writePartition(writer, partition_value);
15 try writer.writeCount(module.call_sites.items.len);
16 for (module.call_sites.items) |call_site| try writeCall(writer, call_site);
17 }
18
19 pub fn read(allocator: std.mem.Allocator, reader: *Reader) serialization.DeserializeError!source.PartitionedModule {
20 var module = try source.PartitionedModule.init(allocator, try reader.readString());
21 errdefer module.deinit();
22
23 const boundary_count = try reader.readCount();
24 for (0..boundary_count) |_| try readBoundary(allocator, reader, &module);
25 const partition_count = try reader.readCount();
26 for (0..partition_count) |_| try readPartition(allocator, reader, &module);
27 const call_count = try reader.readCount();
28 for (0..call_count) |_| try readCall(allocator, reader, &module);
29 return module;
30 }
31
32 fn writeBoundary(writer: *Writer, value: source.Boundary) serialization.SerializeError!void {
33 try writer.writeInt(u64, value.id.value);
34 try writer.writeString(value.name);
35 try writer.writeTag(value.element_type);
36 try writeDimensions(writer, value.dimensions);
37 try writer.writeInt(u64, value.byte_size);
38 try writer.writeTag(value.access);
39 try writer.writeTag(value.ownership);
40 try writeAlias(writer, value.alias);
41 try serialization.provenance.write(writer, value.provenance);
42 }
43
44 fn readBoundary(
45 allocator: std.mem.Allocator,
46 reader: *Reader,
47 module: *source.PartitionedModule,
48 ) serialization.DeserializeError!void {
49 const id = source.BoundaryId{ .value = try reader.readInt(u64) };
50 const name = try reader.readString();
51 const element_type = try reader.readTag(source.ElementType);
52 const dimensions = try readDimensions(allocator, reader);
53 defer allocator.free(dimensions);
54 const byte_size = try reader.readInt(u64);
55 const access = try reader.readTag(source.Access);
56 const ownership = try reader.readTag(source.Ownership);
57 const alias = try readAlias(reader);
58 const provenance = try serialization.provenance.read(reader);
59 try module.addBoundary(.{
60 .id = id,
61 .name = name,
62 .element_type = element_type,
63 .dimensions = dimensions,
64 .byte_size = byte_size,
65 .access = access,
66 .ownership = ownership,
67 .alias = alias,
68 .provenance = provenance,
69 });
70 }
71
72 fn writeAlias(writer: *Writer, alias: source.Alias) serialization.SerializeError!void {
73 const Tag = std.meta.Tag(source.Alias);
74 try writer.writeTag(@as(Tag, alias));
75 switch (alias) {
76 .disjoint => {},
77 .boundary => |id| try writer.writeInt(u64, id.value),
78 }
79 }
80
81 fn readAlias(reader: *Reader) serialization.DeserializeError!source.Alias {
82 const Tag = std.meta.Tag(source.Alias);
83 return switch (try reader.readTag(Tag)) {
84 .disjoint => .disjoint,
85 .boundary => .{ .boundary = .{ .value = try reader.readInt(u64) } },
86 };
87 }
88
89 fn writePartition(writer: *Writer, value: source.Partition) serialization.SerializeError!void {
90 try writer.writeInt(u64, value.id.value);
91 try writer.writeString(value.name);
92 try writer.writeTag(value.pipeline);
93 try writeBoundaryIds(writer, value.inputs);
94 try writeBoundaryIds(writer, value.outputs);
95 try serialization.reference.writeAddress(writer, value.product);
96 try writer.writeTag(value.effect);
97 try serialization.provenance.write(writer, value.provenance);
98 }
99
100 fn readPartition(
101 allocator: std.mem.Allocator,
102 reader: *Reader,
103 module: *source.PartitionedModule,
104 ) serialization.DeserializeError!void {
105 const id = source.PartitionId{ .value = try reader.readInt(u64) };
106 const name = try reader.readString();
107 const pipeline = try reader.readTag(source.Pipeline);
108 const inputs = try readBoundaryIds(allocator, reader);
109 defer allocator.free(inputs);
110 const outputs = try readBoundaryIds(allocator, reader);
111 defer allocator.free(outputs);
112 const address = try serialization.reference.readAddress(reader);
113 const effect = try reader.readTag(source.Effect);
114 const provenance = try serialization.provenance.read(reader);
115 try module.addPartition(.{
116 .id = id,
117 .name = name,
118 .pipeline = pipeline,
119 .inputs = inputs,
120 .outputs = outputs,
121 .product = address,
122 .effect = effect,
123 .provenance = provenance,
124 });
125 }
126
127 fn writeCall(writer: *Writer, value: source.SemanticCallSite) serialization.SerializeError!void {
128 try writer.writeInt(u64, value.id.value);
129 try writer.writeString(value.name);
130 try writer.writeInt(u64, value.caller.value);
131 try writer.writeInt(u64, value.callee.value);
132 try writeBoundaryIds(writer, value.inputs);
133 try writeBoundaryIds(writer, value.outputs);
134 try serialization.provenance.write(writer, value.provenance);
135 }
136
137 fn readCall(
138 allocator: std.mem.Allocator,
139 reader: *Reader,
140 module: *source.PartitionedModule,
141 ) serialization.DeserializeError!void {
142 const id = source.CallSiteId{ .value = try reader.readInt(u64) };
143 const name = try reader.readString();
144 const caller = source.PartitionId{ .value = try reader.readInt(u64) };
145 const callee = source.PartitionId{ .value = try reader.readInt(u64) };
146 const inputs = try readBoundaryIds(allocator, reader);
147 defer allocator.free(inputs);
148 const outputs = try readBoundaryIds(allocator, reader);
149 defer allocator.free(outputs);
150 const provenance = try serialization.provenance.read(reader);
151 try module.addCallSite(.{
152 .id = id,
153 .name = name,
154 .caller = caller,
155 .callee = callee,
156 .inputs = inputs,
157 .outputs = outputs,
158 .provenance = provenance,
159 });
160 }
161
162 pub fn writeBoundaryIds(writer: *Writer, ids: []const source.BoundaryId) serialization.SerializeError!void {
163 try writer.writeCount(ids.len);
164 for (ids) |id| try writer.writeInt(u64, id.value);
165 }
166
167 pub fn readBoundaryIds(allocator: std.mem.Allocator, reader: *Reader) serialization.DeserializeError![]source.BoundaryId {
168 const count = try reader.readCount();
169 const ids = try allocator.alloc(source.BoundaryId, count);
170 errdefer allocator.free(ids);
171 for (ids) |*id| id.* = .{ .value = try reader.readInt(u64) };
172 return ids;
173 }
174
175 fn writeDimensions(writer: *Writer, dimensions: []const u64) serialization.SerializeError!void {
176 try writer.writeCount(dimensions.len);
177 for (dimensions) |dimension| try writer.writeInt(u64, dimension);
178 }
179
180 fn readDimensions(allocator: std.mem.Allocator, reader: *Reader) serialization.DeserializeError![]u64 {
181 const count = try reader.readCount();
182 const dimensions = try allocator.alloc(u64, count);
183 errdefer allocator.free(dimensions);
184 for (dimensions) |*dimension| dimension.* = try reader.readInt(u64);
185 return dimensions;
186 }