Zig Notes

contract programming
Login

contract programming

Example adapted from, probably, the Programming in Ada 2012 book.

const std = @import("std");
const builtin = @import("builtin");

fn assert(ok: bool) void {
    // negate the pop() precondition and see what happens without this test
    if (builtin.mode == .ReleaseFast) return;
    if (!ok) unreachable;
}

fn Stack(T: type, S: usize) type {
    return struct {
        stack: [S]T,
        depth: usize,
        pub const empty = Stack(T, S){ .stack = .{0} ** S, .depth = 0 };
        pub fn is_empty(self: *Stack(T, S)) bool {
            return self.depth == 0;
        }
        pub fn is_full(self: *Stack(T, S)) bool {
            return self.depth == S;
        }
        pub fn pop(self: *Stack(T, S)) T {
            assert(!self.is_empty());
            self.depth -= 1;
            return self.stack[self.depth];
        }
        pub fn push(self: *Stack(T, S), x: T) void {
            assert(!self.is_full());
            defer assert(!self.is_empty());
            self.stack[self.depth] = x;
            self.depth += 1;
        }
        pub fn slice(self: *Stack(T, S)) []T {
            return self.stack[0..self.depth];
        }
    };
}

pub fn main() !void {
    var a: Stack(u8, 5) = .empty;
    var b: Stack(u8, 5) = .empty;
    a.push(1);
    b.push(1);
    b.push(2);
    try std.testing.expect(!std.mem.eql(u8, a.slice(), b.slice()));
    _ = b.pop();
    try std.testing.expect(std.mem.eql(u8, a.slice(), b.slice()));

    b.push(2);
    b.push(3);
    b.push(4);
    b.push(5);
    try std.testing.expect(b.is_full());
    std.debug.print("{any}\n{any}\n", .{ a, b });
}