A small Zig library for parsing and formatting IEEE 802 MAC addresses.
  • Zig 91.7%
  • Nix 8.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-23 14:34:21 -05:00
LICENSES first 2026-08-23 14:08:59 -05:00
src add a README and clean up unneeded files 2026-08-23 14:20:44 -05:00
.gitignore first 2026-08-23 14:08:59 -05:00
build.zig add a README and clean up unneeded files 2026-08-23 14:20:44 -05:00
build.zig.zon add a README and clean up unneeded files 2026-08-23 14:20:44 -05:00
flake.lock first 2026-08-23 14:08:59 -05:00
flake.nix first 2026-08-23 14:08:59 -05:00
README.md Add section to the readme about using radicle. 2026-08-23 14:34:21 -05:00
REUSE.toml first 2026-08-23 14:08:59 -05:00

zig-macaddress

A small Zig library for parsing and formatting IEEE 802 MAC addresses.

A MacAddress is a single u48, so it is cheap to copy, compare, sort, and store. Parsing accepts the common textual conventions; formatting can emit any of them in either case.

Requires Zig 0.16.0 or later.

Installation

Fetch the package and save it to your build.zig.zon:

zig fetch --save git+https://codeberg.org/jcollie/zig-macaddress.git

Then wire the module into your build:

const macaddress_dep = b.dependency("macaddress", .{
    .target = target,
    .optimize = optimize,
});

exe.root_module.addImport("macaddress", macaddress_dep.module("macaddress"));

Usage

const std = @import("std");
const macaddress = @import("macaddress");
const MacAddress = macaddress.MacAddress;

pub fn main() !void {
    const mac: MacAddress = try .parse("00:11:22:33:44:55");

    // mac.data is a plain u48
    std.debug.assert(mac.data == 0x001122334455);

    var buffer: [17]u8 = undefined;

    // Default formatting: upper case, colon separated.
    var w: std.Io.Writer = .fixed(&buffer);
    try w.print("{f}", .{mac});
    std.debug.assert(std.mem.eql(u8, w.buffered(), "00:11:22:33:44:55"));

    // Or pick a style and case explicitly.
    var w2: std.Io.Writer = .fixed(&buffer);
    try mac.formatOptions(&w2, .{ .case = .lower, .style = .cisco });
    std.debug.assert(std.mem.eql(u8, w2.buffered(), "0011.2233.4455"));
}

Parsing

MacAddress.parse (also re-exported as macaddress.parse) trims surrounding whitespace and then accepts exactly these layouts:

Input Length
001122334455 12
0011.2233.4455 14
00 11 22 33 44 55 17
00:11:22:33:44:55 17
00-11-22-33-44-55 17

Hex digits may be upper or lower case, and the two cases may be mixed. Anything else — a wrong length, a stray character, a separator in the wrong place, or a separator that does not match the layout — returns error.NotAMacAddress. The separators in a 17-character address are checked individually, so mixed forms such as 00:11-22 33:44-55 are also accepted.

Formatting

format implements the standard std.fmt interface, so a MacAddress can be printed with {f}. It uses the defaults: upper case, colon separated.

For anything else, call formatOptions with a FormatOptions:

pub const FormatOptions = struct {
    case: Case = .upper,   // .upper, .lower
    style: Style = .colons,
};
Style Output
.compact 001122334455
.cisco 0011.2233.4455
.spaces 00 11 22 33 44 55
.colons 00:11:22:33:44:55
.hyphen, .dash, .minus 00-11-22-33-44-55

.hyphen, .dash, and .minus are three names for the same output; pick whichever reads best where you use it.

Every style produces at most 17 bytes, so a [17]u8 is always a large enough buffer.

Checking out the source with Radicle

This repository is published on Radicle, a peer-to-peer code forge built on git. Its Repository ID (RID) is:

rad:z3tH7LKeAUZWLmjbkkquzDxZ4Zjam

If you do not have Radicle yet, install it, create an identity, and start your node:

curl -sSf https://radicle.dev/install | sh
rad auth
rad node start

Then clone the repository:

rad clone rad:z3tH7LKeAUZWLmjbkkquzDxZ4Zjam

rad clone consults your node's routing table to find seeds that carry the repository, and drops the working copy into a zig-macaddress directory. Pass a target path as a second argument to put it somewhere else. If your node has not discovered a seed yet, name one directly with --seed <NID>.

The result is an ordinary git working copy on the main branch, with a rad remote wired up, so everyday work is just git. To pull in changes published since your clone:

rad sync --fetch
git pull rad main

Building and testing

This package is a library only — it builds no executable, so test is the one interesting step:

zig build test

It has no dependencies of its own beyond the standard library.

A Nix flake provides a development shell with the pinned Zig toolchain plus reuse and pinact:

nix develop

License

MIT, except where noted otherwise. This repository follows the REUSE specification: every file carries its own SPDX headers, and the full license texts live in LICENSES/.