1
0
Fork
You've already forked unitz
0
For when you don't want your probe crashing in Mars' atmosphere https://agagniere.github.io/unitz/
  • Zig 100%
Find a file
2026年04月30日 09:03:26 +02:00
.github/workflows (CI: build with Zig master on macos) 2026年04月28日 01:19:14 +02:00
samples Update error samples 2026年04月30日 00:16:18 +02:00
src Add more documentation 2026年04月30日 09:03:26 +02:00
.gitignore Update for Zig 0.16.0 2026年04月28日 01:15:15 +02:00
build.zig (bump comath) 2025年08月10日 20:34:10 +02:00
build.zig.zon Update for Zig 0.16.0 2026年04月28日 01:15:15 +02:00
LICENSE Initial commit 2024年11月19日 22:01:42 +01:00
README.md Stop exposing evalUnit and evalQuantity publicly 2026年04月30日 00:16:18 +02:00

Unitz

Achieve compile-time unit correctness and avoid runtime surprises.

Status

Architecture \ OS Linux MacOS
x86_64
arm64
Branch name Zig version
master 0.16.x, master
zig-0.15 0.14.x, 0.15.x
zig-0.13 0.13.x

Showcase

Use units as types, to document your functions, and convert to units of the same dimension:

constunits=@import("unitz").quantities(f32);constm=units.meter;consts=units.second;constkt=units.knot;const@"km/h"=units.eval("km / h",.{});fnaircraft_speed(distance:m,duration:s)kt{constspeed=distance.div(duration);// value is in m/sconstresult:kt=.from(speed);// convert to target unitstd.debug.print("Speed: {} m/s = {} kt = {} km/h\n",.{speed.val(),result.val(),speed.toVal(@"km/h"),});returnresult;}

A compilation error occurs when trying to perform an invalid conversion:

constJ=units.joule;consthp=units.imperial_horsepower;constengine_power:hp=.init(130);constenergy=engine_power.to(J);

Will result in the compilation error:

src/quantity.zig:84:60:error:Unitsareonlyinterconvertibleiftheymeasurethesamekindofdimensioncomptimeif(!unit_from.isCompatible(unit_to))@compileError("Units are only interconvertible if they measure the same kind of dimension");^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~foo.zig:8:35:note:calledinlinehereconstenergy=engine_power.to(J);~~~~~~~~~~~~~~~^~~

No conversion is done implicitly, the value stored in memory is exactly the one provided to the constructor.

Defining your own units

This library does not provide all variations of standard units: meter and hour are provided, but kilometer and kilometer per hour is not. Instead, you can define any unit you want from its definition, using prefixes if needed:

constnanosecond=units.eval("ns",.{});const@"kg/m3"=units.eval("kg / m^3",.{});constkilowatthour=units.eval("kW * h",.{});constCal=units.eval("kcal",.{});// large calorie

Simple example

conststd=@import("std");constunitz=@import("unitz");constq=unitz.quantities(f32);constm=q.meter;constkg=q.kilogram;constlb=q.pound;constcm=q.eval("cm",.{});const@"kg/m2"=q.eval("kg / m^2",.{});fnbody_mass_index(height:m,weight:kg)@"kg/m2"{returnweight.div(height.pow(2));}pubfnmain()void{constheight:cm=.init(162);constweight:lb=.init(124);constbmi=body_mass_index(height.to(m),weight.to(kg));std.debug.print("BMI: {}",.{bmi.val()});}

Advanced example

We redefine slug and pound-force to show how it can be done

constu=@import("unitz").quantities(f32);constslug=u.eval("32.174_049 * lb",.{});constlbf=u.eval("ft * my_slug / s^2",.{.my_slug=slug.unit});const@"lbf.s"=u.eval("my_lbf * s",.{.my_lbf=lbf.unit});const@"N.s"=u.eval("N * s",.{});const@"μs"=u.eval("us",.{});fncompute_impulse(force:lbf,delta:@"μs")@"lbf.s"{return.from(force.mul(delta));// The .from converts to the target unit// return force.mul(delta).to(@"lbf.s"); // equivalent}fncompute_trajectory(impulse:@"N.s")void{// ...}pubfnmain()void{constforce=lbf.init(123.0);constdelta=@"μs".init(45.0);compute_trajectory(compute_impulse(force,delta));// compilation error !// Adding .to(@"N.s") will fix it:// compute_trajectory(compute_impulse(force, delta).to(@"N.s"));// compute_trajectory(.from(compute_impulse(force, delta))); // Also possible}

And just like that, you can avoid crashing into the atmosphere

Use in your project

Add the dependency in your build.zig.zon by running the following command:

zig fetch --save git+https://github.com/agagniere/unitz#master

Add it to your exe in your build.zig:

exe.root_module.addImport("unitz",b.dependency("unitz",.{.target=target,.optimize=optimize}).module("unitz"));

Then you can import it from your code:

constunitz=@import("unitz");

Generate documentation

zig build docs
# Then serve locally, for example:
python -m http.server 8000 -d zig-out/docs
open "http://localhost:8000"

Bump dependencies

zig fetch --save git+https://codeberg.org/InKryption/comath#main