Every base encoding, one shape: base2 through base85, bech32 and multibase for MoonBit.
let data = b"moonbase"
let pem = "bW9vbmJhc2U=\n" // a PEM body, newline and all
assert_eq(@base64.encode(data[:]), "bW9vbmJhc2U=")
assert_eq(@base64.encode(data[:], kind=@base64.Url, padding=false), "bW9vbmJhc2U")
assert_eq(@base64.encode_bytes(data[:]), b"bW9vbmJhc2U=") // the ASCII bytes
assert_eq(@base64.decode("bW9vbmJhc2U="), data)
assert_eq(@base64.decode_lossy(pem), data)moon add moonbitstack/moonbase// moon.pkg
import {
"moonbitstack/moonbase/base64",
}| Face | Signature | For |
|---|---|---|
| encode | (BytesView, …) -> String | the ordinary case |
| encode_bytes | (BytesView, …) -> Bytes | wire formats that hold bytes — an HTTP header, a gRPC metadata value — with no round trip through String |
| decode | (StringView, …) -> Bytes raise Malformed | input you want checked |
| decode_bytes | (BytesView, …) -> Bytes raise Malformed | the same, for callers who never had a string |
| decode_lossy | (StringView, …) -> Bytes | a PEM body full of newlines, a fingerprint full of colons |
assert_eq(@base32.encode(data[:], kind=@base32.Hex), "DLNMURJ2C5PMA===")
assert_eq(@base32.encode(data[:], kind=@base32.Crockford), "DNQPYVK2C5SPA")
assert_eq(@base16.encode(data[:], kind=@base16.Upper), "6D6F6F6E62617365")
assert_eq(@base64.encode(data[:], padding=false), "bW9vbmJhc2U")
assert_eq(@base85.encode(b"\x00\xff\x01\xfe"[:], kind=@base85.Z85), "0ri90")assert_eq(@base64.decode("Zg==", padding=true, strict=true), b"f")
let stray = try {
ignore(@base64.decode("Zg==", padding=false))
"decoded"
} catch {
@moonbase.Padding(at~) => "padding at " + at.to_string()
_ => "another failure"
}
assert_eq(stray, "padding at 2")assert_eq(@base64.decode("bW9v\nbmJh\nc2U=", whitespace=true), data)let sink = @base64.sink()
sink.write(b"moon"[:])
sink.write(b"base"[:])
assert_eq(sink.finish(), "bW9vbmJhc2U=")
let source = @base64.source()
source.write("bW9vbm")
assert_eq(source.drain(), b"moon") // six characters are four bytes and four bits
source.write("Jhc2U=")
assert_eq(source.finish(), b"base")assert_eq(@base36.encode_int(123456789), "21i3v9")
assert_eq(@base62.encode_int(123456789), "8M0kX")
assert_eq(@base36.decode_int("21i3v9"), 123456789UL)let hex = @moonbase.Alphabet::of("0123456789abcdef")
assert_eq(@moonbase.encode_big(@bigint.BigInt::from_int(123456789), hex), "75bcd15")
assert_eq(@moonbase.decode_big("75bcd15", hex), @bigint.BigInt::from_int(123456789))let failure = try {
ignore(@base64.decode("Zm*vYg=="))
"decoded"
} catch {
@moonbase.Bad(at~, char~) => "bad " + char.to_string() + " at " + at.to_string()
@moonbase.Truncated(at~) => "truncated at " + at.to_string()
@moonbase.Padding(at~) => "padding at " + at.to_string()
@moonbase.Checksum(at~) => "checksum at " + at.to_string()
}
assert_eq(failure, "bad * at 2")let outcome = try Ok(@base64.decode("Zm*vYg==")) catch { failure => Err(failure) }
assert_eq(outcome is Err(_), true)let crockford = @moonbase.Alphabet::new("0123456789ABCDEFGHJKMNPQRSTVWXYZ")
assert_eq(@moonbase.encode(data[:], crockford), "6TVVFDSH62WV5")assert_eq(@multibase.encode(data[:], base=@multibase.Base58Btc), "zKJfFLz7PRba")
assert_eq(@multibase.detect("zKJfFLz7PRba"), Some(@multibase.Base58Btc))
assert_eq(@multibase.decode("zKJfFLz7PRba"), data)assert_eq(@bech32.encode("moonbase", data[:]), "moonbase1d4hk7mnzv9ek2s84pra")
assert_eq(
@bech32.encode("moonbase", data[:], kind=@bech32.Bech32m),
"moonbase1d4hk7mnzv9ek29m9dxl",
)
assert_eq(@bech32.decode_words("moonbase1d4hk7mnzv9ek2s84pra").hrp, "moonbase")| Package | Specification | Notes |
|---|---|---|
| base2 | multibase 0 | one bit a character; eight characters a byte |
| base8 | multibase 7 | three bits a character — a bit packing, not an octal of a number |
| base10 | multibase 9 | the bytes as one decimal integer, so a leading zero byte stays a leading 0 |
| base16 | RFC 4648 §8 | byte-aligned, so leading zeros survive; encode_colons writes fingerprints |
| base32 | RFC 4648 §6, §7 | kind=Hex keeps byte order under sorting; Crockford and Z for people |
| base36 | multibase k / K | numbers and identifiers |
| base45 | RFC 9285 | two bytes in three characters a QR code's alphanumeric mode can hold; no padding |
| base58 | multibase z | Flickr and Ripple alphabets, plus encode_check / decode_check |
| base62 | — | digits, upper, lower; short identifiers |
| base64 | RFC 4648 §4, §5 | kind=Url for tokens and file names; decode_any reads either alphabet |
| base85 | Adobe, ZeroMQ RFC 32, RFC 1924 | kind=Ascii85, kind=Z85, kind=Ipv6 — four bytes in five characters, three ways |
| bech32 | BIP 173, BIP 350 | a human-readable prefix, five-bit groups and a BCH checksum; kind=Bech32m for version 1 and up |
| multibase | multiformats | one prefix character, from 0 for base2 to a rocket for base256emoji |
moon run src/examples/minimal --target wasm-gc
moon run src/examples/tour --target wasm-gc
moon run src/examples/integration --target wasm-gcpub struct Sink {
// private fields
}let sink = @base64.sink()
sink.write(b"foo"[:])
sink.write(b"bar"[:])
sink.finish() // "Zm9vYmFy"pub struct Source {
// private fields
}Install
Download zipEvery base encoding, one shape: base2 through base85, bech32 and multibase for MoonBit.