WIP: varint-extension

[?]
Jun 13, 2023, 2:57 AM
H3JTOAUEPPD7BWQA3M6WTYXPTGPEJXZLNIDPRJ7MJKZWEYNRZOTAC

Dependencies

Change contents

  • file addition: varint-extension (d--r------)
    [2.5]
  • file addition: varint-extension.zig (----------)
    [0.6]
    // https://csprimer.com/watch/varint-extension/
    // inspired by https://github.com/adamserafini/zaml/blob/27b2d54ffb39aace5d5d58f0aa75396c3e6fe84d/zamlmodule.zig
    const std = @import("std");
    const varint = @import("protobuf-varint");
    const py = @cImport({
    @cDefine("PY_SSIZE_T_CLEAN", {});
    @cInclude("Python.h");
    });
    fn cvarint_encode(
    self: [*c]py.PyObject,
    args: [*c]py.PyObject,
    ) callconv(.C) [*]py.PyObject {
    _ = self;
    var cvalue_K: CUInt = undefined;
    if (!py.PyArg_ParseTuple(args, "K", &cvalue_K)) return null;
    if (!canIntCast(u64, cvalue_K)) return null;
    const value = @intCast(u64, cvalue_K);
    var buffer: [10]varint.VarintByte = undefined;
    const result_vbytes = varint.encode(value, &buffer);
    // see https://docs.python.org/3/c-api/arg.html#building-values
    return py.Py_BuildValue(
    "y#",
    @ptrCast([*c]u8, result_vbytes.ptr),
    @as(py.Py_ssize_t, result_vbytes.len),
    );
    }
    fn cvarint_decode(
    self: [*c]py.PyObject,
    args: [*c]py.PyObject,
    ) callconv(.C) [*]py.PyObject {
    _ = self;
    var cvalue_ptr: [*c]u8 = undefined;
    var cvalue_len: py.Py_ssize_t = undefined;
    if (!py.PyArg_ParseTuple(args, "K", &cvalue_ptr, &cvalue_len)) return null;
    if (!cvalue_ptr) return null;
    const value = @ptrCast([]const varint.VarintByte, cvalue_ptr[0..cvalue_len]);
    const result = varint.decode(value) orelse return null;
    return py.Py_BuildValue("K", @as(CUInt, result));
    }
    /// A c-native uint at least as big as u64.
    const CUInt: type = c_ulonglong;
    comptime {
    std.debug.assert(@bitSizeOf(CUInt) >= @bitSizeOf(u64));
    }
    /// Runtime check that an int value fits in another int type.
    fn canIntCast(comptime T: type, value: anytype) bool {
    return @truncate(@TypeOf(value), @truncate(T, value)) != value;
    }
    var CVarintMethods = [_]py.PyMethodDef{
    py.PyMethodDef{
    .ml_name = "encode",
    .ml_meth = cvarint_encode,
    .ml_flags = py.METH_VARARGS,
    .ml_doc = "Encode an integer as varint.",
    },
    py.PyMethodDef{
    .ml_name = "decode",
    .ml_meth = cvarint_decode,
    .ml_flags = py.METH_VARARGS,
    .ml_doc = "Decode varint bytes to an integer.",
    },
    py.PyMethodDef{
    .ml_name = null,
    .ml_meth = null,
    .ml_flags = 0,
    .ml_doc = null,
    },
    };
    var cvarintmodule = py.PyModuleDef{
    .m_base = py.PyModuleDef_Base{
    .ob_base = py.PyObject{
    .ob_refcnt = 1,
    .ob_type = null,
    },
    .m_init = null,
    .m_index = 0,
    .m_copy = null,
    },
    .m_name = "cvarint",
    .m_doc = "A C implementation of protobuf varint encoding",
    .m_size = -1,
    .m_methods = &CVarintMethods,
    .m_slots = null,
    .m_traverse = null,
    .m_clear = null,
    .m_free = null,
    };
    pub export fn PyInit_cvarint() [*]py.PyObject {
    return py.PyModule_Create(&cvarintmodule);
    }
  • file addition: build.zig (----------)
    [0.6]
    const std = @import("std");
    // Although this function looks imperative, note that its job is to
    // declaratively construct a build graph that will be executed by an external
    // runner.
    pub fn build(b: *std.Build) void {
    // Standard target options allows the person running `zig build` to choose
    // what target to build for. Here we do not override the defaults, which
    // means any target is allowed, and the default is native. Other options
    // for restricting supported target set are available.
    const target = b.standardTargetOptions(.{});
    // Standard optimization options allow the person running `zig build` to select
    // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
    // set a preferred release mode, allowing the user to decide how to optimize.
    const optimize = b.standardOptimizeOption(.{});
    const lib = b.addSharedLibrary(.{
    .name = "varint-extension",
    // In this case the main source file is merely a path, however, in more
    // complicated build scripts, this could be a generated file.
    .root_source_file = .{ .path = "varint-extension.zig" },
    .target = target,
    .optimize = optimize,
    });
    // Add protobuf varint Zig implementation as a dependency.
    const protobuf_varint = b.addModule("protobuf-varint", .{ .source_file = .{ .path = "../../bits-and-bytes/protobuf-varint.zig" } });
    lib.addModule("protobuf-varint", protobuf_varint);
    // This declares intent for the library to be installed into the standard
    // location when the user invokes the "install" step (the default step when
    // running `zig build`).
    b.installArtifact(lib);
    // Creates a step for unit testing. This only builds the test executable
    // but does not run it.
    const main_tests = b.addTest(.{
    .root_source_file = .{ .path = "src/main.zig" },
    .target = target,
    .optimize = optimize,
    });
    const run_main_tests = b.addRunArtifact(main_tests);
    // This creates a build step. It will be visible in the `zig build --help` menu,
    // and can be selected like this: `zig build test`
    // This will evaluate the `test` step rather than the default, which is "install".
    const test_step = b.step("test", "Run library tests");
    test_step.dependOn(&run_main_tests.step);
    }
  • replacement in zig/src/computer-systems/bits-and-bytes/protobuf-varint.zig at line 70
    [3.1941][3.1941:1990]()
    pub fn decode(buffer: []const VarintByte) !u64 {
    [3.1941]
    [3.1990]
    pub fn decode(buffer: []const VarintByte) DecodeError!u64 {
  • edit in zig/.gitignore at line 2
    [5.875]
    zig-out