std/binary
Fixed-width integer and float codecs over a byte buffer — the encoding/binary / byteorder / Buffer.readUInt32LE layer.
from "std/binary" import { Bytes }A Milo string is an owned byte buffer, and it is what file-format code carries its bytes in, so reads take &string plus a byte offset and writes append to a &mut string.
Reads return Option
A read yields Option.None when fewer than the needed bytes remain at the offset, or when the offset is negative. Nothing aborts, and nothing comes back as a plausible zero.
That is deliberate. src[i] is an index — a claim by you that the position is valid, and a bad claim is a bug worth trapping on. A decode at an offset that came out of the data being decoded is the opposite situation: the input is untrusted, and truncation is an ordinary thing for a file or a network frame to be. Option.None is what lets a parser answer a truncated input with a parse error instead of dying, and — unlike a zero-filled read — it can't be mistaken for a value that was really there.
// a parser turns the None into its own error, once, in a helper
fn le32(src: &string, p: i64): Result<i64, string> {
let Option.Some(v) = Bytes.readU32Le(src, p) else {
return Result.Err("truncated archive")
}
return Result.Ok(v as i64)
}Reading
Bytes.readU8 / readI8, and Le/Be pairs for every wider type:
fn Bytes.readU16Le(src: &string, off: i64): Option<u16> // also Be, and I16
fn Bytes.readU32Le(src: &string, off: i64): Option<u32> // also Be, and I32
fn Bytes.readU64Le(src: &string, off: i64): Option<u64> // also Be, and I64
fn Bytes.readF32Le(src: &string, off: i64): Option<f32> // also Be
fn Bytes.readF64Le(src: &string, off: i64): Option<f64> // also BeThe signed forms are the two's-complement reinterpretation of the same bytes, so readI16Be over ff ff is -1, not 65535.
let hdr = readFile("frame.bin")?
let magic = Bytes.readU32Be(hdr, 0)
let temp = Bytes.readI16Le(hdr, 8) // -40 stays -40Bytes.has(src, off, n) answers the bounds question directly when you want to check once and then read several fields.
Writing
Writes append and cannot fail, so they return void:
var out = ""
Bytes.writeU32Be(out, body.len as u32) // body.len is i64 — the cast is required
Bytes.writeI16Le(out, -40) // a literal adopts the parameter's type
Bytes.writeF64Le(out, 1.5)A literal needs no cast: it takes the width from the parameter it is passed to. A value of another width does, and that as u32 is where one too large for the field gets truncated — spelling it at the call site is what keeps the truncation visible.
Float bits
Bytes.f64ToBits / f64FromBits (and the f32 pair) expose the raw IEEE-754 bit pattern. as between a float and an integer converts the value; these convert the representation, which is what the readF*/writeF* pairs are built on.
print(Bytes.f64ToBits(1.5)) // 4609434218613702656