lib/choir/src/backends/artifact/model/artifact.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 const artifact = @import("root.zig");
 3 
 4 const Allocator = std.mem.Allocator;
 5 
 6 pub const Artifact = struct {
 7     allocator: Allocator,
 8     metadata: artifact.Metadata,
 9     options: artifact.Options,
10     linkage: artifact.Linkage,
11     payload: artifact.Payload,
12     verification: artifact.VerificationStatus = .{},
13 
14     pub fn init(allocator: Allocator, metadata: artifact.Metadata) Allocator.Error!Artifact {
15         return .{
16             .allocator = allocator,
17             .metadata = try metadata.dupe(allocator),
18             .options = .init(allocator),
19             .linkage = .init(allocator),
20             .payload = .init(allocator),
21         };
22     }
23 
24     pub fn clone(self: Artifact, allocator: Allocator) Allocator.Error!Artifact {
25         var copy = try Artifact.init(allocator, self.metadata);
26         errdefer copy.deinit();
27         try self.options.cloneInto(&copy.options);
28         try self.linkage.cloneInto(&copy.linkage);
29         try self.payload.cloneInto(&copy.payload);
30         try copy.verification.replace(copy.allocator, self.verification);
31         return copy;
32     }
33 
34     pub fn eql(self: Artifact, other: Artifact) bool {
35         return self.metadata.eql(other.metadata) and
36             self.options.eql(other.options) and
37             self.linkage.eql(other.linkage) and
38             self.payload.eql(other.payload) and
39             self.verification.eql(other.verification);
40     }
41 
42     pub fn deinit(self: *Artifact) void {
43         self.options.deinit();
44         self.linkage.deinit();
45         self.payload.deinit();
46         self.verification.deinit(self.allocator);
47         self.metadata.deinit(self.allocator);
48         self.* = undefined;
49     }
50 };
51 
52 test "artifact owns provided symbol names" {
53     var value = try Artifact.init(std.testing.allocator, .{
54         .kind = .container,
55         .producer = "test",
56     });
57     defer value.deinit();
58 
59     var name = [_]u8{ 'e', 'n', 't', 'r', 'y' };
60     try value.linkage.addProvided(.{ .name = &name, .kind = .function });
61     name[0] = 'x';
62 
63     try std.testing.expectEqualStrings("entry", value.linkage.provided_symbols.items[0].name);
64     try std.testing.expect(value.linkage.hasProvided("entry"));
65 }
66 
67 test "artifact clone survives every allocation failure" {
68     const Harness = struct {
69         fn run(allocator: Allocator) !void {
70             var value = try Artifact.init(allocator, .{
71                 .kind = .object_file,
72                 .producer = "allocation",
73                 .target = .{ .architecture = .x86_64, .triple = "x86_64-linux", .features = &.{"sse2"} },
74                 .abi = .{ .name = "sysv", .calling_convention = "c", .object_format = "elf" },
75             });
76             defer value.deinit();
77             try value.options.add(.{ .key = "opt", .value = .{ .text = "speed" } });
78             try value.linkage.addRequired(.{ .name = "runtime", .kind = .runtime });
79             try value.linkage.addProvided(.{ .name = "entry", .kind = .function });
80             try value.linkage.addRelocation(.{ .offset = 0, .symbol = "runtime" });
81             try value.payload.addDebugRecord(.{ .name = "lines", .kind = .line_table, .bytes = &.{1} });
82             try value.payload.addBuffer(.{ .name = "entry.o", .format = .object_file, .bytes = &.{2} });
83             try value.payload.addTextDump(.{ .name = "ir", .contents = "entry" });
84             try value.verification.replace(value.allocator, .{ .state = .passed, .stage = "verify", .message = "ok" });
85 
86             var copy = try value.clone(allocator);
87             defer copy.deinit();
88             try std.testing.expect(copy.linkage.hasProvided("entry"));
89             try std.testing.expectEqualStrings("verify", copy.verification.stage.?);
90             try std.testing.expect(value.eql(copy));
91             copy.metadata.kind = .container;
92             try std.testing.expect(!value.eql(copy));
93         }
94     };
95 
96     try std.testing.checkAllAllocationFailures(std.testing.allocator, Harness.run, .{});
97 }