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 };