Skip to documentation
SLOP

tiny.preserves.SignedInteger

Reference tiny.preserves SignedInteger

Defined in integer_mod.

A signed integer of any size, stored in the smallest of three representations that holds it.

API (19)

Actions

Public operations.

Types and contracts

Public types and contracts.

Fields and members

Public fields and members.

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

Source

Source: lib/preserves/src/integer.zig:47

zig
/// A signed integer of any size, stored in the smallest of three representations that holds it./// Every integer in a value is one of these, so every reader, writer and comparison of integers/// uses it. A value built by `fromCanonicalBytes` or `clone` owns its heap bytes, and `deinit`/// frees them. Equality and order assume the smallest representation, so a value written directly/// through `repr` has to keep it.pub const SignedInteger = struct {    /// The number in one of its three representations. A value set here directly has to use the    /// smallest representation that holds the number, because nothing checks it.    repr: Repr,    /// The number stored as 128 signed bits, 128 unsigned bits or heap bytes, tagged by which. Code    /// that switches on how an integer is stored reads this.    pub const Repr = union(Tier) {        /// The number when it fits in 128 signed bits.        i128: i128,        /// The number when it is above the largest 128-bit signed integer and fits in 128 unsigned        /// bits.        u128: u128,        /// The number's shortest big-endian two's-complement bytes, for a number outside both        /// 128-bit ranges. These bytes are at least 17 long.        big: []const u8,    };    /// Returns zero, stored in 128 signed bits. Code that needs a zero integer calls it.    pub fn zero() SignedInteger {        return .{ .repr = .{ .i128 = 0 } };    }    /// Returns `v`, stored in 128 signed bits. Readers and constructors call it for any integer    /// that fits in 128 signed bits.    pub fn fromI128(v: i128) SignedInteger {        return .{ .repr = .{ .i128 = v } };    }    /// Returns `v`, stored in 128 signed bits when it fits there and in 128 unsigned bits    /// otherwise. Readers call it for a non-negative integer read as 128 unsigned bits.    pub fn fromU128(v: u128) SignedInteger {        const limit: u128 = @intCast(std.math.maxInt(i128));        if (v <= limit) {            return .{ .repr = .{ .i128 = @intCast(v) } };        }        return .{ .repr = .{ .u128 = v } };    }    /// Reads a number from its shortest big-endian two's-complement bytes. The binary and text    /// readers call it for integers too large for fixed-width parsing. Empty bytes are zero, up to    /// 16 bytes give a 128-bit signed number, and 17 bytes of a number that fits 128 unsigned bits    /// give a 128-bit unsigned number. Numbers with more bytes keep a copy of the bytes from    /// `allocator`, which `deinit` frees. The call returns `error.NonCanonicalInteger` for any    /// spelling longer than the shortest.    pub fn fromCanonicalBytes(allocator: Allocator, bytes: []const u8) !SignedInteger {        if (!isCanonicalBytes(bytes)) return DecodeError.NonCanonicalInteger;        if (bytes.len == 0) return zero();        if (bytes.len <= 16) return fromI128(decodeI128Bytes(bytes));        if (bytes.len == 17 and bytes[0] == 0x00 and (bytes[1] & 0x80) != 0) {            return .{ .repr = .{ .u128 = decode16BytesAsU128(bytes[1..]) } };        }        return .{ .repr = .{ .big = try allocator.dupe(u8, bytes) } };    }    /// Frees the heap bytes of a number too large for 128 bits, and does nothing for any other    /// number. `Value.deinit` and `freeValueDeep` call it for every integer they free. The value is    /// undefined afterward.    pub fn deinit(self: *SignedInteger, allocator: Allocator) void {        switch (self.repr) {            .big => |b| if (b.len != 0) allocator.free(b),            else => {},        }        self.* = undefined;    }    /// Returns a copy that owns its storage, copying the heap bytes of a large number with    /// `allocator`. `cloneValueDeep` calls it for every integer it copies. A number that fits in    /// 128 bits is copied without allocating.    pub fn clone(self: SignedInteger, allocator: Allocator) !SignedInteger {        return switch (self.repr) {            .i128 => |v| fromI128(v),            .u128 => |v| .{ .repr = .{ .u128 = v } },            .big => |b| .{ .repr = .{ .big = try allocator.dupe(u8, b) } },        };    }    /// Returns a new allocation from `allocator` holding the number's shortest big-endian    /// two's-complement bytes, which the caller frees. The binary writer calls it for the bytes of    /// each integer it writes. Zero gives an empty slice.    pub fn toCanonicalBytes(self: SignedInteger, allocator: Allocator) ![]u8 {        return switch (self.repr) {            .i128 => |v| try encodeI128(allocator, v),            .u128 => |v| try encodeU128(allocator, v),            .big => |b| try allocator.dupe(u8, b),        };    }    /// Returns the number when it is stored in 128 signed bits, and `error.OutOfRange` otherwise.    /// Code that needs the number as a Zig `i128` calls it, as the package's tests do.    pub fn toI128(self: SignedInteger) RangeError!i128 {        return switch (self.repr) {            .i128 => |v| v,            .u128, .big => RangeError.OutOfRange,        };    }    /// Returns the number when it is zero or positive and fits in 128 unsigned bits, and    /// `error.OutOfRange` otherwise. Code that needs a 128-bit unsigned integer calls it.    pub fn toU128(self: SignedInteger) RangeError!u128 {        return switch (self.repr) {            .i128 => |v| if (v < 0) RangeError.OutOfRange else @intCast(v),            .u128 => |v| v,            .big => RangeError.OutOfRange,        };    }    /// Returns the number when it fits in 64 signed bits, and `error.OutOfRange` otherwise. Code    /// that reads a field it expects to fit in 64 bits calls it for an `i64`.    pub fn toI64(self: SignedInteger) RangeError!i64 {        const v = try self.toI128();        if (v < std.math.minInt(i64) or v > std.math.maxInt(i64)) return RangeError.OutOfRange;        return @intCast(v);    }    /// Returns the number clamped to the 64-bit signed range: the largest `i64` for any number    /// above it and the smallest for any number below. The JSON writer calls it to print an integer    /// too large for 128 bits. The call never fails.    pub fn toI64Lossy(self: SignedInteger) i64 {        return switch (self.repr) {            .i128 => |v| blk: {                if (v > std.math.maxInt(i64)) break :blk std.math.maxInt(i64);                if (v < std.math.minInt(i64)) break :blk std.math.minInt(i64);                break :blk @intCast(v);            },            .u128 => std.math.maxInt(i64),            .big => |b| if (b.len > 0 and (b[0] & 0x80) != 0) std.math.minInt(i64) else std.math.maxInt(i64),        };    }    /// Returns the number when it is zero or positive and fits in 64 unsigned bits, and    /// `error.OutOfRange` otherwise. Code that reads a count or a size calls it for a `u64`.    pub fn toU64(self: SignedInteger) RangeError!u64 {        const v = try self.toU128();        if (v > std.math.maxInt(u64)) return RangeError.OutOfRange;        return @intCast(v);    }    /// Returns whether the number is zero. Code that tests for zero calls it. Only a zero stored in    /// 128 signed bits counts, so a zero written directly into another representation reads as    /// nonzero.    pub fn isZero(self: SignedInteger) bool {        return switch (self.repr) {            .i128 => |v| v == 0,            .u128, .big => false,        };    }    /// Returns whether the number is below zero. Code that needs the sign calls it.    pub fn isNegative(self: SignedInteger) bool {        return switch (self.repr) {            .i128 => |v| v < 0,            .u128 => false,            .big => |b| b.len > 0 and (b[0] & 0x80) != 0,        };    }    /// Returns whether two integers are equal. `Value.eql` calls it for two integers. Integers in    /// different representations are never equal, so the call is exact only when both use the    /// smallest representation that holds their number.    pub fn eql(a: SignedInteger, b: SignedInteger) bool {        return switch (a.repr) {            .i128 => |av| switch (b.repr) {                .i128 => |bv| av == bv,                else => false,            },            .u128 => |av| switch (b.repr) {                .u128 => |bv| av == bv,                else => false,            },            .big => |av| switch (b.repr) {                .big => |bv| std.mem.eql(u8, av, bv),                else => false,            },        };    }    /// Returns the numeric order of two integers. `Value.compare` calls it for two integers. Large    /// numbers compare by sign, then by byte length, then byte by byte. The order across    /// representations is exact only when both integers use the smallest representation that holds    /// their number.    pub fn order(a: SignedInteger, b: SignedInteger) std.math.Order {        return switch (a.repr) {            .i128 => |av| switch (b.repr) {                .i128 => |bv| std.math.order(av, bv),                .u128 => .lt,                .big => |bv| if (bigIsNegative(bv)) .gt else .lt,            },            .u128 => |av| switch (b.repr) {                .i128 => .gt,                .u128 => |bv| std.math.order(av, bv),                .big => |bv| if (bigIsNegative(bv)) .gt else .lt,            },            .big => |av| switch (b.repr) {                .i128, .u128 => if (bigIsNegative(av)) .lt else .gt,                .big => |bv| compareBig(av, bv),            },        };    }    /// Returns whether `bytes` are the shortest big-endian two's-complement spelling of their    /// number. The binary reader calls it before reading an integer, so a longer spelling is    /// rejected. Empty bytes spell zero. A lone `0x00` byte, a leading `0x00` before a byte whose    /// top bit is clear, and a leading `0xff` before a byte whose top bit is set are all longer    /// than needed.    pub fn isCanonicalBytes(bytes: []const u8) bool {        if (bytes.len == 0) return true;        if (bytes.len == 1) return bytes[0] != 0x00;        const first = bytes[0];        const second = bytes[1];        if (first == 0x00 and (second & 0x80) == 0) return false;        if (first == 0xff and (second & 0x80) != 0) return false;        return true;    }};

