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.

Metadata

Builder.Metadata
pub const Metadata = packed struct(u32)

File

lib/std/zig/llvm/Builder.zig:7980

Code

pub const Metadata = packed struct(u32) {
    index: u29,
    kind: Kind,
    unused: enum(u1) { unused = 0 } = .unused,

    pub const Kind = enum(u2) {
        string,
        node,
        forward,
        local,
    };

    pub const empty_tuple: Metadata = .{ .kind = .node, .index = 0 };

    pub const Optional = packed struct(u32) {
        index: u29,
        kind: Metadata.Kind,
        is_none: bool,

        pub const none: Metadata.Optional = .{ .index = 0, .kind = .string, .is_none = true };
        pub const empty_tuple: Metadata.Optional = Metadata.empty_tuple.toOptional();

        pub fn wrap(metadata: ?Metadata) Metadata.Optional {
            return (metadata orelse return .none).toOptional();
        }
        pub fn unwrap(metadata: Metadata.Optional) ?Metadata {
            return if (metadata.is_none) null else .{ .index = metadata.index, .kind = metadata.kind };
        }
        pub fn toValue(metadata: Metadata.Optional) Value {
            return if (metadata.unwrap()) |m| m.toValue() else .none;
        }
        pub fn toString(metadata: Metadata.Optional) Metadata.String.Optional {
            return if (metadata.unwrap()) |m| m.toString().toOptional() else .none;
        }
    };
    pub fn toOptional(metadata: Metadata) Metadata.Optional {
        return .{ .index = metadata.index, .kind = metadata.kind, .is_none = false };
    }
    pub fn toValue(metadata: Metadata) Value {
        return @fromBackingInt(@intCast(Value.first_metadata + @as(u32, @bitCast(metadata))));
    }

    pub const String = enum(u32) {
        _,

        pub const Optional = enum(u32) {
            none = @bitCast(Metadata.Optional.none),
            _,

            pub fn wrap(metadata: ?Metadata.String) Metadata.String.Optional {
                return (metadata orelse return .none).toOptional();
            }
            pub fn unwrap(metadata: Metadata.String.Optional) ?Metadata.String {
                return switch (metadata) {
                    .none => null,
                    else => @fromBackingInt(@intCast(@backingInt(metadata))),
                };
            }
            pub fn toMetadata(metadata: Metadata.String.Optional) Metadata.Optional {
                return if (metadata.unwrap()) |m| m.toMetadata().toOptional() else .none;
            }
        };
        pub fn toOptional(metadata: Metadata.String) Metadata.String.Optional {
            return @fromBackingInt(@intCast(@backingInt(metadata)));
        }
        pub fn toMetadata(metadata: Metadata.String) Metadata {
            return .{ .index = @intCast(@backingInt(metadata)), .kind = .string };
        }

        pub fn slice(metadata: Metadata.String, builder: *const Builder) []const u8 {
            const index = @backingInt(metadata);
            const start = builder.metadata_string_indices.items[index];
            const end = builder.metadata_string_indices.items[index + 1];
            return builder.metadata_string_bytes.items[start..end];
        }

        const Adapter = struct {
            builder: *const Builder,
            pub fn hash(_: Adapter, key: []const u8) u32 {
                return @truncate(std.hash.Wyhash.hash(0, key));
            }
            pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {
                const rhs_metadata: Metadata.String = @fromBackingInt(@intCast(rhs_index));
                return std.mem.eql(u8, lhs_key, rhs_metadata.slice(ctx.builder));
            }
        };

        const FormatData = struct {
            metadata: Metadata.String,
            builder: *const Builder,
        };
        fn format(data: FormatData, w: *Writer) Writer.Error!void {
            try printEscapedString(data.metadata.slice(data.builder), .always_quote, w);
        }
        fn fmt(self: Metadata.String, builder: *const Builder) std.fmt.Alt(FormatData, format) {
            return .{ .data = .{ .metadata = self, .builder = builder } };
        }
    };
    pub fn toString(metadata: Metadata) Metadata.String {
        assert(metadata.kind == .string);
        return @fromBackingInt(@intCast(metadata.index));
    }

    pub const Tag = enum(u6) {
        file,
        compile_unit,
        @"compile_unit optimized",
        subprogram,
        @"subprogram local",
        @"subprogram definition",
        @"subprogram local definition",
        @"subprogram optimized",
        @"subprogram optimized local",
        @"subprogram optimized definition",
        @"subprogram optimized local definition",
        lexical_block,
        location,
        basic_bool_type,
        basic_unsigned_type,
        basic_signed_type,
        basic_float_type,
        composite_struct_type,
        composite_union_type,
        composite_enumeration_type,
        composite_array_type,
        composite_vector_type,
        derived_pointer_type,
        derived_member_type,
        derived_typedef_type,
        subroutine_type,
        enumerator_unsigned,
        enumerator_signed_positive,
        enumerator_signed_negative,
        subrange,
        tuple,
        expression,
        local_var,
        parameter,
        global_var,
        @"global_var local",
        global_var_expression,
        constant,

        pub fn isInline(metadata_tag: Metadata.Tag) bool {
            return switch (metadata_tag) {
                .expression,
                .constant,
                => true,
                .file,
                .compile_unit,
                .@"compile_unit optimized",
                .subprogram,
                .@"subprogram local",
                .@"subprogram definition",
                .@"subprogram local definition",
                .@"subprogram optimized",
                .@"subprogram optimized local",
                .@"subprogram optimized definition",
                .@"subprogram optimized local definition",
                .lexical_block,
                .location,
                .basic_bool_type,
                .basic_unsigned_type,
                .basic_signed_type,
                .basic_float_type,
                .composite_struct_type,
                .composite_union_type,
                .composite_enumeration_type,
                .composite_array_type,
                .composite_vector_type,
                .derived_pointer_type,
                .derived_member_type,
                .derived_typedef_type,
                .subroutine_type,
                .enumerator_unsigned,
                .enumerator_signed_positive,
                .enumerator_signed_negative,
                .subrange,
                .tuple,
                .local_var,
                .parameter,
                .global_var,
                .@"global_var local",
                .global_var_expression,
                => false,
            };
        }
    };

    pub fn tag(metadata: Metadata, builder: *const Builder) Tag {
        assert(metadata.kind == .node);
        return builder.metadata_items.items(.tag)[metadata.index];
    }

    pub fn item(metadata: Metadata, builder: *const Builder) Item {
        assert(metadata.kind == .node);
        return builder.metadata_items.get(metadata.index);
    }

    pub fn isInline(metadata: Metadata, builder: *const Builder) bool {
        return metadata.tag(builder).isInline();
    }

    pub fn unwrap(metadata: Metadata, builder: *const Builder) Metadata {
        switch (metadata.kind) {
            .string, .node, .local => return metadata,
            .forward => {
                const referenced = builder.metadata_forward_references.items[metadata.index].unwrap().?;
                switch (referenced.kind) {
                    .string, .node => return referenced,
                    .forward, .local => unreachable,
                }
            },
        }
    }

    pub const Item = struct {
        tag: Tag,
        data: ExtraIndex,

        const ExtraIndex = u32;
    };

    pub const DIFlags = packed struct(u32) {
        Visibility: enum(u2) { Zero, Private, Protected, Public } = .Zero,
        FwdDecl: bool = false,
        AppleBlock: bool = false,
        ReservedBit4: u1 = 0,
        Virtual: bool = false,
        Artificial: bool = false,
        Explicit: bool = false,
        Prototyped: bool = false,
        ObjcClassComplete: bool = false,
        ObjectPointer: bool = false,
        Vector: bool = false,
        StaticMember: bool = false,
        LValueReference: bool = false,
        RValueReference: bool = false,
        ExportSymbols: bool = false,
        Inheritance: enum(u2) {
            Zero,
            SingleInheritance,
            MultipleInheritance,
            VirtualInheritance,
        } = .Zero,
        IntroducedVirtual: bool = false,
        BitField: bool = false,
        NoReturn: bool = false,
        ReservedBit21: u1 = 0,
        TypePassbyValue: bool = false,
        TypePassbyReference: bool = false,
        EnumClass: bool = false,
        Thunk: bool = false,
        NonTrivial: bool = false,
        BigEndian: bool = false,
        LittleEndian: bool = false,
        AllCallsDescribed: bool = false,
        Unused: u2 = 0,

        pub fn format(self: DIFlags, w: *Writer) Writer.Error!void {
            var need_pipe = false;
            const info = @typeInfo(DIFlags).@"struct";
            inline for (info.field_names, info.field_types) |field_name, field_type| {
                switch (@typeInfo(field_type)) {
                    .bool => if (@field(self, field_name)) {
                        if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
                        try w.print("DIFlag{s}", .{field_name});
                    },
                    .@"enum" => if (@field(self, field_name) != .Zero) {
                        if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
                        try w.print("DIFlag{s}", .{@tagName(@field(self, field_name))});
                    },
                    .int => assert(@field(self, field_name) == 0),
                    else => @compileError("bad field type: " ++ field_name ++ ": " ++
                        @typeName(field_type)),
                }
            }
            if (!need_pipe) try w.writeByte('0');
        }
    };

    pub const File = struct {
        filename: Metadata.String.Optional,
        directory: Metadata.String.Optional,
    };

    pub const CompileUnit = struct {
        pub const Options = struct {
            optimized: bool,
        };

        file: Metadata.Optional,
        producer: Metadata.String.Optional,
        enums: Metadata.Optional,
        globals: Metadata.Optional,
    };

    pub const Subprogram = struct {
        pub const Options = struct {
            di_flags: DIFlags,
            sp_flags: DISPFlags,
        };

        pub const DISPFlags = packed struct(u32) {
            Virtuality: enum(u2) { Zero, Virtual, PureVirtual } = .Zero,
            LocalToUnit: bool = false,
            Definition: bool = false,
            Optimized: bool = false,
            Pure: bool = false,
            Elemental: bool = false,
            Recursive: bool = false,
            MainSubprogram: bool = false,
            Deleted: bool = false,
            ReservedBit10: u1 = 0,
            ObjCDirect: bool = false,
            Unused: u20 = 0,

            pub fn format(self: DISPFlags, w: *Writer) Writer.Error!void {
                var need_pipe = false;
                const info = @typeInfo(DISPFlags).@"struct";
                inline for (info.field_names, info.field_types) |field_name, field_type| {
                    switch (@typeInfo(field_type)) {
                        .bool => if (@field(self, field_name)) {
                            if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
                            try w.print("DISPFlag{s}", .{field_name});
                        },
                        .@"enum" => if (@field(self, field_name) != .Zero) {
                            if (need_pipe) try w.writeAll(" | ") else need_pipe = true;
                            try w.print("DISPFlag{s}", .{@tagName(@field(self, field_name))});
                        },
                        .int => assert(@field(self, field_name) == 0),
                        else => @compileError("bad field type: " ++ field_name ++ ": " ++
                            @typeName(field_type)),
                    }
                }
                if (!need_pipe) try w.writeByte('0');
            }
        };

        file: Metadata.Optional,
        name: Metadata.String.Optional,
        linkage_name: Metadata.String.Optional,
        line: u32,
        scope_line: u32,
        ty: Metadata.Optional,
        di_flags: DIFlags,
        compile_unit: Metadata.Optional,
    };
    pub fn getSubprogram(metadata: Metadata, builder: *const Builder) Subprogram {
        const metadata_item = metadata.item(builder);
        switch (metadata_item.tag) {
            else => unreachable,
            .subprogram,
            .@"subprogram local",
            .@"subprogram definition",
            .@"subprogram local definition",
            .@"subprogram optimized",
            .@"subprogram optimized local",
            .@"subprogram optimized definition",
            .@"subprogram optimized local definition",
            => return builder.metadataExtraData(Metadata.Subprogram, metadata_item.data),
        }
    }

    pub const LexicalBlock = struct {
        scope: Metadata.Optional,
        file: Metadata.Optional,
        line: u32,
        column: u32,
    };

    pub const Location = struct {
        line: u32,
        column: u32,
        scope: Metadata,
        inlined_at: Metadata.Optional,
    };

    pub const BasicType = struct {
        name: Metadata.String.Optional,
        size_in_bits_lo: u32,
        size_in_bits_hi: u32,

        pub fn bitSize(self: BasicType) u64 {
            return @as(u64, self.size_in_bits_hi) << 32 | self.size_in_bits_lo;
        }
    };

    pub const CompositeType = struct {
        name: Metadata.String.Optional,
        file: Metadata.Optional,
        scope: Metadata.Optional,
        line: u32,
        underlying_type: Metadata.Optional,
        size_in_bits_lo: u32,
        size_in_bits_hi: u32,
        align_in_bits_lo: u32,
        align_in_bits_hi: u32,
        fields_tuple: Metadata.Optional,

        pub fn bitSize(self: CompositeType) u64 {
            return @as(u64, self.size_in_bits_hi) << 32 | self.size_in_bits_lo;
        }
        pub fn bitAlign(self: CompositeType) u64 {
            return @as(u64, self.align_in_bits_hi) << 32 | self.align_in_bits_lo;
        }
    };

    pub const DerivedType = struct {
        name: Metadata.String.Optional,
        file: Metadata.Optional,
        scope: Metadata.Optional,
        line: u32,
        underlying_type: Metadata.Optional,
        size_in_bits_lo: u32,
        size_in_bits_hi: u32,
        align_in_bits_lo: u32,
        align_in_bits_hi: u32,
        offset_in_bits_lo: u32,
        offset_in_bits_hi: u32,

        pub fn bitSize(self: DerivedType) u64 {
            return @as(u64, self.size_in_bits_hi) << 32 | self.size_in_bits_lo;
        }
        pub fn bitAlign(self: DerivedType) u64 {
            return @as(u64, self.align_in_bits_hi) << 32 | self.align_in_bits_lo;
        }
        pub fn bitOffset(self: DerivedType) u64 {
            return @as(u64, self.offset_in_bits_hi) << 32 | self.offset_in_bits_lo;
        }
    };

    pub const SubroutineType = struct {
        types_tuple: Metadata.Optional,
    };

    pub const Enumerator = struct {
        name: Metadata.String.Optional,
        bit_width: u32,
        limbs_index: u32,
        limbs_len: u32,
    };

    pub const Subrange = struct {
        lower_bound: Metadata.Optional,
        count: Metadata.Optional,
    };

    pub const Expression = struct {
        elements_len: u32,

        // elements: [elements_len]u32
    };

    pub const Tuple = struct {
        elements_len: u32,

        // elements: [elements_len]Metadata
    };

    pub const LocalVar = struct {
        name: Metadata.String.Optional,
        file: Metadata.Optional,
        scope: Metadata.Optional,
        line: u32,
        ty: Metadata.Optional,
    };

    pub const Parameter = struct {
        name: Metadata.String.Optional,
        file: Metadata.Optional,
        scope: Metadata.Optional,
        line: u32,
        ty: Metadata.Optional,
        arg_no: u32,
    };

    pub const GlobalVar = struct {
        pub const Options = struct {
            local: bool,
        };

        name: Metadata.String.Optional,
        linkage_name: Metadata.String.Optional,
        file: Metadata.Optional,
        scope: Metadata.Optional,
        line: u32,
        ty: Metadata.Optional,
        variable: Variable.Index,
    };

    pub const GlobalVarExpression = struct {
        variable: Metadata.Optional,
        expression: Metadata.Optional,
    };

    const Formatter = struct {
        builder: *Builder,
        need_comma: bool,
        map: std.array_hash_map.Auto(union(enum) {
            metadata: Metadata,
            debug_location: DebugLocation.Location,
        }, void) = .empty,

        const FormatData = struct {
            formatter: *Formatter,
            prefix: []const u8 = "",
            node: Node,
            specialized: ?FormatFlags,

            const Node = union(enum) {
                none,
                @"inline": Metadata,
                index: u32,

                local_value: ValueData,
                local_metadata: ValueData,
                local_inline: Metadata,
                local_index: u32,

                string: Metadata.String,
                bool: bool,
                u32: u32,
                u64: u64,
                di_flags: DIFlags,
                sp_flags: Subprogram.DISPFlags,
                raw: []const u8,

                const ValueData = struct {
                    value: Value,
                    function: Function.Index,
                };
            };
        };
        fn format(data: FormatData, w: *Writer) Writer.Error!void {
            if (data.node == .none) return;

            const is_specialized = data.specialized != null;

            if (data.formatter.need_comma) try w.writeAll(", ");
            defer data.formatter.need_comma = true;
            try w.writeAll(data.prefix);

            const builder = data.formatter.builder;
            switch (data.node) {
                .none => unreachable,
                .@"inline" => |node| {
                    const needed_comma = data.formatter.need_comma;
                    defer data.formatter.need_comma = needed_comma;
                    data.formatter.need_comma = false;

                    const node_item = node.item(builder);
                    switch (node_item.tag) {
                        .expression => {
                            var extra = builder.metadataExtraDataTrail(Expression, node_item.data);
                            const elements = extra.trail.next(extra.data.elements_len, u32, builder);
                            try w.writeAll("!DIExpression(");
                            for (elements) |element| try format(.{
                                .formatter = data.formatter,
                                .node = .{ .u64 = element },
                                .specialized = .{ .percent = true },
                            }, w);
                            try w.writeByte(')');
                        },
                        .constant => try Constant.format(.{
                            .constant = @fromBackingInt(@intCast(node_item.data)),
                            .builder = builder,
                            .flags = data.specialized orelse .{},
                        }, w),
                        else => unreachable,
                    }
                },
                .index => |node| try w.print("!{d}", .{node}),
                inline .local_value, .local_metadata => |node, node_tag| try Value.format(.{
                    .value = node.value,
                    .function = node.function,
                    .builder = builder,
                    .flags = switch (node_tag) {
                        .local_value => data.specialized orelse .{},
                        .local_metadata => .{ .percent = true },
                        else => unreachable,
                    },
                }, w),
                inline .local_inline, .local_index => |node, node_tag| {
                    if (data.specialized) |flags| {
                        if (flags.onlyPercent()) {
                            try w.print("{f} ", .{Type.metadata.fmt(builder, .percent)});
                        }
                    }
                    try format(.{
                        .formatter = data.formatter,
                        .node = @unionInit(FormatData.Node, @tagName(node_tag)["local_".len..], node),
                        .specialized = .{ .percent = true },
                    }, w);
                },
                .string => |s| {
                    if (is_specialized) try w.writeByte('!');
                    try w.print("{f}", .{s.fmt(builder)});
                },
                inline .bool, .u32, .u64 => |node| try w.print("{}", .{node}),
                inline .di_flags, .sp_flags => |node| try w.print("{f}", .{node}),
                .raw => |node| try w.writeAll(node),
            }
        }
        inline fn fmt(formatter: *Formatter, prefix: []const u8, node: anytype, special: ?FormatFlags) switch (@TypeOf(node)) {
            Metadata, Metadata.Optional, ?Metadata => Allocator.Error,
            else => error{},
        }!std.fmt.Alt(FormatData, format) {
            const Node = @TypeOf(node);
            const MaybeNode = switch (Node) {
                Metadata.Optional => ?Metadata,
                Metadata.String.Optional => ?Metadata.String,
                else => switch (@typeInfo(Node)) {
                    .optional => Node,
                    .null => ?noreturn,
                    else => ?Node,
                },
            };
            const Some = @typeInfo(MaybeNode).optional.child;
            return .{ .data = .{
                .formatter = formatter,
                .prefix = prefix,
                .node = if (@as(MaybeNode, switch (Node) {
                    Metadata.Optional, Metadata.String.Optional => node.unwrap(),
                    else => node,
                })) |some| switch (@typeInfo(Some)) {
                    .@"enum" => |enum_info| switch (Some) {
                        Metadata.String => .{ .string = some },
                        else => if (enum_info.mode == .exhaustive)
                            .{ .raw = @tagName(some) }
                        else
                            @compileError("unknown type to format: " ++ @typeName(Node)),
                    },
                    .enum_literal => .{ .raw = @tagName(some) },
                    .bool => .{ .bool = some },
                    .@"struct" => switch (Some) {
                        DIFlags => .{ .di_flags = some },
                        Metadata => switch (some.kind) {
                            .string => .{ .string = some.toString() },
                            .node, .forward => try formatter.refUnwrapped(some.unwrap(formatter.builder)),
                            .local => unreachable,
                        },
                        Subprogram.DISPFlags => .{ .sp_flags = some },
                        else => @compileError("unknown type to format: " ++ @typeName(Node)),
                    },
                    .int, .comptime_int => .{ .u64 = some },
                    .pointer => .{ .raw = some },
                    else => @compileError("unknown type to format: " ++ @typeName(Node)),
                } else switch (Node) {
                    Metadata.Optional, Metadata.String.Optional => .none,
                    else => switch (@typeInfo(Node)) {
                        .optional, .null => .none,
                        else => unreachable,
                    },
                },
                .specialized = special,
            } };
        }
        inline fn fmtLocal(
            formatter: *Formatter,
            prefix: []const u8,
            value: Value,
            function: Function.Index,
        ) Allocator.Error!std.fmt.Alt(FormatData, format) {
            return .{ .data = .{
                .formatter = formatter,
                .prefix = prefix,
                .node = node: switch (value.unwrap()) {
                    .instruction, .constant => .{ .local_value = .{
                        .value = value,
                        .function = function,
                    } },
                    .metadata => |metadata| if (value == .none) .none else {
                        const unwrapped = metadata.unwrap(formatter.builder);
                        break :node switch (unwrapped.kind) {
                            .string, .node => switch (try formatter.refUnwrapped(unwrapped)) {
                                .@"inline" => |node| .{ .local_inline = node },
                                .index => |node| .{ .local_index = node },
                                else => unreachable,
                            },
                            .forward => unreachable,
                            .local => .{ .local_metadata = .{
                                .value = function.ptrConst(formatter.builder).debug_values[
                                    unwrapped.index
                                ].toValue(),
                                .function = function,
                            } },
                        };
                    },
                },
                .specialized = null,
            } };
        }
        fn refUnwrapped(formatter: *Formatter, node: Metadata) Allocator.Error!FormatData.Node {
            const builder = formatter.builder;
            const unwrapped_metadata = node.unwrap(builder);
            switch (unwrapped_metadata.tag(builder)) {
                .expression, .constant => return .{ .@"inline" = unwrapped_metadata },
                else => |metadata_tag| {
                    assert(!metadata_tag.isInline());
                    const gop = try formatter.map.getOrPut(builder.gpa, .{ .metadata = unwrapped_metadata });
                    return .{ .index = @intCast(gop.index) };
                },
            }
        }

        inline fn specialized(
            formatter: *Formatter,
            distinct: enum { @"!", @"distinct !" },
            node: enum {
                DIFile,
                DICompileUnit,
                DISubprogram,
                DILexicalBlock,
                DILocation,
                DIBasicType,
                DICompositeType,
                DIDerivedType,
                DISubroutineType,
                DIEnumerator,
                DISubrange,
                DILocalVariable,
                DIGlobalVariable,
                DIGlobalVariableExpression,
            },
            nodes: anytype,
            w: *Writer,
        ) !void {
            const names = comptime std.meta.fieldNames(@TypeOf(nodes));

            comptime var fmt_str: []const u8 = "{[distinct]s}{[node]s}(";
            inline for (names) |name| fmt_str = fmt_str ++ "{[" ++ name ++ "]f}";
            fmt_str = fmt_str ++ ")\n";

            const field_names = @as([]const []const u8, &.{ "distinct", "node" }) ++ names;
            comptime var field_types: [2 + names.len]type = undefined;
            @memset(field_types[0..2], []const u8);
            @memset(field_types[2..], std.fmt.Alt(FormatData, format));

            var fmt_args: @Struct(.auto, null, field_names, &field_types, &@splat(.{})) = undefined;
            fmt_args.distinct = @tagName(distinct);
            fmt_args.node = @tagName(node);
            inline for (names) |name| @field(fmt_args, name) = try formatter.fmt(
                name ++ ": ",
                @field(nodes, name),
                null,
            );
            try w.print(fmt_str, fmt_args);
        }
    };
}