Skip to documentation
SLOP

tiny.smg.model

Reference tiny.smg model

Defined in tiny.smg.

API (32)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callstiny.smgmodel
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsgraphcloneprivate; no linktools.smg.src.scan.pipeline.scanmergeSourceFragmentscan.reconcile.projectionclonePlanmodelclonePairsmodeldeinitEdgemodelcloneEdge
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsgraphcloneprivate; no linktools.smg.src.scan.pipeline.scanmergeSourceFragmentmodelclonePairsmodeldeinitNodemodelcloneNode
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsprivate; no linktools.smg.src.modelcheckPairHelperAllocationFailuresmodelcloneEdgemodelcloneNodeprivate; no linktools.smg.src.modelfreePairPayloadsmodelclonePairs
Static calls · unresolved targets: 0 · external targets: 3.
Called byCallsprivate; no linktools.smg.src.graphcheckGraphCloneAllocationFailuresgraphcloneprivate; no linktools.smg.src.modelcheckEdgeParsingAllocationFailuresmodelcloneEdgemodeledgeFromValue+9 moremodelfreePairsmodeldeinitEdge
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsprivate; no linktools.smg.src.graphcheckGraphCloneAllocationFailuresgraphcloneprivate; no linktools.smg.src.modelcheckNodeParsingAllocationFailuresmodelcloneNodemodelnodeFromValue+13 moremodelfreePairsmodeldeinitNode
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsprivate; no linktools.smg.src.storage.syncfillEdgeDiffmodelpairsEqualmodeledgeEquals
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsprivate; no linktools.smg.src.modelcheckEdgeParsingAllocationFailuresmodeldeinitEdgeprivate; no linktools.smg.src.modelmetadataFromObjectprivate; no linktools.smg.src.modelstringFieldmodeledgeFromValue
Static calls · unresolved targets: 1 · external targets: 1.
Called byCallsprivate; no linktools.smg.src.modelcheckPairHelperAllocationFailuresmodeldeinitEdgemodeldeinitNodetest; no linktools.smg.src.modeltest: metadata pairs round trip throu...test; no linktools.smg.src.modeltest: rendered pairs decode all value...private; no linktools.smg.src.modelfreePairPayloadsmodelfreePairs
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsprivate; no linktools.smg.src.batch.mutationupdatecommand.mutate.nodeupdategraphaddEdgeTrackedgraphaddNodeprivate; no linktools.smg.src.modelcheckPairHelperAllocationFailures+8 moreprivate sourcelib.quic.src.properties.tls.PairdeinitmodelmergePairs
Static calls · unresolved targets: 2 · external targets: 0.
Called byCallsprivate; no linktools.smg.src.storage.syncfillNodeDiffprivate; no linktools.smg.src.modeloptionalTextEqualmodelpairsEqualmodelnodeEquals
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsprivate; no linktools.smg.src.modelcheckNodeParsingAllocationFailurestest; no linktools.smg.src.modeltest: node json round tripmodeldeinitNodeprivate; no linktools.smg.src.modelintFieldprivate; no linktools.smg.src.modelmetadataFromObjectprivate; no linktools.smg.src.modelstringFieldmodelnodeFromValue
Static calls · unresolved targets: 1 · external targets: 1.
Called byCallsNo direct callsprivate; no linktools.smg.src.analysis.reportcyclomaticComplexityapi.PublicMembersourceSpellingapi.PublicMembertypeExpressionapi.PublicMembervalueExpressionapi.PublicMemberGapsourceSpelling+98 moremodelpairValue
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsmodeledgeEqualsmodelnodeEqualstest; no linktools.smg.src.modeltest: metadata pairs round trip throu...test; no linktools.smg.src.modeltest: rendered pairs decode all value...modelpairsEqual
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest; no linktools.smg.src.modeltest: metadata pairs round trip throu...test; no linktools.smg.src.modeltest: rendered pairs decode all value...private; no linktools.smg.src.storage.rows.readdecodeMetadataprivate sourcelib.quic.src.properties.tls.Pairdeinitprivate; no linktools.smg.src.modelfreePairPayloadsprivate; no linktools.smg.src.modelrenderedPairsIntomodelpairsFromRenderedJson
Static calls · unresolved targets: 1 · external targets: 1.
Called byCallstest; no linktools.smg.src.modeltest: metadata pairs round trip throu...test; no linktools.smg.src.modeltest: rendered pairs decode all value...private; no linktools.smg.src.storage.rows.writerenderMetadataprivate; no linktools.smg.src.modelwritePairsObjectmodelrenderPairsAlloc
Static calls · unresolved targets: 0 · external targets: 3.
Called byCallsNo direct callsscan.scan_metricsupdateCallMetricsmodelreplaceOwnedPairValue
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest; no linktools.smg.src.batch.testtest: batch renders Python-compatible...test; no linktools.smg.src.graphtest: graph clone owns payload indepe...private; no linktools.smg.src.modelcheckPairHelperAllocationFailurestest; no linktools.smg.src.modeltest: node json round tripprivate; no linktools.smg.src.scan.chicletaddDeclaration+48 moremodelsourcePair
Static calls · unresolved targets: 0 · external targets: 3.
Called byCallsNo direct callsprivate; no linktools.smg.src.batch.mutationcommandMetadatacli.metadatapairstest; no linktools.smg.src.modeltest: metadata pair upsert preserves ...modelupsertPair
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callersprivate; no linktools.smg.src.modelwriteEdgeJsonKindmodelwriteEdgeDataJson
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallscli.jsonrenderEdgeArrayprivate; no linktools.smg.src.modelwriteEdgeJsonKindmodelwriteEdgeDataJsonObject
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate; no linktools.smg.src.modelwriteEdgeJsonKindmodelwriteEdgeJson
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersprivate; no linktools.smg.src.modelwriteEdgeJsonKindmodelwriteEdgeJsonObject
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsprivate; no linktools.smg.src.modelwriteEdgeJsonKindprivate; no linktools.smg.src.modelwriteNodeJsonKindprivate; no linktools.smg.src.modelwritePairsObjectmodelwriteMetadata
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersprivate; no linktools.smg.src.modelwriteNodeJsonKindmodelwriteNodeDataJson
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallscli.jsonwriteAboutprivate; no linktools.smg.src.modelwriteNodeJsonKindmodelwriteNodeDataJsonObject
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest; no linktools.smg.src.modeltest: node json round tripprivate; no linktools.smg.src.modelwriteNodeJsonKindmodelwriteNodeJson
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersprivate; no linktools.smg.src.modelwriteNodeJsonKindmodelwriteNodeJsonObject
Static calls · unresolved targets: 0 · external targets: 0.

