Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

Storage

Configuration.Storage
pub const Storage = enum

File

lib/std/Build/Configuration.zig:2857

Code

pub const Storage = enum {
    flag_optional,
    enum_optional,
    extended,
    length_prefixed_list,
    flag_length_prefixed_list,
    union_list,
    flag_union,
    multi_list,
    flag_list,

    /// The presence of the field is determined by a boolean within a packed
    /// struct.
    pub fn FlagOptional(
        comptime flags_arg: @EnumLiteral(),
        comptime flag_arg: @EnumLiteral(),
        comptime ValueArg: type,
    ) type {
        return struct {
            value: ?Value,

            pub const storage: Storage = .flag_optional;
            pub const flags = flags_arg;
            pub const flag = flag_arg;
            pub const Value = ValueArg;
        };
    }

    /// The type of the field is determined by an enum within a packed struct.
    pub fn FlagUnion(
        comptime flags_arg: @EnumLiteral(),
        comptime flag_arg: @EnumLiteral(),
        comptime UnionArg: type,
    ) type {
        return struct {
            u: Union,

            pub const storage: Storage = .flag_union;
            pub const flags = flags_arg;
            pub const flag = flag_arg;
            pub const Union = UnionArg;

            pub const Tag = @typeInfo(Union).@"union".tag_type.?;
        };
    }

    /// The field is present if an enum tag from flags matches a specific value.
    pub fn EnumOptional(
        comptime flags_arg: @EnumLiteral(),
        comptime flag_arg: @EnumLiteral(),
        comptime tag_arg: @EnumLiteral(),
        comptime ValueArg: type,
    ) type {
        return struct {
            value: ?Value,

            pub const storage: Storage = .enum_optional;
            pub const flags = flags_arg;
            pub const flag = flag_arg;
            pub const tag = tag_arg;
            pub const Value = ValueArg;
        };
    }

    /// The field indexes into an auxilary buffer, with the first element being
    /// a packed struct that contains the tag.
    pub fn Extended(comptime BaseFlags: type, comptime U: type) type {
        return enum(u32) {
            _,

            pub const storage: Storage = .extended;

            pub fn tag(this: @This(), c: *const Configuration) @FieldType(BaseFlags, "tag") {
                const base_flags: BaseFlags = @bitCast(c.extra[@backingInt(this)]);
                return base_flags.tag;
            }

            pub fn cast(this: @This(), c: *const Configuration, comptime S: type) ?S {
                const wanted_tag = blk: {
                    const info = @typeInfo(S.Flags).@"struct";
                    break :blk info.field_attrs[0].defaultValue(info.field_types[0]).?;
                };
                const base_flags: BaseFlags = @bitCast(c.extra[@backingInt(this)]);
                if (base_flags.tag != wanted_tag) return null;
                var i: usize = @backingInt(this);
                return data(c.extra, &i, S);
            }

            pub fn get(this: @This(), buffer: []const u32) U {
                var i: usize = @backingInt(this);
                const base_flags: BaseFlags = @bitCast(buffer[i]);
                return switch (base_flags.tag) {
                    inline else => |t| @unionInit(U, @tagName(t), data(buffer, &i, @FieldType(U, @tagName(t)))),
                };
            }
        };
    }

    /// A field in flags determines whether the length is zero or nonzero. If
    /// the length is nonzero, then there is a length field followed by the
    /// list. The elements need well-defined memory layout but can otherwise be
    /// any multiple of u32 length. The length is the number of elements, not
    /// the number of u32s.
    pub fn FlagLengthPrefixedList(
        comptime flags_arg: @EnumLiteral(),
        comptime flag_arg: @EnumLiteral(),
        comptime ElemArg: type,
    ) type {
        return struct {
            slice: []const Elem,

            pub const storage: Storage = .flag_length_prefixed_list;
            pub const flags = flags_arg;
            pub const flag = flag_arg;
            pub const Elem = ElemArg;

            pub fn initErased(s: []const u32) @This() {
                return .{ .slice = @ptrCast(s) };
            }
        };
    }

    /// The field contains a u32 length followed by that many items. Each
    /// element needs well-defined memory layout but can otherwise be any
    /// multiple of u32 length. The length is number of elements, not the
    /// number of u32s.
    pub fn LengthPrefixedList(comptime ElemArg: type) type {
        return struct {
            slice: []const Elem,

            pub const storage: Storage = .length_prefixed_list;
            pub const Elem = ElemArg;

            pub fn initErased(s: []const u32) @This() {
                return .{ .slice = @ptrCast(s) };
            }
        };
    }

    /// The field is a list whose length is an integer inside flags.
    pub fn FlagList(
        comptime flags_arg: @EnumLiteral(),
        comptime flag_arg: @EnumLiteral(),
        comptime ElemArg: type,
    ) type {
        return struct {
            slice: []const Elem,

            pub const storage: Storage = .flag_list;
            pub const flags = flags_arg;
            pub const flag = flag_arg;
            pub const Elem = ElemArg;

            pub fn initErased(s: []const u32) @This() {
                return .{ .slice = @ptrCast(s) };
            }
        };
    }

    /// The field contains a u32 length followed by that many items for the
    /// first field, that many items for the second field, etc.
    pub fn MultiList(comptime ElemArg: type) type {
        return struct {
            mal: std.MultiArrayList(Elem),

            pub const storage: Storage = .multi_list;
            pub const Elem = ElemArg;
        };
    }

    /// `UnionArg` is a tagged union with a small integer for the enum tag.
    ///
    /// A field in flags determines whether the metadata is present.
    ///
    /// The metadata is bit-packed consecutive packed struct which is the
    /// `UnionArg` enum tag combined with a "last" marker boolean field.
    /// When "last" is true, the element is the last one, providing
    /// the length of the list.
    ///
    /// Following is each element of the list; each bitcastable to u32.
    pub fn UnionList(
        comptime flags_arg: @EnumLiteral(),
        comptime flag_arg: @EnumLiteral(),
        comptime UnionArg: type,
    ) type {
        return struct {
            /// When serializing it is UnionArg slice pointer.
            /// When deserializing it is extra index of first UnionArg element.
            data: ?*const anyopaque,
            len: usize,

            pub const storage: Storage = .union_list;
            pub const flags = flags_arg;
            pub const flag = flag_arg;
            pub const Union = UnionArg;

            pub const Tag = @typeInfo(Union).@"union".tag_type.?;
            pub const MetaInt = @Int(.unsigned, @bitSizeOf(Tag) + 1);
            pub const Meta = packed struct(MetaInt) {
                tag: Tag,
                last: bool,
            };

            /// Valid to call only when serializing.
            pub fn init(s: []const Union) @This() {
                return .{ .data = s.ptr, .len = s.len };
            }

            /// Valid to call only when deserializing.
            pub fn slice(this: *const @This(), extra: []const u32) []const u32 {
                return extra[@intFromPtr(this.data)..][0..this.len];
            }

            /// Valid to call only when deserializing.
            pub fn get(this: *const @This(), extra: []const u32, i: usize) Union {
                const elem = slice(this, extra)[i];
                return switch (this.tag(extra, i)) {
                    inline else => |comptime_tag| @unionInit(Union, @tagName(comptime_tag), @fromBackingInt(@intCast(elem))),
                };
            }

            /// Valid to call only when deserializing.
            pub fn tag(this: *const @This(), extra: []const u32, i: usize) Tag {
                const start = @intFromPtr(this.data);
                const meta_start = start - (this.len * @bitSizeOf(Meta) + 31) / 32;
                return loadBits(u32, extra[meta_start..], i * @bitSizeOf(Meta), Meta).tag;
            }

            fn extraLen(len: usize) usize {
                return len + (len * @bitSizeOf(Meta) + 31) / 32;
            }
        };
    }

    pub fn dataLength(buffer: []const u32, i: usize, comptime S: type) usize {
        var end = i;
        _ = data(buffer, &end, S);
        return end - i;
    }

    pub fn data(buffer: []const u32, i: *usize, comptime T: type) T {
        switch (@typeInfo(T)) {
            .@"struct" => |info| {
                var result: T = undefined;
                inline for (info.field_names, info.field_types) |field_name, field_type| {
                    @field(result, field_name) = dataField(buffer, i, &result, field_type);
                }
                return result;
            },
            .@"union" => |info| {
                const flags: T.Flags = @bitCast(buffer[i.*]);
                return switch (flags.tag) {
                    inline else => |comptime_tag| @unionInit(
                        T,
                        @tagName(comptime_tag),
                        data(buffer, i, info.field_types[@backingInt(comptime_tag)]),
                    ),
                };
            },
            else => comptime unreachable,
        }
    }

    fn dataField(buffer: []const u32, i: *usize, container: anytype, comptime Field: type) Field {
        switch (@typeInfo(Field)) {
            .void => return {},
            .int => |info| switch (info.bits) {
                32 => {
                    defer i.* += 1;
                    return buffer[i.*];
                },
                64 => {
                    defer i.* += 2;
                    return @bitCast(buffer[i.*..][0..2].*);
                },
                else => comptime unreachable,
            },
            .@"enum" => {
                defer i.* += 1;
                return @fromBackingInt(@intCast(buffer[i.*]));
            },
            .@"struct" => |info| switch (info.layout) {
                .@"packed" => switch (info.backing_integer.?) {
                    u32 => {
                        defer i.* += 1;
                        return @bitCast(buffer[i.*]);
                    },
                    u64 => {
                        defer i.* += 2;
                        return @bitCast(buffer[i.*..][0..2].*);
                    },
                    else => comptime unreachable,
                },
                .auto => switch (Field) {
                    std.Target.Cpu.Feature.Set => {
                        const u32_count = (Field.usize_count * @sizeOf(usize)) / @sizeOf(u32);
                        defer i.* += u32_count;
                        return .{ .ints = @as(
                            *align(@alignOf(u32)) const [Field.usize_count]usize,
                            @ptrCast(buffer[i.*..][0..u32_count]),
                        ).* };
                    },
                    else => switch (Field.storage) {
                        .flag_optional => {
                            const flags = @field(container, @tagName(Field.flags));
                            const flag = @field(flags, @tagName(Field.flag));
                            return .{
                                .value = if (flag) dataField(buffer, i, container, Field.Value) else null,
                            };
                        },
                        .flag_union => {
                            const flags = @field(container, @tagName(Field.flags));
                            const tag: Field.Tag = @field(flags, @tagName(Field.flag));
                            return .{
                                .u = switch (tag) {
                                    inline else => |comptime_tag| @unionInit(
                                        Field.Union,
                                        @tagName(comptime_tag),
                                        dataField(
                                            buffer,
                                            i,
                                            container,
                                            @typeInfo(Field.Union).@"union".field_types[@backingInt(comptime_tag)],
                                        ),
                                    ),
                                },
                            };
                        },
                        .enum_optional => {
                            const flags = @field(container, @tagName(Field.flags));
                            const tag = @field(flags, @tagName(Field.flag));
                            const match = tag == Field.tag;
                            return .{
                                .value = if (match) dataField(buffer, i, container, Field.Value) else null,
                            };
                        },
                        .extended => @compileError("unimplemented"),
                        .length_prefixed_list => {
                            const n = @divExact(@sizeOf(Field.Elem), @sizeOf(u32));
                            const data_start = i.* + 1;
                            const buf_len = buffer[data_start - 1] * n;
                            defer i.* = data_start + buf_len;
                            return .{ .slice = @ptrCast(buffer[data_start..][0..buf_len]) };
                        },
                        .flag_length_prefixed_list => {
                            const flags = @field(container, @tagName(Field.flags));
                            const flag = @field(flags, @tagName(Field.flag));
                            if (!flag) return .{ .slice = &.{} };
                            const n = @divExact(@sizeOf(Field.Elem), @sizeOf(u32));
                            const data_start = i.* + 1;
                            const buf_len = buffer[data_start - 1] * n;
                            defer i.* = data_start + buf_len;
                            return .{ .slice = @ptrCast(buffer[data_start..][0..buf_len]) };
                        },
                        .flag_list => {
                            const flags = @field(container, @tagName(Field.flags));
                            const len: u32 = @field(flags, @tagName(Field.flag));
                            const data_start = i.*;
                            defer i.* = data_start + len;
                            return .{ .slice = @ptrCast(buffer[data_start..][0..len]) };
                        },
                        .multi_list => {
                            const data_start = i.* + 1;
                            const len = buffer[data_start - 1];
                            defer i.* = data_start + len * @typeInfo(Field.Elem).@"struct".field_names.len;
                            return .{ .mal = .{
                                .bytes = @ptrCast(@constCast(buffer[data_start..][0..len])),
                                .len = len,
                                .capacity = len,
                            } };
                        },
                        .union_list => {
                            const flags = @field(container, @tagName(Field.flags));
                            const flag = @field(flags, @tagName(Field.flag));
                            if (!flag) return .{ .data = null, .len = 0 };
                            const meta_start = i.*;
                            const meta_buffer = buffer[meta_start..];
                            var len: u32 = 0;
                            var bit_offset: usize = 0;
                            while (true) : (bit_offset += @bitSizeOf(Field.Meta)) {
                                const meta = loadBits(u32, meta_buffer, bit_offset, Field.Meta);
                                len += 1;
                                if (meta.last) break;
                            }
                            const end = meta_start + Field.extraLen(len);
                            i.* = end;
                            return .{ .data = @ptrFromInt(end - len), .len = len };
                        },
                    },
                },
                .@"extern" => {
                    const n = @divExact(@sizeOf(Field), @sizeOf(u32));
                    defer i.* += n;
                    const ptr: *align(@alignOf(u32)) const Field = @ptrCast(buffer[i.*..][0..n]);
                    return ptr.*;
                },
            },
            else => comptime unreachable,
        }
    }

    /// Returns new end index.
    fn setExtra(buffer: []u32, index: usize, extra: anytype) usize {
        const info = @typeInfo(@TypeOf(extra)).@"struct";
        var i = index;
        inline for (info.field_names, info.field_types) |field_name, field_type| {
            i += setExtraField(buffer, i, field_type, @field(extra, field_name));
        }
        return i;
    }

    fn extraFieldLen(field: anytype) usize {
        const Field = @TypeOf(field);
        return switch (@typeInfo(Field)) {
            .void => 0,
            .int => |info| switch (info.bits) {
                32 => 1,
                64 => 2,
                else => comptime unreachable,
            },
            .@"enum" => 1,
            .@"struct" => |info| switch (info.layout) {
                .@"packed" => switch (info.backing_integer.?) {
                    u32 => 1,
                    u64 => 2,
                    else => comptime unreachable,
                },
                .auto => switch (Field.storage) {
                    .flag_optional, .enum_optional => (@sizeOf(Field.Value) + 3) / 4,
                    .extended => 1,
                    .length_prefixed_list,
                    .flag_length_prefixed_list,
                    .flag_list,
                    => 1 + @divExact(@sizeOf(Field.Elem), @sizeOf(u32)) * field.slice.len,
                    .multi_list => 1 + field.mal.len * @typeInfo(Field.Elem).@"struct".field_names.len,
                    .union_list => Field.extraLen(field.len),
                    .flag_union => switch (field.u) {
                        inline else => |v| extraFieldLen(v),
                    },
                },
                .@"extern" => @divExact(@sizeOf(Field), @sizeOf(u32)),
            },
            else => @compileError("bad type: " ++ @typeName(Field)),
        };
    }

    fn extraLen(extra: anytype) usize {
        const field_names = @typeInfo(@TypeOf(extra)).@"struct".field_names;
        var i: usize = 0;
        inline for (field_names) |name| {
            i += Storage.extraFieldLen(@field(extra, name));
        }
        return i;
    }

    inline fn setExtraField(buffer: []u32, i: usize, comptime Field: type, value: anytype) usize {
        switch (@typeInfo(Field)) {
            .void => return 0,
            .int => |info| switch (info.bits) {
                32 => {
                    buffer[i] = value;
                    return 1;
                },
                64 => {
                    buffer[i..][0..2].* = @bitCast(value);
                    return 2;
                },
                else => comptime unreachable,
            },
            .@"enum" => {
                buffer[i] = @backingInt(value);
                return 1;
            },
            .@"struct" => |info| switch (info.layout) {
                .@"packed" => switch (info.backing_integer.?) {
                    u32 => {
                        buffer[i] = @bitCast(value);
                        return 1;
                    },
                    u64 => {
                        buffer[i..][0..2].* = @bitCast(value);
                        return 2;
                    },
                    else => comptime unreachable,
                },
                .auto => switch (Field) {
                    std.Target.Cpu.Feature.Set => {
                        const casted: []const u32 = @ptrCast(&value.ints);
                        @memcpy(buffer[i..][0..casted.len], casted);
                        return casted.len;
                    },
                    else => switch (Field.storage) {
                        .flag_optional, .enum_optional => {
                            return if (value.value) |v| setExtraField(buffer, i, Field.Value, v) else 0;
                        },
                        .flag_union => return switch (value.u) {
                            inline else => |x| setExtraField(buffer, i, @TypeOf(x), x),
                        },
                        .extended => @compileError("unimplemented"),
                        .flag_length_prefixed_list => {
                            const len: u32 = @intCast(value.slice.len);
                            if (len == 0) return 0; // Flag bit hides the length prefix.
                            buffer[i] = len;
                            const buf_len = len * @divExact(@sizeOf(Field.Elem), @sizeOf(u32));
                            @memcpy(buffer[i + 1 ..][0..buf_len], @as([]const u32, @ptrCast(value.slice)));
                            return 1 + buf_len;
                        },
                        .length_prefixed_list => {
                            const len: u32 = @intCast(value.slice.len);
                            buffer[i] = len;
                            const buf_len = len * @divExact(@sizeOf(Field.Elem), @sizeOf(u32));
                            @memcpy(buffer[i + 1 ..][0..buf_len], @as([]const u32, @ptrCast(value.slice)));
                            return 1 + buf_len;
                        },
                        .flag_list => {
                            const len: u32 = @intCast(value.slice.len);
                            @memcpy(buffer[i..][0..len], @as([]const u32, @ptrCast(value.slice)));
                            return len;
                        },
                        .multi_list => {
                            const len: u32 = @intCast(value.mal.len);
                            buffer[i] = len;
                            const field_names = @typeInfo(Field.Elem).@"struct".field_names;
                            inline for (0..field_names.len) |field_i| @memcpy(
                                buffer[i + 1 + field_i * len ..][0..len],
                                @as([]const u32, @ptrCast(value.mal.items(@fromBackingInt(@intCast(field_i))))),
                            );
                            return 1 + field_names.len * len;
                        },
                        .union_list => {
                            if (value.len == 0) return 0;
                            const Tag = @typeInfo(Field.Union).@"union".tag_type.?;
                            const slice_ptr: [*]const Field.Union = @ptrCast(@alignCast(value.data));
                            const slice = slice_ptr[0..value.len];
                            const meta_buffer = buffer[i..][0 .. (slice.len * @bitSizeOf(Field.Meta) + 31) / 32];
                            for (slice[0 .. slice.len - 1], 0..) |elem, elem_index| {
                                const union_tag: Tag = elem;
                                storeBits(u32, meta_buffer, elem_index * @bitSizeOf(Field.Meta), @as(Field.Meta, .{
                                    .tag = union_tag,
                                    .last = false,
                                }));
                            } else {
                                const elem_index = slice.len - 1;
                                const elem = slice[elem_index];
                                const union_tag: Tag = elem;
                                storeBits(u32, meta_buffer, elem_index * @bitSizeOf(Field.Meta), @as(Field.Meta, .{
                                    .tag = union_tag,
                                    .last = true,
                                }));
                            }
                            var total: usize = meta_buffer.len;
                            for (i + meta_buffer.len.., slice) |elem_index, src| switch (src) {
                                inline else => |x| total += setExtraField(buffer, elem_index, @TypeOf(x), x),
                            };
                            return total;
                        },
                    },
                },
                .@"extern" => {
                    const n = @divExact(@sizeOf(Field), @sizeOf(u32));
                    const ptr: *align(@alignOf(Field)) const [n]u32 = @ptrCast(&value);
                    buffer[i..][0..n].* = ptr.*;
                    return n;
                },
            },
            else => @compileError("bad field type: " ++ @typeName(Field)),
        }
    }
}