Skip to documentation
SLOP

tiny.zen.diagram.dsl

Reference tiny.zen diagram dsl

Defined in diagram.

API (30)

Actions

Public operations.

Types and contracts

Public types and contracts.

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

Source

Called byCallsdiagram.FigurerenderAsciiprivate sourcelib.zen.src.diagram.dslappendLayerprivate sourcelib.zen.src.diagram.dslcopyFrameprivate sourcelib.zen.src.diagram.dslcopyRowprivate sourcelib.zen.src.diagram.dslcopyScalesprivate sourcelib.zen.src.diagram.dslcopyTransformdiagram.Figuredocument
Static calls · unresolved targets: 2 · external targets: 2.
Called byCallsNo direct callersdiagram.Figuredocumentdiagram.FigurerenderAscii
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsNo direct callstest sourcelib.zen.src.diagram.dsltest: diagram DSL renders data-driven...diagram.dslbar
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersdiagram.dslfielddiagram.dslboolean
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsdiagram.dslbooleandiagram.dslnumberdiagram.dsltextdiagram.dslfield
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.zen.src.diagram.dsltest: diagram DSL renders data-driven...diagram.dslfigure
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.zen.src.diagram.dsltest: diagram DSL renders data-driven...diagram.dslfielddiagram.dslnumber
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.zen.src.diagram.dsltest: diagram DSL renders data-driven...diagram.dslrow
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.zen.src.diagram.dsltest: diagram DSL renders data-driven...diagram.dslfielddiagram.dsltext
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/zen/src/diagram/dsl.zig