Source: tools/smg/src/model.zig

zig
const std = @import("std");const pretty = @import("pretty");const pretty_json = pretty.json;pub const NodeType = struct {    pub const package = "package";    pub const module = "module";    pub const class = "class";    pub const function = "function";    pub const method = "method";    pub const interface = "interface";    pub const variable = "variable";    pub const constant = "constant";    pub const @"type" = "type";    pub const field = "field";    pub const enum_tag = "enum_tag";    pub const error_member = "error_member";    pub const member_gap = "member_gap";    pub const endpoint = "endpoint";    pub const config = "config";};pub const RelType = struct {    pub const calls = "calls";    pub const inherits = "inherits";    pub const implements = "implements";    pub const contains = "contains";    pub const depends_on = "depends_on";    pub const imports = "imports";    pub const returns = "returns";    pub const accepts = "accepts";    pub const overrides = "overrides";    pub const decorates = "decorates";    pub const tests = "tests";};pub const Pair = struct {    key: []const u8,    value: []const u8,    json: bool = false,};pub const Node = struct {    name: []const u8,    type: []const u8,    file: ?[]const u8 = null,    line: ?i64 = null,    end_line: ?i64 = null,    docstring: ?[]const u8 = null,    metadata: []const Pair = &.{},};pub const Edge = struct {    source: []const u8,    target: []const u8,    rel: []const u8,    metadata: []const Pair = &.{},};pub fn deinitNode(node: *Node, allocator: std.mem.Allocator) void {    allocator.free(node.name);    allocator.free(node.type);    if (node.file) |value| allocator.free(value);    if (node.docstring) |value| allocator.free(value);    freePairs(allocator, node.metadata);    node.* = undefined;}pub fn deinitEdge(edge: *Edge, allocator: std.mem.Allocator) void {    allocator.free(edge.source);    allocator.free(edge.target);    allocator.free(edge.rel);    freePairs(allocator, edge.metadata);    edge.* = undefined;}pub fn cloneNode(allocator: std.mem.Allocator, node: Node) !Node {    var cloned = Node{        .name = try allocator.dupe(u8, node.name),        .type = &.{},    };    errdefer deinitNode(&cloned, allocator);    cloned.type = try allocator.dupe(u8, node.type);    cloned.file = if (node.file) |value| try allocator.dupe(u8, value) else null;    cloned.line = node.line;    cloned.end_line = node.end_line;    cloned.docstring = if (node.docstring) |value| try allocator.dupe(u8, value) else null;    cloned.metadata = try clonePairs(allocator, node.metadata);    return cloned;}pub fn cloneEdge(allocator: std.mem.Allocator, edge: Edge) !Edge {    var cloned = Edge{        .source = try allocator.dupe(u8, edge.source),        .target = &.{},        .rel = &.{},    };    errdefer deinitEdge(&cloned, allocator);    cloned.target = try allocator.dupe(u8, edge.target);    cloned.rel = try allocator.dupe(u8, edge.rel);    cloned.metadata = try clonePairs(allocator, edge.metadata);    return cloned;}pub fn clonePairs(allocator: std.mem.Allocator, pairs: []const Pair) ![]const Pair {    if (pairs.len == 0) return &.{};    const out = try allocator.alloc(Pair, pairs.len);    var initialized: usize = 0;    errdefer {        freePairPayloads(allocator, out[0..initialized]);        allocator.free(out);    }    for (pairs, 0..) |pair, index| {        const key = try allocator.dupe(u8, pair.key);        errdefer allocator.free(key);        const value = try allocator.dupe(u8, pair.value);        out[index] = .{            .key = key,            .value = value,            .json = pair.json,        };        initialized += 1;    }    return out;}pub fn freePairs(allocator: std.mem.Allocator, pairs: []const Pair) void {    freePairPayloads(allocator, pairs);    if (pairs.len != 0) allocator.free(pairs);}fn freePairPayloads(allocator: std.mem.Allocator, pairs: []const Pair) void {    for (pairs) |pair| {        allocator.free(pair.key);        allocator.free(pair.value);    }}pub fn pairValue(pairs: []const Pair, key: []const u8) ?[]const u8 {    for (pairs) |pair| if (std.mem.eql(u8, pair.key, key)) return pair.value;    return null;}pub fn replaceOwnedPairValue(pairs: []const Pair, key: []const u8, value: []const u8, json: bool) bool {    for (@constCast(pairs)) |*pair| {        if (!std.mem.eql(u8, pair.key, key)) continue;        pair.value = value;        pair.json = json;        return true;    }    return false;}pub fn upsertPair(allocator: std.mem.Allocator, pairs: *std.ArrayList(Pair), update: Pair) !void {    for (pairs.items) |*pair| {        if (std.mem.eql(u8, pair.key, update.key)) {            pair.value = update.value;            pair.json = update.json;            return;        }    }    try pairs.append(allocator, update);}pub fn mergePairs(allocator: std.mem.Allocator, existing: []const Pair, updates: []const Pair) ![]const Pair {    var out: std.ArrayList(Pair) = .empty;    errdefer out.deinit(allocator);    for (existing) |pair| try out.append(allocator, .{ .key = pair.key, .value = pair.value, .json = pair.json });    for (updates) |update| {        var replaced = false;        for (out.items) |*pair| {            if (std.mem.eql(u8, pair.key, update.key)) {                pair.value = update.value;                pair.json = update.json;                replaced = true;                break;            }        }        if (!replaced) try out.append(allocator, .{ .key = update.key, .value = update.value, .json = update.json });    }    return try out.toOwnedSlice(allocator);}pub fn sourcePair(allocator: std.mem.Allocator, value: []const u8) ![]const Pair {    const pairs = try allocator.alloc(Pair, 1);    errdefer allocator.free(pairs);    const key = try allocator.dupe(u8, "source");    errdefer allocator.free(key);    const pair_value = try allocator.dupe(u8, value);    pairs[0] = .{        .key = key,        .value = pair_value,    };    return pairs;}pub fn nodeFromValue(allocator: std.mem.Allocator, value: std.json.Value) !Node {    const object = switch (value) {        .object => |object| object,        else => return error.InvalidNode,    };    var node = Node{        .name = try allocator.dupe(u8, stringField(object, "name") orelse return error.InvalidNode),        .type = &.{},    };    errdefer deinitNode(&node, allocator);    node.type = try allocator.dupe(u8, stringField(object, "type") orelse return error.InvalidNode);    node.file = if (stringField(object, "file")) |v| try allocator.dupe(u8, v) else null;    node.line = intField(object, "line");    node.end_line = intField(object, "end_line");    node.docstring = if (stringField(object, "docstring")) |v| try allocator.dupe(u8, v) else null;    node.metadata = try metadataFromObject(allocator, object.get("metadata"));    return node;}pub fn edgeFromValue(allocator: std.mem.Allocator, value: std.json.Value) !Edge {    const object = switch (value) {        .object => |object| object,        else => return error.InvalidEdge,    };    var edge = Edge{        .source = try allocator.dupe(u8, stringField(object, "source") orelse return error.InvalidEdge),        .target = &.{},        .rel = &.{},    };    errdefer deinitEdge(&edge, allocator);    edge.target = try allocator.dupe(u8, stringField(object, "target") orelse return error.InvalidEdge);    edge.rel = try allocator.dupe(u8, stringField(object, "rel") orelse return error.InvalidEdge);    edge.metadata = try metadataFromObject(allocator, object.get("metadata"));    return edge;}fn stringField(object: std.json.ObjectMap, key: []const u8) ?[]const u8 {    const value = object.get(key) orelse return null;    return switch (value) {        .string => |string| string,        else => null,    };}fn intField(object: std.json.ObjectMap, key: []const u8) ?i64 {    const value = object.get(key) orelse return null;    return switch (value) {        .integer => |integer| integer,        .float => |float| @intFromFloat(float),        else => null,    };}fn metadataFromObject(allocator: std.mem.Allocator, maybe_value: ?std.json.Value) ![]const Pair {    const value = maybe_value orelse return &.{};    const object = switch (value) {        .object => |object| object,        else => return &.{},    };    var out: std.ArrayList(Pair) = .empty;    errdefer {        freePairPayloads(allocator, out.items);        out.deinit(allocator);    }    var it = object.iterator();    while (it.next()) |entry| {        const key = try allocator.dupe(u8, entry.key_ptr.*);        errdefer allocator.free(key);        const rendered = switch (entry.value_ptr.*) {            .string => |string| try allocator.dupe(u8, string),            else => try pretty_json.renderMinifiedAlloc(allocator, entry.value_ptr.*),        };        errdefer allocator.free(rendered);        try out.append(allocator, .{            .key = key,            .value = rendered,            .json = entry.value_ptr.* != .string,        });    }    return try out.toOwnedSlice(allocator);}pub fn writeNodeJson(node: Node, writer: *std.Io.Writer) !void {    var out = pretty_json.Writer.init(writer, .minified);    try writeNodeJsonKind(node, &out, true);}pub fn writeNodeDataJson(node: Node, writer: *std.Io.Writer) !void {    var out = pretty_json.Writer.init(writer, .minified);    try writeNodeJsonKind(node, &out, false);}pub fn writeNodeJsonObject(node: Node, writer: *pretty_json.Writer) !void {    try writeNodeJsonKind(node, writer, true);}pub fn writeNodeDataJsonObject(node: Node, writer: *pretty_json.Writer) !void {    try writeNodeJsonKind(node, writer, false);}fn writeNodeJsonKind(node: Node, writer: *pretty_json.Writer, include_kind: bool) !void {    try writer.beginObject();    if (include_kind) {        try writer.objectField("kind");        try writer.write("node");    }    try writer.objectField("name");    try writer.write(node.name);    try writer.objectField("type");    try writer.write(node.type);    if (node.file) |file| {        try writer.objectField("file");        try writer.write(file);    }    if (node.line) |line| {        try writer.objectField("line");        try writer.write(line);    }    if (node.end_line) |line| {        try writer.objectField("end_line");        try writer.write(line);    }    if (node.docstring) |doc| {        try writer.objectField("docstring");        try writer.write(doc);    }    if (node.metadata.len != 0) try writeMetadata(node.metadata, writer);    try writer.endObject();}pub fn writeEdgeJson(edge: Edge, writer: *std.Io.Writer) !void {    var out = pretty_json.Writer.init(writer, .minified);    try writeEdgeJsonKind(edge, &out, true);}pub fn writeEdgeDataJson(edge: Edge, writer: *std.Io.Writer) !void {    var out = pretty_json.Writer.init(writer, .minified);    try writeEdgeJsonKind(edge, &out, false);}pub fn writeEdgeJsonObject(edge: Edge, writer: *pretty_json.Writer) !void {    try writeEdgeJsonKind(edge, writer, true);}pub fn writeEdgeDataJsonObject(edge: Edge, writer: *pretty_json.Writer) !void {    try writeEdgeJsonKind(edge, writer, false);}fn writeEdgeJsonKind(edge: Edge, writer: *pretty_json.Writer, include_kind: bool) !void {    try writer.beginObject();    if (include_kind) {        try writer.objectField("kind");        try writer.write("edge");    }    try writer.objectField("source");    try writer.write(edge.source);    try writer.objectField("rel");    try writer.write(edge.rel);    try writer.objectField("target");    try writer.write(edge.target);    if (edge.metadata.len != 0) try writeMetadata(edge.metadata, writer);    try writer.endObject();}pub fn writeMetadata(pairs: []const Pair, writer: *pretty_json.Writer) !void {    try writer.objectField("metadata");    try writePairsObject(pairs, writer);}fn writePairsObject(pairs: []const Pair, writer: *pretty_json.Writer) !void {    try writer.beginObject();    for (pairs) |pair| {        try writer.objectField(pair.key);        if (pair.json) {            try writer.raw(pair.value);        } else {            try writer.write(pair.value);        }    }    try writer.endObject();}pub fn renderPairsAlloc(allocator: std.mem.Allocator, pairs: []const Pair) ![]const u8 {    var out: std.Io.Writer.Allocating = .init(allocator);    errdefer out.deinit();    var writer = pretty_json.Writer.init(&out.writer, .minified);    try writePairsObject(pairs, &writer);    return try out.toOwnedSlice();}pub fn pairsFromRenderedJson(allocator: std.mem.Allocator, text: []const u8) ![]const Pair {    if (text.len == 0) return &.{};    var scanner = std.json.Scanner.initCompleteInput(allocator, text);    defer scanner.deinit();    var out: std.ArrayList(Pair) = .empty;    errdefer {        freePairPayloads(allocator, out.items);        out.deinit(allocator);    }    renderedPairsInto(allocator, &scanner, text, &out) catch |err| switch (err) {        error.OutOfMemory => return error.OutOfMemory,        else => return error.InvalidMetadata,    };    return try out.toOwnedSlice(allocator);}fn renderedPairsInto(allocator: std.mem.Allocator, scanner: *std.json.Scanner, text: []const u8, out: *std.ArrayList(Pair)) !void {    switch (try scanner.peekNextTokenType()) {        .object_begin => {},        .end_of_document => return error.InvalidMetadata,        else => {            try scanner.skipValue();            if (try scanner.peekNextTokenType() != .end_of_document) return error.InvalidMetadata;            return;        },    }    _ = try scanner.next();    while (true) {        if (try scanner.peekNextTokenType() == .object_end) {            _ = try scanner.next();            break;        }        const key = try ownedTokenString(allocator, try scanner.nextAllocMax(allocator, .alloc_if_needed, std.json.default_max_value_len));        errdefer allocator.free(key);        switch (try scanner.peekNextTokenType()) {            .string => {                const value = try ownedTokenString(allocator, try scanner.nextAllocMax(allocator, .alloc_if_needed, std.json.default_max_value_len));                errdefer allocator.free(value);                try out.append(allocator, .{ .key = key, .value = value, .json = false });            },            .object_begin, .array_begin, .number, .true, .false, .null => {                const start = scanner.cursor;                try scanner.skipValue();                const value = try allocator.dupe(u8, text[start..scanner.cursor]);                errdefer allocator.free(value);                try out.append(allocator, .{ .key = key, .value = value, .json = true });            },            else => return error.InvalidMetadata,        }    }    if (try scanner.peekNextTokenType() != .end_of_document) return error.InvalidMetadata;}fn ownedTokenString(allocator: std.mem.Allocator, token: std.json.Token) ![]const u8 {    return switch (token) {        .string => |slice| try allocator.dupe(u8, slice),        .allocated_string => |slice| slice,        else => error.InvalidMetadata,    };}pub fn pairsEqual(left: []const Pair, right: []const Pair) bool {    if (left.len != right.len) return false;    for (left, right) |a, b| {        if (a.json != b.json) return false;        if (!std.mem.eql(u8, a.key, b.key)) return false;        if (!std.mem.eql(u8, a.value, b.value)) return false;    }    return true;}pub fn nodeEquals(left: Node, right: Node) bool {    if (!std.mem.eql(u8, left.name, right.name)) return false;    if (!std.mem.eql(u8, left.type, right.type)) return false;    if (!optionalTextEqual(left.file, right.file)) return false;    if (!std.meta.eql(left.line, right.line)) return false;    if (!std.meta.eql(left.end_line, right.end_line)) return false;    if (!optionalTextEqual(left.docstring, right.docstring)) return false;    return pairsEqual(left.metadata, right.metadata);}pub fn edgeEquals(left: Edge, right: Edge) bool {    if (!std.mem.eql(u8, left.source, right.source)) return false;    if (!std.mem.eql(u8, left.rel, right.rel)) return false;    if (!std.mem.eql(u8, left.target, right.target)) return false;    return pairsEqual(left.metadata, right.metadata);}fn optionalTextEqual(left: ?[]const u8, right: ?[]const u8) bool {    const a = left orelse return right == null;    const b = right orelse return false;    return std.mem.eql(u8, a, b);}test "node json round trip" {    var arena = std.heap.ArenaAllocator.init(std.testing.allocator);    defer arena.deinit();    const allocator = arena.allocator();    const meta = try sourcePair(allocator, "manual");    const node: Node = .{ .name = "a.b", .type = NodeType.module, .file = "a/b.zig", .line = 3, .metadata = meta };    var out: std.Io.Writer.Allocating = .init(allocator);    try writeNodeJson(node, &out.writer);    const parsed = try std.json.parseFromSlice(std.json.Value, allocator, out.written(), .{});    const clone = try nodeFromValue(allocator, parsed.value);    try std.testing.expectEqualStrings("a.b", clone.name);    try std.testing.expectEqualStrings("manual", pairValue(clone.metadata, "source").?);}test "metadata pairs round trip through json text" {    const allocator = std.testing.allocator;    const pairs = [_]Pair{        .{ .key = "source", .value = "scan" },        .{ .key = "metrics", .value = "{\"fan_in\":2,\"fan_out\":0}", .json = true },    };    const rendered = try renderPairsAlloc(allocator, &pairs);    defer allocator.free(rendered);    try std.testing.expectEqualStrings("{\"source\":\"scan\",\"metrics\":{\"fan_in\":2,\"fan_out\":0}}", rendered);    const decoded = try pairsFromRenderedJson(allocator, rendered);    defer freePairs(allocator, decoded);    try std.testing.expect(pairsEqual(&pairs, decoded));    const rerendered = try renderPairsAlloc(allocator, decoded);    defer allocator.free(rerendered);    try std.testing.expectEqualStrings(rendered, rerendered);    const empty = try pairsFromRenderedJson(allocator, "");    try std.testing.expectEqual(@as(usize, 0), empty.len);    try std.testing.expectError(error.InvalidMetadata, pairsFromRenderedJson(allocator, "not json"));}test "metadata pair upsert preserves replacement shape" {    const allocator = std.testing.allocator;    var pairs: std.ArrayList(Pair) = .empty;    defer pairs.deinit(allocator);    try upsertPair(allocator, &pairs, .{ .key = "source", .value = "manual" });    try upsertPair(allocator, &pairs, .{ .key = "source", .value = "scan", .json = true });    try upsertPair(allocator, &pairs, .{ .key = "owner", .value = "smg" });    try std.testing.expectEqual(@as(usize, 2), pairs.items.len);    try std.testing.expectEqualStrings("scan", pairValue(pairs.items, "source").?);    try std.testing.expect(pairs.items[0].json);    try std.testing.expectEqualStrings("smg", pairValue(pairs.items, "owner").?);}test "rendered pairs decode all value shapes byte exactly" {    const allocator = std.testing.allocator;    const pairs = [_]Pair{        .{ .key = "plain", .value = "scan" },        .{ .key = "esc\"aped", .value = "line\nbreak \"quoted\" \\slash" },        .{ .key = "unicode", .value = "snowman \u{2603} tail" },        .{ .key = "metrics", .value = "{\"fan_in\":2,\"nested\":{\"deep\":[1,2,3]}}", .json = true },        .{ .key = "count", .value = "42", .json = true },        .{ .key = "ratio", .value = "-3.5e-2", .json = true },        .{ .key = "flag", .value = "true", .json = true },        .{ .key = "gone", .value = "null", .json = true },        .{ .key = "list", .value = "[\"a\",{\"b\":\"c\"}]", .json = true },    };    const rendered = try renderPairsAlloc(allocator, &pairs);    defer allocator.free(rendered);    const decoded = try pairsFromRenderedJson(allocator, rendered);    defer freePairs(allocator, decoded);    try std.testing.expect(pairsEqual(&pairs, decoded));    const rerendered = try renderPairsAlloc(allocator, decoded);    defer allocator.free(rerendered);    try std.testing.expectEqualStrings(rendered, rerendered);    const non_object = try pairsFromRenderedJson(allocator, "[1,2]");    try std.testing.expectEqual(@as(usize, 0), non_object.len);    try std.testing.expectError(error.InvalidMetadata, pairsFromRenderedJson(allocator, "{\"a\":\"b\"}trailing"));    try std.testing.expectError(error.InvalidMetadata, pairsFromRenderedJson(allocator, "{\"a\":}"));}test "pair helpers clean up allocation failures" {    try std.testing.checkAllAllocationFailures(        std.testing.allocator,        checkPairHelperAllocationFailures,        .{},    );}fn checkPairHelperAllocationFailures(allocator: std.mem.Allocator) !void {    const source = try sourcePair(allocator, "manual");    defer freePairs(allocator, source);    const cloned = try clonePairs(allocator, source);    defer freePairs(allocator, cloned);    const updates = [_]Pair{        .{ .key = "source", .value = "scan" },        .{ .key = "async", .value = "true", .json = true },    };    const merged = try mergePairs(allocator, cloned, &updates);    defer allocator.free(merged);    try std.testing.expectEqualStrings("scan", pairValue(merged, "source").?);    try std.testing.expectEqualStrings("true", pairValue(merged, "async").?);}test "node parsing cleans up allocation failures" {    try checkAllModelAllocationFailures(checkNodeParsingAllocationFailures);}fn checkNodeParsingAllocationFailures(allocator: std.mem.Allocator) !void {    var parsed = try std.json.parseFromSlice(std.json.Value, std.testing.allocator,        \\{"name":"app.main","type":"function","file":"app.zig","line":7,"end_line":9,"docstring":"entry","metadata":{"source":"scan","async":true,"rank":3}}    , .{});    defer parsed.deinit();    var node = try nodeFromValue(allocator, parsed.value);    defer deinitNode(&node, allocator);    try std.testing.expectEqualStrings("app.main", node.name);    try std.testing.expectEqualStrings("true", pairValue(node.metadata, "async").?);}test "edge parsing cleans up allocation failures" {    try checkAllModelAllocationFailures(checkEdgeParsingAllocationFailures);}fn checkEdgeParsingAllocationFailures(allocator: std.mem.Allocator) !void {    var parsed = try std.json.parseFromSlice(std.json.Value, std.testing.allocator,        \\{"source":"app.main","rel":"calls","target":"app.helper","metadata":{"source":"scan","weight":2}}    , .{});    defer parsed.deinit();    var edge = try edgeFromValue(allocator, parsed.value);    defer deinitEdge(&edge, allocator);    try std.testing.expectEqualStrings("app.main", edge.source);    try std.testing.expectEqualStrings("2", pairValue(edge.metadata, "weight").?);}fn checkAllModelAllocationFailures(comptime test_fn: anytype) !void {    var fail_index: usize = 0;    while (true) : (fail_index += 1) {        var failing = std.testing.FailingAllocator.init(std.testing.allocator, .{ .fail_index = fail_index });        if (@call(.auto, test_fn, .{failing.allocator()})) |_| {            if (failing.has_induced_failure) return error.SwallowedOutOfMemoryError;            return;        } else |err| switch (err) {            error.OutOfMemory => {                try std.testing.expect(failing.has_induced_failure);                try std.testing.expectEqual(failing.allocated_bytes, failing.freed_bytes);            },            else => |other| return other,        }    }}

Source: tools/smg/src/root.zig:26

zig
pub const model = @import("model.zig");

Complete caller list for model.deinitEdge

14 direct callers.

Complete caller list for model.deinitNode

18 direct callers.

Complete caller list for model.mergePairs

13 direct callers.

Complete caller list for model.pairValue

103 direct callers.

Complete caller list for model.sourcePair

53 direct callers.

Audit

Definitions29
Public names29
Members3
Version26.7.0
Revisiondaab053ee433