lib/choir/src/composition/module/fragment.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const choir = @import("../../root.zig");
3 const composition = @import("../root.zig");
4 const model = @import("root.zig");
5
6 const Allocator = std.mem.Allocator;
7 const Artifact = choir.backends.artifact.Artifact;
8 const product = choir.product;
9 const source = composition.source;
10
11 /// Borrowed serializable inputs for one compiled partition.
12 pub const FragmentSpec = struct {
13 id: source.FragmentId,
14 partition: source.PartitionId,
15 pipeline: source.Pipeline,
16 pipeline_input: product.ProductKey,
17 artifacts: []const Artifact,
18 exports: []const model.ExportSpec,
19 imports: []const model.ImportSpec = &.{},
20 provenance: source.ProvenanceSpec,
21 };
22
23 /// Owns artifact transport data and an exact input record; it grants no native reuse entitlement.
24 /// Process-local compiled and loaded objects remain in materialization jobs.
25 pub const Fragment = struct {
26 id: source.FragmentId,
27 partition: source.PartitionId,
28 pipeline: source.Pipeline,
29 pipeline_input: product.ProductKey,
30 artifacts: []Artifact,
31 exports: []model.Export,
32 imports: []model.Import,
33 provenance: source.Provenance,
34
35 pub fn init(allocator: Allocator, spec: FragmentSpec) product.ProductMetadataError!Fragment {
36 const pipeline_input = try product.cloneProductKey(allocator, spec.pipeline_input);
37 errdefer product.deinitProductKey(allocator, pipeline_input);
38
39 const artifacts = try allocator.alloc(Artifact, spec.artifacts.len);
40 var artifact_count: usize = 0;
41 errdefer {
42 var index = artifact_count;
43 while (index != 0) {
44 index -= 1;
45 artifacts[index].deinit();
46 }
47 allocator.free(artifacts);
48 }
49 for (spec.artifacts, 0..) |artifact_value, index| {
50 artifacts[index] = try artifact_value.clone(allocator);
51 artifact_count += 1;
52 }
53
54 const exports = try allocator.alloc(model.Export, spec.exports.len);
55 var export_count: usize = 0;
56 errdefer {
57 var index = export_count;
58 while (index != 0) {
59 index -= 1;
60 exports[index].deinit(allocator);
61 }
62 allocator.free(exports);
63 }
64 for (spec.exports, 0..) |export_spec, index| {
65 exports[index] = try model.Export.init(allocator, export_spec);
66 export_count += 1;
67 }
68
69 const imports: []model.Import = if (spec.imports.len == 0) &.{} else try allocator.alloc(model.Import, spec.imports.len);
70 var import_count: usize = 0;
71 errdefer {
72 var index = import_count;
73 while (index != 0) {
74 index -= 1;
75 imports[index].deinit(allocator);
76 }
77 if (imports.len != 0) allocator.free(imports);
78 }
79 for (spec.imports, 0..) |import_spec, index| {
80 imports[index] = try model.Import.init(allocator, import_spec);
81 import_count += 1;
82 }
83
84 return .{
85 .id = spec.id,
86 .partition = spec.partition,
87 .pipeline = spec.pipeline,
88 .pipeline_input = pipeline_input,
89 .artifacts = artifacts,
90 .exports = exports,
91 .imports = imports,
92 .provenance = try source.Provenance.init(allocator, spec.provenance),
93 };
94 }
95
96 pub fn deinit(self: *Fragment, allocator: Allocator) void {
97 self.provenance.deinit(allocator);
98 var import_index = self.imports.len;
99 while (import_index != 0) {
100 import_index -= 1;
101 self.imports[import_index].deinit(allocator);
102 }
103 if (self.imports.len != 0) allocator.free(self.imports);
104 var export_index = self.exports.len;
105 while (export_index != 0) {
106 export_index -= 1;
107 self.exports[export_index].deinit(allocator);
108 }
109 allocator.free(self.exports);
110 var artifact_index = self.artifacts.len;
111 while (artifact_index != 0) {
112 artifact_index -= 1;
113 self.artifacts[artifact_index].deinit();
114 }
115 allocator.free(self.artifacts);
116 product.deinitProductKey(allocator, self.pipeline_input);
117 self.* = undefined;
118 }
119
120 pub fn exportByName(self: *const Fragment, name: []const u8) ?*const model.Export {
121 for (self.exports) |*export_value| {
122 if (std.mem.eql(u8, export_value.name, name)) return export_value;
123 }
124 return null;
125 }
126
127 pub fn importByName(self: *const Fragment, name: []const u8) ?*const model.Import {
128 for (self.imports) |*import_value| {
129 if (std.mem.eql(u8, import_value.name, name)) return import_value;
130 }
131 return null;
132 }
133
134 pub fn providesSymbol(self: *const Fragment, symbol: []const u8) bool {
135 for (self.artifacts) |artifact_value| {
136 if (artifact_value.linkage.hasProvided(symbol)) return true;
137 }
138 return false;
139 }
140
141 pub fn requiresSymbol(self: *const Fragment, symbol: []const u8) bool {
142 for (self.artifacts) |artifact_value| {
143 if (artifact_value.linkage.hasRequired(symbol)) return true;
144 }
145 return false;
146 }
147 };