Parsing and Encoding
const std = @import("std");
const expect = std.testing.expect;
const expectError = std.testing.expectError;
const expectEqualStrings = std.testing.expectEqualStrings;
test "parseInt" {
try expect(try std.fmt.parseInt(i32, "-42", 10) == -42);
// Base 0 reads the prefix like a Zig literal: 0x, 0o, 0b, or decimal.
try expect(try std.fmt.parseInt(u32, "0xff", 0) == 255);
try expect(try std.fmt.parseInt(u32, "0b1010", 0) == 10);
// Underscore separators are accepted, like Zig literals.
try expect(try std.fmt.parseInt(u32, "1_000_000", 10) == 1_000_000);
}
test "parse failures are errors, not zeros" {
try expectError(error.InvalidCharacter, std.fmt.parseInt(u8, "12a", 10));
// The target type bounds the parse: 300 does not fit in a u8.
try expectError(error.Overflow, std.fmt.parseInt(u8, "300", 10));
}
test "parseFloat" {
try expect(try std.fmt.parseFloat(f64, "3.25") == 3.25);
try expect(try std.fmt.parseFloat(f64, "-1e-3") == -0.001);
try expect(std.math.isInf(try std.fmt.parseFloat(f32, "inf")));
}
test "hex" {
const bytes = [_]u8{ 0xde, 0xad, 0xbe, 0xef };
// bytesToHex returns a fixed-size array: the length is known at
// compile time from the input, so no allocator is needed.
const hex = std.fmt.bytesToHex(bytes, .lower);
try expectEqualStrings("deadbeef", &hex);
var back: [4]u8 = undefined;
_ = try std.fmt.hexToBytes(&back, "deadbeef");
try expect(std.mem.eql(u8, &back, &bytes));
}
test "base64" {
const codec = std.base64.standard;
var enc_buf: [16]u8 = undefined;
const encoded = codec.Encoder.encode(&enc_buf, "zig");
try expectEqualStrings("emln", encoded);
var dec_buf: [16]u8 = undefined;
const n = try codec.Decoder.calcSizeForSlice(encoded);
try codec.Decoder.decode(dec_buf[0..n], encoded);
try expectEqualStrings("zig", dec_buf[0..n]);
}
test "url_safe base64 for tokens and file names" {
// standard base64 emits + and /, which break URLs and paths.
const bytes = [_]u8{ 0xfb, 0xff };
var buf: [8]u8 = undefined;
try expectEqualStrings("+/8=", std.base64.standard.Encoder.encode(&buf, &bytes));
try expectEqualStrings("-_8=", std.base64.url_safe.Encoder.encode(&buf, &bytes));
}Parsing is fallible, and says so
std.fmt.parseInt returns an error union, so a bad character or an
out-of-range value is a value you handle, never a silent zero. The target
type is the bound: parseInt(u8, "300", 10) is error.Overflow because 300
does not fit. Passing base 0 reads the prefix the way a Zig literal would:
0x, 0o, 0b, or decimal, underscores allowed.
parseFloat accepts the usual decimal and scientific forms plus inf and
nan.
Hex
bytesToHex returns a fixed-size array, not a slice, because the output
length is known from the input at compile time. That means no allocator and
no failure path. hexToBytes goes the other way into a caller-provided
buffer.
base64: pick the alphabet for the destination
std.base64.standard uses + and /, which are fine in a MIME body and
wrong in a URL or a file name. std.base64.url_safe swaps them for - and
_. Both expose an Encoder and a Decoder; decoding is fallible because
the input might not be valid base64. Size the destination with
Decoder.calcSizeForSlice before decoding.
| Codec | Emits | Use for |
|---|---|---|
standard | A-Za-z0-9+/ | MIME, email, data URIs |
url_safe | A-Za-z0-9-_ | URLs, file names, tokens |
*_no_pad | above, no = | fixed-width IDs |