zig
const std = @import("std");const root = @import("root.zig");const spec = root.spec;pub const Value = union(enum) {    number: f64,    text: []const u8,    boolean: bool,};pub const Field = struct {    name: []const u8,    value: Value,};pub const Row = struct {    name: []const u8,    fields: []const Field,};pub const Frame = struct {    width: f64 = 640,    height: f64 = 360,    inset: f64 = 44,    axes: bool = true,    title: []const u8 = "",    x_label: []const u8 = "",    y_label: []const u8 = "",    background: []const u8 = "",    y_min: ?f64 = null,    y_max: ?f64 = null,    x_min: ?f64 = null,    x_max: ?f64 = null,};pub const Scale = struct {    kind: spec.ScaleKind = .linear,    min: ?f64 = null,    max: ?f64 = null,    base: f64 = 10,    label: []const u8 = "",};pub const Scales = struct {    x: Scale = .{},    y: Scale = .{},};pub const Stack = struct {    mark: []const u8 = "bar",};pub const Transform = union(enum) {    stack: Stack,};pub const Channel = struct {    data: []const u8,    x: []const u8,    y: []const u8,    label: []const u8 = "",    fill: []const u8 = "",    series: []const u8 = "",    text: []const u8 = "",    radius: []const u8 = "",};pub const Rule = struct {    x1: f64,    y1: f64,    x2: f64,    y2: f64,    stroke: []const u8 = "",};pub const Box = struct {    x: f64,    y: f64,    width: f64,    height: f64,    text: []const u8 = "",    fill: []const u8 = "",    stroke: []const u8 = "",};pub const Edge = struct {    x1: f64,    y1: f64,    x2: f64,    y2: f64,    label: []const u8 = "",    stroke: []const u8 = "",    arrow: bool = true,};pub const Layer = union(enum) {    bar: Channel,    point: Channel,    label: Channel,    rule: Rule,    box: Box,    edge: Edge,};/// Borrowed declarative diagram that can create an owned document or ASCII result.pub const Figure = struct {    frame: Frame = .{},    scales: Scales = .{},    transforms: []const Transform = &.{},    data: []const Row = &.{},    layers: []const Layer = &.{},    /// Copies declarative values into an owned diagram document.    pub fn document(self: Figure, allocator: std.mem.Allocator) !spec.Document {        var result = spec.Document{ .allocator = allocator };        errdefer result.deinit();        result.frame = try copyFrame(allocator, self.frame);        result.scales = try copyScales(allocator, self.scales);        for (self.transforms) |transform_value| {            var copied = try copyTransform(allocator, transform_value);            var owned = true;            errdefer if (owned) copied.deinit(allocator);            try result.transforms.append(allocator, copied);            owned = false;        }        for (self.data) |row_value| {            var copied = try copyRow(allocator, row_value);            var owned = true;            errdefer if (owned) copied.deinit(allocator);            try result.data.append(allocator, copied);            owned = false;        }        for (self.layers) |layer_value| try appendLayer(allocator, &result, layer_value);        return result;    }    /// Returns owned ASCII output; release it with the same allocator.    pub fn renderAscii(        self: Figure,        allocator: std.mem.Allocator,        options: root.ascii.Options,    ) !root.ascii.Rendered {        var result = try self.document(allocator);        defer result.deinit();        return try root.ascii.renderOwned(allocator, &result, options);    }};pub fn figure(value: Figure) Figure {    return value;}pub fn row(name: []const u8, fields: []const Field) Row {    return .{ .name = name, .fields = fields };}pub fn field(name: []const u8, value: Value) Field {    return .{ .name = name, .value = value };}pub fn number(name: []const u8, value: f64) Field {    return field(name, .{ .number = value });}pub fn text(name: []const u8, value: []const u8) Field {    return field(name, .{ .text = value });}pub fn boolean(name: []const u8, value: bool) Field {    return field(name, .{ .boolean = value });}pub fn bar(channel: Channel) Layer {    return .{ .bar = channel };}pub fn point(channel: Channel) Layer {    return .{ .point = channel };}pub fn label(channel: Channel) Layer {    return .{ .label = channel };}pub fn layer(value: Layer) Layer {    return value;}pub fn rule(value: Rule) Layer {    return .{ .rule = value };}pub fn box(value: Box) Layer {    return .{ .box = value };}pub fn edge(value: Edge) Layer {    return .{ .edge = value };}pub fn stack() Transform {    return .{ .stack = .{} };}fn copyFrame(allocator: std.mem.Allocator, value: Frame) !spec.Frame {    var result = spec.Frame{        .width = value.width,        .height = value.height,        .inset = value.inset,        .axes = value.axes,        .y_min = value.y_min,        .y_max = value.y_max,        .x_min = value.x_min,        .x_max = value.x_max,    };    errdefer result.deinit(allocator);    result.title = try copyString(allocator, value.title);    result.x_label = try copyString(allocator, value.x_label);    result.y_label = try copyString(allocator, value.y_label);    result.background = try copyString(allocator, value.background);    return result;}fn copyScales(allocator: std.mem.Allocator, value: Scales) !spec.Scales {    var result = spec.Scales{};    errdefer result.deinit(allocator);    result.x = try copyScale(allocator, value.x);    result.y = try copyScale(allocator, value.y);    return result;}fn copyScale(allocator: std.mem.Allocator, value: Scale) !spec.Scale {    var result = spec.Scale{        .kind = value.kind,        .min = value.min,        .max = value.max,        .base = value.base,    };    errdefer result.deinit(allocator);    result.label = try copyString(allocator, value.label);    return result;}fn copyTransform(allocator: std.mem.Allocator, value: Transform) !spec.Transform {    return switch (value) {        .stack => |stack_value| .{ .stack = .{ .mark = try copyString(allocator, stack_value.mark) } },    };}fn copyRow(allocator: std.mem.Allocator, value: Row) !spec.DataRow {    var result = spec.DataRow{ .name = try copyRequiredString(allocator, value.name) };    errdefer result.deinit(allocator);    for (value.fields) |field_value| {        var copied = spec.Field{ .name = &.{}, .value = .{ .number = 0 } };        var owned = true;        errdefer if (owned) copied.deinit(allocator);        copied.name = try copyRequiredString(allocator, field_value.name);        copied.value = try copyValue(allocator, field_value.value);        try result.fields.append(allocator, copied);        owned = false;    }    if (result.fields.items.len == 0) return error.InvalidData;    return result;}fn copyValue(allocator: std.mem.Allocator, value: Value) !spec.DataValue {    return switch (value) {        .number => |number_value| .{ .number = number_value },        .text => |text_value| .{ .text = try copyString(allocator, text_value) },        .boolean => |boolean_value| .{ .boolean = boolean_value },    };}fn appendLayer(allocator: std.mem.Allocator, document_value: *spec.Document, value: Layer) !void {    switch (value) {        .bar => |channel| try appendChannelLayer(allocator, document_value, channel, .bar),        .point => |channel| try appendChannelLayer(allocator, document_value, channel, .point),        .label => |channel| try appendChannelLayer(allocator, document_value, channel, .text),        .rule => |rule_value| {            var copied = spec.Mark{ .rule = try copyRule(allocator, rule_value) };            var owned = true;            errdefer if (owned) copied.deinit(allocator);            try document_value.marks.append(allocator, copied);            owned = false;        },        .box => |box_value| {            var copied = spec.Mark{ .box = try copyBox(allocator, box_value) };            var owned = true;            errdefer if (owned) copied.deinit(allocator);            try document_value.marks.append(allocator, copied);            owned = false;        },        .edge => |edge_value| {            var copied = spec.Mark{ .edge = try copyEdge(allocator, edge_value) };            var owned = true;            errdefer if (owned) copied.deinit(allocator);            try document_value.marks.append(allocator, copied);            owned = false;        },    }}const ChannelLayer = enum {    bar,    point,    text,};fn appendChannelLayer(allocator: std.mem.Allocator, document_value: *spec.Document, channel: Channel, kind: ChannelLayer) !void {    var matched = false;    for (document_value.data.items) |*row_value| {        if (!std.mem.eql(u8, row_value.name, channel.data)) continue;        matched = true;        var mark = try markFromChannel(allocator, channel, row_value, kind);        var owned = true;        errdefer if (owned) mark.deinit(allocator);        try document_value.marks.append(allocator, mark);        owned = false;    }    if (!matched) return error.UnknownData;}fn markFromChannel(allocator: std.mem.Allocator, channel: Channel, row_value: *const spec.DataRow, kind: ChannelLayer) !spec.Mark {    return switch (kind) {        .bar => .{ .bar = try barFromChannel(allocator, channel, row_value) },        .point => .{ .point = try pointFromChannel(allocator, channel, row_value) },        .text => .{ .text = try textFromChannel(allocator, channel, row_value) },    };}fn barFromChannel(allocator: std.mem.Allocator, channel: Channel, row_value: *const spec.DataRow) !spec.Bar {    var result = spec.Bar{ .x = &.{}, .y = 0 };    errdefer result.deinit(allocator);    result.x = try requiredText(allocator, row_value, channel.x);    result.y = try requiredNumber(row_value, channel.y);    result.series = try optionalText(allocator, row_value, channel.series);    result.label = try optionalText(allocator, row_value, channel.label);    result.fill = try optionalText(allocator, row_value, channel.fill);    return result;}fn pointFromChannel(allocator: std.mem.Allocator, channel: Channel, row_value: *const spec.DataRow) !spec.Point {    var result = spec.Point{ .x = .{ .number = 0 }, .y = 0 };    errdefer result.deinit(allocator);    result.x = try requiredX(allocator, row_value, channel.x);    result.y = try requiredNumber(row_value, channel.y);    result.label = try optionalText(allocator, row_value, channel.label);    result.fill = try optionalText(allocator, row_value, channel.fill);    result.radius = if (channel.radius.len == 0) 4 else try requiredNumber(row_value, channel.radius);    return result;}fn textFromChannel(allocator: std.mem.Allocator, channel: Channel, row_value: *const spec.DataRow) !spec.Text {    if (channel.text.len == 0) return error.MissingField;    var result = spec.Text{ .x = .{ .number = 0 }, .y = 0, .text = &.{} };    errdefer result.deinit(allocator);    result.x = try requiredX(allocator, row_value, channel.x);    result.y = try requiredNumber(row_value, channel.y);    result.text = try requiredText(allocator, row_value, channel.text);    result.fill = try optionalText(allocator, row_value, channel.fill);    return result;}fn copyRule(allocator: std.mem.Allocator, value: Rule) !spec.Rule {    var result = spec.Rule{        .x1 = value.x1,        .y1 = value.y1,        .x2 = value.x2,        .y2 = value.y2,    };    errdefer result.deinit(allocator);    result.stroke = try copyString(allocator, value.stroke);    return result;}fn copyBox(allocator: std.mem.Allocator, value: Box) !spec.Box {    if (value.width <= 0 or value.height <= 0) return error.InvalidField;    var result = spec.Box{        .x = value.x,        .y = value.y,        .width = value.width,        .height = value.height,    };    errdefer result.deinit(allocator);    result.text = try copyString(allocator, value.text);    result.fill = try copyString(allocator, value.fill);    result.stroke = try copyString(allocator, value.stroke);    return result;}fn copyEdge(allocator: std.mem.Allocator, value: Edge) !spec.Edge {    var result = spec.Edge{        .x1 = value.x1,        .y1 = value.y1,        .x2 = value.x2,        .y2 = value.y2,        .arrow = value.arrow,    };    errdefer result.deinit(allocator);    result.label = try copyString(allocator, value.label);    result.stroke = try copyString(allocator, value.stroke);    return result;}fn requiredValue(row_value: *const spec.DataRow, name: []const u8) !spec.DataValue {    if (name.len == 0) return error.MissingField;    return row_value.lookup(name) orelse error.MissingField;}fn requiredNumber(row_value: *const spec.DataRow, name: []const u8) !f64 {    return numberValue(try requiredValue(row_value, name));}fn requiredText(allocator: std.mem.Allocator, row_value: *const spec.DataRow, name: []const u8) ![]u8 {    return textValue(allocator, try requiredValue(row_value, name));}fn requiredX(allocator: std.mem.Allocator, row_value: *const spec.DataRow, name: []const u8) !spec.XValue {    return xValue(allocator, try requiredValue(row_value, name));}fn optionalText(allocator: std.mem.Allocator, row_value: *const spec.DataRow, name: []const u8) ![]u8 {    if (name.len == 0) return &.{};    return requiredText(allocator, row_value, name);}fn numberValue(value: spec.DataValue) !f64 {    return switch (value) {        .number => |number_value| number_value,        .text => |text_value| std.fmt.parseFloat(f64, text_value) catch error.InvalidField,        .boolean => error.InvalidField,    };}fn textValue(allocator: std.mem.Allocator, value: spec.DataValue) ![]u8 {    return switch (value) {        .number => |number_value| try std.fmt.allocPrint(allocator, "{d}", .{number_value}),        .text => |text_value| try copyString(allocator, text_value),        .boolean => |boolean_value| try copyString(allocator, if (boolean_value) "true" else "false"),    };}fn xValue(allocator: std.mem.Allocator, value: spec.DataValue) !spec.XValue {    return switch (value) {        .number => |number_value| .{ .number = number_value },        .text => |text_value| .{ .text = try copyString(allocator, text_value) },        .boolean => |boolean_value| .{ .text = try copyString(allocator, if (boolean_value) "true" else "false") },    };}fn copyRequiredString(allocator: std.mem.Allocator, value: []const u8) ![]u8 {    if (value.len == 0) return error.MissingField;    return copyString(allocator, value);}fn copyString(allocator: std.mem.Allocator, value: []const u8) ![]u8 {    if (value.len == 0) return &.{};    return try allocator.dupe(u8, value);}test "diagram DSL renders data-driven bars as ASCII" {    const plot = figure(.{        .frame = .{ .title = "Coin", .y_min = 0, .y_max = 1, .x_label = "outcome", .y_label = "p" },        .data = &.{            row("coin", &.{ text("outcome", "heads"), number("probability", 0.62), text("label", "heads") }),            row("coin", &.{ text("outcome", "tails"), number("probability", 0.38), text("label", "tails") }),        },        .layers = &.{            bar(.{ .data = "coin", .x = "outcome", .y = "probability", .label = "label" }),        },    });    var rendered = try plot.renderAscii(std.testing.allocator, .{ .width = 40, .height = 12 });    defer rendered.deinit(std.testing.allocator);    try std.testing.expect(std.mem.indexOf(u8, rendered.output, "Coin") != null);    try std.testing.expect(std.mem.indexOf(u8, rendered.output, "heads") != null);    try std.testing.expect(std.mem.indexOf(u8, rendered.output, "#") != null);}

Source: lib/zen/src/diagram/root.zig:6

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

Audit

Definitions31
Public names51
Members66
Version26.7.0
Revisiondaab053ee433