ona/src/core/unicode.zig

85 lines
2.3 KiB
Zig
Raw Normal View History

2022-10-30 22:07:36 +00:00
const io = @import("./io.zig");
const math = @import("./math.zig");
///
/// [PrintError.WriteFailure] occurs when the underlying [io.Writer] implementation failed to write
/// the entirety of a the requested print operation.
///
pub const PrintError = error {
WriteFailure,
};
///
/// Number formatting modes supported by [printInt].
///
pub const Radix = enum {
binary,
tinary,
quaternary,
quinary,
senary,
septenary,
octal,
nonary,
decimal,
undecimal,
duodecimal,
tridecimal,
tetradecimal,
pentadecimal,
hexadecimal,
};
///
/// Writes `value` as a ASCII / UTF-8 encoded integer to `writer`, returning `true` if the full
/// sequence was successfully written, otherwise `false`.
///
/// The `radix` argument identifies which base system to format `value` as.
///
pub fn printInt(writer: io.Writer, radix: Radix, value: anytype) PrintError!void {
const Int = @TypeOf(value);
switch (@typeInfo(Int)) {
.Int => |int_info| {
if (value == 0) return writer.apply("0");
const base = @enumToInt(radix);
const is_signed = (int_info.signedness == .signed);
var buffer = [_]u8{0} ** (math.ceil(math.log(math.
maxInt(Int), base)) + @boolToInt(is_signed));
var buffer_count: usize = 0;
var n1 = value;
if (is_signed and (value < 0)) {
// Negative value.
n1 = -value;
buffer[0] = '-';
buffer_count += 1;
}
while (n1 != 0) {
buffer[buffer_count] = @intCast(u8, (n1 % base) + '0');
n1 = (n1 / base);
buffer_count += 1;
}
for (buffer[0 .. (buffer_count / 2)]) |_, i|
io.swap(u8, &buffer[i], &buffer[buffer_count - i - 1]);
if (writer.call(buffer[0 .. buffer_count]) != buffer_count) return error.WriteFailure;
},
// Cast comptime int into known-size integer and try again.
.ComptimeInt => return printInt(writer, radix,
@intCast(math.IntFittingRange(value, value), value)),
else => @compileError("`value` must be of type int or comptime_int"),
}
}
test "Print 64-bit signed integer" {
// TODO: implement.
}