const std = @import("std"); const io = @import("./io.zig"); const math = @import("./math.zig"); /// /// Errors that may occur during utf8-encoded int parsing. /// pub const IntParseError = math.CheckedArithmeticError || ParseError; /// /// Optional rules for int parsing logic to consider during parsing. /// pub const IntParseOptions = struct { delimiter: []const u8 = "", }; /// /// Errors that may occur during any kind of utf8-encoded parsing. /// pub const ParseError = error { BadSyntax, }; /// /// Errors that may occur during any kind of utf8-encoded printing. /// pub const PrintError = error { PrintFailed, PrintIncomplete, }; /// /// Attempts to parse a float value of type described by `float` from `utf8`. /// /// The function returns a [ParseError] if `utf8` does not conform to the syntax of a float. /// pub fn parse_float(comptime float: std.builtin.Type.Float, utf8: []const u8) ParseError!math.Float(float) { // "" if (utf8.len == 0) { return error.BadSyntax; } const is_negative = utf8[0] == '-'; // "-" if (is_negative and (utf8.len == 1)) { return error.BadSyntax; } const negative_offset = @boolToInt(is_negative); var has_decimal = utf8[negative_offset] == '.'; // "-." if (has_decimal and (utf8.len == 2)) { return error.BadSyntax; } const Float = math.Float(float); var result: Float = 0; var factor: Float = 1; for (utf8[0 .. negative_offset + @boolToInt(has_decimal)]) |code| switch (code) { '.' => { if (has_decimal) return error.BadSyntax; has_decimal = true; }, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => { if (has_decimal) factor /= 10.0; result = ((result * 10.0) + @intToFloat(Float, code - '0')); }, else => return error.BadSyntax, }; return result * factor; } /// /// Attempts to parse an int value of type described by `int` from `utf8`, with `options` as additional rules for the /// parsing logic to consider. /// /// The function returns a [IntParseError] if `utf8` does not conform to the syntax of a float, does not match the rules /// specified in `option`, or exceeds the maximum size of the int described by `int`. /// pub fn parse_int( comptime int: std.builtin.Type.Int, utf8: []const u8, options: IntParseOptions) IntParseError!math.Int(int) { if (utf8.len == 0) { return error.BadSyntax; } { const is_negative = utf8[0] == '-'; switch (int.signedness) { .signed => { if (is_negative and utf8.len == 1) { return error.BadSyntax; } }, .unsigned => { if (is_negative) { return error.BadSyntax; } }, } } var result = @as(math.Int(int), 0); for (0 .. utf8.len) |index| { const code = utf8[index]; switch (code) { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' => { result = try math.checked_add(try math.checked_mul(result, 10), try math.checked_sub(code, '0')); }, else => { if (options.delimiter.len == 0 or !io.equals(options.delimiter, utf8[index ..])) { return error.BadSyntax; } }, } } return result; } /// /// Attempts to print `utf8` to `writer`. /// /// The function returns [PrintError] if the write failed to complete partially or entirely. /// pub fn print(writer: io.Writer, utf8: []const u8) PrintError!void { if ((writer.invoke(utf8) orelse return error.PrintFailed) != utf8.len) { return error.PrintIncomplete; } } /// /// Attempts to print the int `value` described by `int` to `writer`. /// /// The function returns [PrintError] if the write failed to complete partially or entirely. /// pub fn print_int(comptime int: std.builtin.Type.Int, writer: io.Writer, value: math.Int(int)) PrintError!void { if (value == 0) { return try print(writer, "0"); } // TODO: Don't make this buffer arbitrarily size cause big int types WILL overflow. var buffer = [_]u8{0} ** 40; var buffer_count: usize = 0; var split_value = value; if ((int.signedness == .unsigned) and (value < 0)) { buffer[0] = '-'; buffer_count += 1; } while (split_value != 0) : (buffer_count += 1) { const radix = 10; buffer[buffer_count] = @intCast(u8, (split_value % radix) + '0'); split_value = (split_value / radix); } { const half_buffer_count = buffer_count / 2; var index: usize = 0; while (index < half_buffer_count) : (index += 1) { io.swap(u8, &buffer[index], &buffer[buffer_count - index - 1]); } } try print(writer, buffer[0 .. buffer_count]); }