2018-07-14 12:45:15 -07:00
|
|
|
const std = @import("std");
|
2018-07-12 12:08:40 -07:00
|
|
|
const Value = @import("value.zig").Value;
|
2018-07-22 20:27:58 -07:00
|
|
|
const assert = std.debug.assert;
|
2018-07-12 12:08:40 -07:00
|
|
|
|
2020-04-18 16:41:45 -07:00
|
|
|
/// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication.
|
|
|
|
/// It's important for this struct to be small.
|
|
|
|
/// It is not copyable since it may contain references to its inner data.
|
|
|
|
/// Types are not de-duplicated, which helps with multi-threading since it obviates the requirement
|
|
|
|
/// of obtaining a lock on a global type table, as well as making the
|
|
|
|
/// garbage collection bookkeeping simpler.
|
|
|
|
/// This union takes advantage of the fact that the first page of memory
|
|
|
|
/// is unmapped, giving us 4096 possible enum tags that have no payload.
|
|
|
|
pub const Type = extern union {
|
|
|
|
/// If the tag value is less than Tag.no_payload_count, then no pointer
|
|
|
|
/// dereference is needed.
|
|
|
|
tag_if_small_enough: usize,
|
|
|
|
ptr_otherwise: *Payload,
|
|
|
|
|
|
|
|
pub fn zigTypeTag(self: Type) std.builtin.TypeId {
|
|
|
|
switch (self.tag()) {
|
|
|
|
.int_u8, .int_usize => return .Int,
|
|
|
|
.array_u8, .array_u8_sentinel_0 => return .Array,
|
|
|
|
.single_const_pointer => return .Pointer,
|
2018-07-12 12:08:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-18 17:22:54 -07:00
|
|
|
pub fn initTag(comptime small_tag: Tag) Type {
|
|
|
|
comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);
|
|
|
|
return .{ .tag_if_small_enough = @enumToInt(small_tag) };
|
2018-07-14 12:45:15 -07:00
|
|
|
}
|
|
|
|
|
2020-04-18 16:41:45 -07:00
|
|
|
pub fn initPayload(payload: *Payload) Type {
|
|
|
|
assert(@enumToInt(payload.tag) >= Tag.no_payload_count);
|
|
|
|
return .{ .ptr_otherwise = payload };
|
2018-07-14 21:04:12 -07:00
|
|
|
}
|
|
|
|
|
2020-04-18 16:41:45 -07:00
|
|
|
pub fn tag(self: Type) Tag {
|
|
|
|
if (self.tag_if_small_enough < Tag.no_payload_count) {
|
|
|
|
return @intToEnum(self.tag_if_small_enough);
|
|
|
|
} else {
|
|
|
|
return self.ptr_otherwise.tag;
|
2018-07-14 21:04:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-18 16:41:45 -07:00
|
|
|
pub fn format(
|
|
|
|
self: Type,
|
|
|
|
comptime fmt: []const u8,
|
|
|
|
options: std.fmt.FormatOptions,
|
|
|
|
out_stream: var,
|
|
|
|
) !void {
|
|
|
|
comptime assert(fmt.len == 0);
|
|
|
|
switch (self.tag()) {
|
|
|
|
.int_u8 => return out_stream.writeAll("u8"),
|
|
|
|
.int_usize => return out_stream.writeAll("usize"),
|
|
|
|
.array_u8_sentinel_0 => {
|
|
|
|
const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise);
|
|
|
|
return out_stream.print("[{}:0]u8", .{payload.len});
|
|
|
|
},
|
|
|
|
.array => {
|
|
|
|
const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
|
|
|
|
return out_stream.print("[{}]{}", .{ payload.len, payload.elem_type });
|
|
|
|
},
|
|
|
|
.single_const_pointer => {
|
|
|
|
const payload = @fieldParentPtr(Payload.SingleConstPointer, "base", self.ptr_otherwise);
|
|
|
|
return out_stream.print("*const {}", .{payload.pointee_type});
|
2018-07-18 21:08:47 -07:00
|
|
|
},
|
2018-07-22 20:27:58 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-18 16:41:45 -07:00
|
|
|
/// This enum does not directly correspond to `std.builtin.TypeId` because
|
|
|
|
/// it has extra enum tags in it, as a way of using less memory. For example,
|
|
|
|
/// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types
|
|
|
|
/// but with different alignment values, in this data structure they are represented
|
|
|
|
/// with different enum tags, because the the former requires more payload data than the latter.
|
|
|
|
/// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`.
|
|
|
|
pub const Tag = enum {
|
|
|
|
// The first section of this enum are tags that require no payload.
|
|
|
|
int_u8,
|
|
|
|
int_usize,
|
|
|
|
// Bump this when adding items above.
|
|
|
|
pub const last_no_payload_tag = Tag.int_usize;
|
|
|
|
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
|
|
|
|
// After this, the tag requires a payload.
|
|
|
|
|
|
|
|
array_u8_sentinel_0,
|
|
|
|
array,
|
|
|
|
single_const_pointer,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const Payload = struct {
|
|
|
|
tag: Tag,
|
|
|
|
|
|
|
|
pub const Array_u8_Sentinel0 = struct {
|
|
|
|
base: Payload = Payload{ .tag = .array_u8_sentinel_0 },
|
|
|
|
|
|
|
|
len: u64,
|
2018-07-22 20:27:58 -07:00
|
|
|
};
|
2018-07-13 18:56:38 -07:00
|
|
|
|
2020-04-18 16:41:45 -07:00
|
|
|
pub const Array = struct {
|
|
|
|
base: Payload = Payload{ .tag = .array },
|
2018-07-22 20:27:58 -07:00
|
|
|
|
2020-04-18 16:41:45 -07:00
|
|
|
elem_type: Type,
|
|
|
|
len: u64,
|
2018-07-22 20:27:58 -07:00
|
|
|
};
|
|
|
|
|
2020-04-18 16:41:45 -07:00
|
|
|
pub const SingleConstPointer = struct {
|
|
|
|
base: Payload = Payload{ .tag = .single_const_pointer },
|
2018-07-22 20:27:58 -07:00
|
|
|
|
2020-04-18 16:41:45 -07:00
|
|
|
pointee_type: Type,
|
2018-07-22 20:27:58 -07:00
|
|
|
};
|
2018-07-12 12:08:40 -07:00
|
|
|
};
|
|
|
|
};
|