moonip
00 · header

An IPv4 header, to scale · 20 bytes · one column per bit

Addresses, blocks,
and the bits
between them.

moonip reads the text forms of RFC 4291 and gives every address back in the canonical shape of RFC 5952. It works out the block an address sits in, splits blocks down, joins ranges back up, and places an address in one of the IANA special-purpose registries. Nothing here opens a socket: the two fields above are the whole job.

families
IPv4 · IPv6, zones included
text
RFC 4291 in, RFC 5952 out
blocks
classless, /0 to /32 and /0 to /128
targets
wasm · wasm-gc · js · native
two fieldsof thirteen are this package's business. Hover one to see which.

fig. 1 Field widths are bit widths read off the header, not a drawing decision: four columns for a nibble, eight for an octet, thirty-two for an address. The two shaded rows are Addr; the hatched fields belong to a layer that owns them.

01 · values

three types

Everything else is a function over these.

typewidthmade bywhat it is
Addr 32 · 128 parse decode v4 v6 One address, plus the zone a scoped IPv6 address carries. Immutable, ordered, hashable.
Prefix addr + 0…32
addr + 0…128
parse new A block. Keeps the address it was written with, so one value can stand for an interface.
AddrPort addr + 16 parse new One end of a conversation: four dotted fields with a port, or a bracketed IPv6 with one.

fig. 2 The width column is the field width the value models, not a structure size.

02 · probe

the library, running here

Paste one.

…

fe80::1%eth0 · ::ffff:192.0.2.1 · 10.1.2.3 · 2001:4860:4860::8888

fig. 3 Not a mock-up: this is src/examples/browser compiled to JavaScript and imported by the page. Every string above is the library's answer, and the bit row is drawn from the encoded bytes.

03 · install

two lines

Add it, then read a block.

moon add moonbitstack/moonip
main.mbtmoonbit
fn main raise {
  let block = @moonip.Prefix::parse("192.0.2.0/24")
  println(block.netmask())                                  // 255.255.255.0
  println(block.contains(@moonip.Addr::parse("192.0.2.7")))  // true
  println(block.hosts().next())                             // Some(192.0.2.1)
}
Strict on purpose. A leading zero in an IPv4 field, a dotted netmask in place of a mask length, or a zone inside a prefix is refused rather than guessed at. Every refusal says what kind of mistake it was and where it started.

The guide walks the whole surface in ten steps; the reference is generated from the interface the compiler emits; the explorer takes blocks apart.

top top