Files
bun.sh/src/ptr/meta.zig
taylor.fish ecd74ac14c Improve owned pointer types (#21908)
(For internal tracking: fixes STAB-1005, STAB-1006, STAB-1007,
STAB-1008, STAB-1009)
2025-08-15 19:05:25 -07:00

101 lines
3.3 KiB
Zig

//! Private utilities used in smart pointer implementations.
pub const PointerInfo = struct {
const Self = @This();
/// A possibly optional slice or single-item pointer type.
/// E.g., `*u8`, `[]u8`, `?*u8`, `?[]u8`.
Pointer: type,
/// If `Pointer` is an optional pointer, this is the non-optional equivalent. Otherwise, this
/// is the same as `Pointer`.
///
/// For example, if `Pointer` is `?[]u8`, this is `[]u8`.
NonOptionalPointer: type,
/// The type of data stored by the pointer, i.e., the type obtained by dereferencing a
/// single-item pointer or accessing an element of a slice.
///
/// For example, if `Pointer` is `?[]u8`, this is `u8`.
Child: type,
pub fn kind(self: Self) enum { single, slice } {
return switch (@typeInfo(self.NonOptionalPointer).pointer.size) {
.one => .single,
.slice => .slice,
else => @compileError("unreachable"),
};
}
pub fn isOptional(self: Self) bool {
return @typeInfo(self.Pointer) == .optional;
}
pub fn isConst(self: Self) bool {
return @typeInfo(self.NonOptionalPointer).pointer.is_const;
}
pub const ParseOptions = struct {
allow_const: bool = true,
allow_slices: bool = true,
};
pub fn parse(comptime Pointer: type, comptime options: ParseOptions) Self {
const NonOptionalPointer = switch (@typeInfo(Pointer)) {
.optional => |opt| opt.child,
else => Pointer,
};
const pointer_info = switch (@typeInfo(NonOptionalPointer)) {
.pointer => |ptr| ptr,
else => @compileError("type must be a (possibly optional) pointer"),
};
const Child = pointer_info.child;
switch (pointer_info.size) {
.one => {},
.slice => if (!options.allow_slices) @compileError("slices not supported"),
.many => @compileError("many-item pointers not supported"),
.c => @compileError("C pointers not supported"),
}
if (pointer_info.is_const and !options.allow_const) {
@compileError("const pointers not supported");
}
if (pointer_info.is_volatile) {
@compileError("volatile pointers not supported");
}
if (pointer_info.alignment != @alignOf(Child)) {
@compileError("non-default alignment not supported");
}
if (pointer_info.is_allowzero) {
@compileError("allowzero not supported");
}
if (pointer_info.sentinel_ptr != null) {
@compileError("sentinel-terminated pointers not supported");
}
return .{
.Pointer = Pointer,
.NonOptionalPointer = NonOptionalPointer,
.Child = Child,
};
}
};
pub fn AddConst(Pointer: type) type {
var type_info = @typeInfo(Pointer);
switch (type_info) {
.pointer => |*ptr| {
ptr.is_const = true;
},
.optional => |*opt| {
opt.child = AddConst(opt.child);
},
// Technically this function accepts things like `?????[]u8`, but `PointerInfo.parse`
// verifies that's not the case.
else => @compileError("`Pointer` must be a (possibly optional) pointer or slice"),
}
return @Type(type_info);
}