mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
101 lines
3.3 KiB
Zig
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);
|
|
}
|