Source: lib/preserves/src/root.zig:128

zig
pub const SignedInteger = integer_mod.SignedInteger;
Called byCallsCowSignedIntegerintoOwnedSignedIntegerfromI128SignedIntegerclone
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callsCowSignedIntegerdeinitSignedIntegerdeinit
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallstest sourcelib.preserves.src.integertest: SignedInteger U128 tier above i...test sourcelib.preserves.src.integertest: SignedInteger big tier holds by...test sourcelib.preserves.src.integertest: SignedInteger rejects non-canon...test sourcelib.preserves.src.integertest: SignedInteger round-trip I128 f...test sourcelib.preserves.src.validation.test.roundtriptest: packed round-trip: integer tier...SignedIntegerfromI128SignedIntegerisCanonicalBytesSignedIntegerzeroprivate sourcelib.preserves.src.integerdecode16BytesAsU128private sourcelib.preserves.src.integerdecodeI128BytesSignedIntegerfromCanonicalBytes
Static calls · unresolved targets: 1 · external targets: 1.
Called byCallsNo direct callsSignedIntegercloneSignedIntegerfromCanonicalBytestest sourcelib.preserves.src.integer.test_SignedIntegertoI64Lossy saturates out-of-range tie...test sourcelib.preserves.src.integertest: SignedInteger cross-tier orderi...test sourcelib.preserves.src.integertest: SignedInteger round-trip I128 f...+5 moreSignedIntegerfromI128
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.preserves.src.integer.test_SignedIntegertoI64Lossy saturates out-of-range tie...test sourcelib.preserves.src.integertest: SignedInteger U128 tier above i...test sourcelib.preserves.src.integertest: SignedInteger cross-tier orderi...test sourcelib.preserves.src.jsontest: toJsonString: nested dictionari...valueValueSignedIntegerfromU128
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsSignedIntegerfromCanonicalBytesSignedIntegerisCanonicalBytes
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallstest sourcelib.preserves.src.integertest: SignedInteger cross-tier orderi...private sourcelib.preserves.src.integerbigIsNegativeprivate sourcelib.preserves.src.integercompareBigSignedIntegerorder
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.preserves.src.integerencodeI128private sourcelib.preserves.src.integerencodeU128SignedIntegertoCanonicalBytes
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callsSignedIntegertoI64SignedIntegertoI128
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersSignedIntegertoI128SignedIntegertoI64
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsSignedIntegertoU64SignedIntegertoU128
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersSignedIntegertoU128SignedIntegertoU64
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsSignedIntegerfromCanonicalBytesSignedIntegerzero
Static calls · unresolved targets: 0 · external targets: 0.

Also reachable as

atom.SignedInteger, json.SignedInteger, value.SignedInteger.

Complete caller list for SignedInteger.fromI128

10 direct callers.

Audit

Definitions19
Public names95
Members4
Version26.7.0
Revisiondaab053ee433