Releases: sothis/bovnar
v1.1.0
Bovnar 1.1.0 — native time, opt-in and fully compatible
Spec 1.1 adds a native time family to the unit-safe format — and nothing
else changes. Every 1.0 document parses unchanged and decodes to the same
values; the new constructs are opt-in, enabled per document by a leading
#!bovnar 1.1 directive. A 1.0 reader skips the directive as a comment, and a
1.1 reader treats a directive-less document as spec 1.0.
#!bovnar 1.1
.launch = <datetime:64,tai> 2026-05-28T00:00:00Z; # epoch-aware timestamp
.created = 2026-06-15T12:00:00.5Z; # bare ISO literal → <datetime:64,unix>
.label = "caf\u{e9}"; # \u{…} / \xHH string escapes
.cell = &.matrix[0][1]; # references can index arrays
This is an additive 1.x release: per the §17 stability contract, it only
adds new constructs, appends new error codes after the previous maximum, and
adds optional reader/writer flags. No 1.0 document is invalidated — with one
reserved-prefix exception: because #!bovnar on a first-line comment is now a
version directive, a 1.0 document whose first line is a comment beginning
literally with #!bovnar followed by non-version text is now reported as a
malformed directive rather than skipped. #!bovnar was never a 1.0 convention,
so no realistic document is affected.
Install
pip install --upgrade bovnar # pure-ctypes bindings + bundled shared libraryBinary wheels are published for CPython 3.10–3.14 on Linux (x86_64,
aarch64) and macOS (arm64, x86_64); an sdist is available for other targets.
C / embedding: vendor the single-file amalgamation dist/bovnar.h +
dist/bovnar.c (C99, no dependencies), or build the library with CMake. The
build understands the highest spec it supports via bvnr_spec_version() /
BVNR_SPEC_VERSION_MAJOR·MINOR (now 1·1).
Windows: the library and CLI now build natively on 64-bit Windows with both
MinGW64 and MSVC — see Windows build support below.
What's new in 1.1
- Version directive — an optional first-line
#!bovnar <major>.<minor>
comment declaring the spec a document targets. A 1.1 reader records it
(bvnr_reader_get_declared_version, thebovnar versionCLI) and, with the
strict_versionread flag, rejects a version it does not support. - Native time family —
<datetime:width,epoch>carries a timestamp as a
signed integer count of seconds since a named epoch (unixdefault, plus
tai,gps,mjd,ntp,galileo,glonass,y2000,beidou) — distinct
from a duration (a number with a time unit). The epoch is recoverable
(bvnr_datetime_epoch_name/_mjd) and convertible to civil time via
bvn_datetime.h. In an array, datetime is its own kind and its epoch is a
dimension. - ISO-8601 datetime literals — write
YYYY-MM-DDor
YYYY-MM-DDTHH:MM:SS, with an optionalZ, a numeric±HH:MMoffset, and/or
a fractional second, instead of a raw integer. It converts to the epoch-seconds
carrier at parse time and round-trips idempotently; a bare literal infers
<datetime:64,unix>. The UTC→epoch conversion is leap-second correct
(taiapplies the IERS table); the atomic GNSS epochs reject a literal, since
they have no round-trippable civil⇄seconds inverse — use an integer carrier
there. A fractional second is preserved verbatim and re-emitted as an ISO
literal. - Richer string escapes —
\u{1–6 hex}(a Unicode scalar, UTF-8 encoded)
and\xHH(one byte), both held to the same valid-UTF-8 / no-raw-control rules
as the rest of the string grammar. - Reference array indexing — a reference path may index arrays,
&.matrix[0][1], resolved bybvn_dom_lookup(andbovnar query). - Python & numpy —
bovnar.version()/spec_version()/peek_version(),
Reader.declared_version,Quantity.epoch_name/epoch_mjd,
ValueTypeFamily.DATETIME.dumps()auto-prepends#!bovnar 1.1(and the
<datetime>annotation) only when the value tree needs it, so typed
round-trips stay lossless. The numpy bridge maps a unix-epoch datetime array
to/fromdatetime64[s]. - Python — lossless wide/decimal/fixed-point floats —
Quantitygains
.decimal()/.fraction()(the exact value from the verbatim literal) and
.stored_value()/.ieee_bits()/.fixed_point()(bit-exact materialisation of
the 16/32/64/128/256 encodings), plus afrom_numberconstructor;dumps()
acceptsDecimal/Fraction. The numpy bridge decodesfloat_dec/float_fix/
float:128+ to exactDecimalobject arrays (withfrom_numpy(float_format=)
to write them), and the arbitrary-precisionbvn_floatAPI is exposed as
bovnar.BvnFloat. - Windows build support (64-bit MinGW64 and MSVC) — the library (
bvnr.dll
plus import lib and a static archive) and thebovnarCLI now build natively
on Windows. A portability shim (src/utils/bvn_port.h) maps the fd I/O onto the
CRT and — critically for a binary format — forces binary mode on files and on
stdin/stdout/stderr so no CRLF translation can corrupt the byte stream. On MSVC
the static archive isbvnr_static.lib(the DLL import lib takesbvnr.lib);
MinGW keeps the unifiedlibbvnrnames. A newBuild & PackageCI workflow
builds both Windows toolchains and a native Linux target, smoke-tests the CLI,
and publishes the build + amalgamation artifacts. - Tooling — a
bovnar versionsubcommand; thedatetimekeyword in all five
syntax highlighters and the web playground; and a conformance suite grown to
306 cases (up from 207), adding theversionanddatetimegroups —
including the ISO-literalDTLITcases — passing in both self-test and--iut
modes.
New error codes (appended, non-breaking)
error_invalid_spec_version (42), error_unsupported_spec_version (43),
error_invalid_codepoint (44), error_invalid_datetime_literal (45),
error_datetime_literal_unsupported_epoch (46). Existing codes are unchanged.
Compatibility
- 1.0 documents are unaffected — parse unchanged, decode identically. The
1.0 freeze (grammar, type families, arrays/structs/octet-streams/references,
homogeneity rules, error-code values) still holds. - 1.1 constructs are opt-in — they require the
#!bovnar 1.1directive; a
1.1-only construct in a directive-less (spec-1.0) document is an error, exactly
as a 1.0 reader reports.
Documentation
Full docs — tutorial, specification, unit/currency reference, C and Python API,
formal EBNF grammar, FAQ, conformance protocol, and cheat sheet — are available
at https://www.bovnar.io (each also downloadable as PDF), and in the
doc/ directory. See
CHANGELOG.md for the complete change list.
License
MIT.
Bovnar 1.0.0 — first stable release
Bovnar 1.0.0 — first stable release
Unit-safe serialization for science, industry, and finance. Every value in a
.bvnr document carries its type family, bit-width, numeric base, and a
validated physical unit or currency — inline, in the same byte stream, with
no external schema. A bare 9.81 is never ambiguous, and a mismatched unit is a
parse error.
.thrust = <float:64,k~N> 7.6; # 7.6 kilonewtons
.altitude = <uint:32,m> 412000; # 412 km, explicit width + unit
.price = <float_dec:64,$USD> 19.99;
.matrix = [1, 2, 3]/[4, 5, 6]; # rectangular, homogeneous
This is the 1.0 format freeze: a document valid under spec 1.0 stays valid,
and decodes to the same values, under every 1.x release.
Install
pip install bovnar # pure-ctypes bindings + bundled shared libraryBinary wheels are published for CPython 3.10–3.14 on Linux (x86_64,
aarch64) and macOS (arm64, x86_64); an sdist is available for other targets.
C / embedding: vendor the single-file amalgamation dist/bovnar.h +
dist/bovnar.c (C99, no dependencies), or build the library with CMake.
Highlights
- Self-describing, unit-safe values — type family (
uint/sint/float/
float_fix/float_dec/utf8/bool), bit-width, numeric base, and unit all
travel with the value and are validated by the parser. - Rich unit system — 163 named physical units, SI/IEC prefixes, and compound
expressions (k~g/(m·s²)), plus 164 ISO 4217 fiat currencies and 50
cryptocurrencies with minor-unit metadata. - First-class structure — nested structs, multi-dimensional arrays with a
clean/-row syntax, references, and native binary embedding via octet streams
(no Base64). - Streaming C API and pure-ctypes Python bindings (
loads/dumpsplus
event-drivenReader/Writer), with optionalpintandnumpybridges. bovnarCLI — validate, query by path, pretty-print, convert to/from JSON,
inspect the event stream, and benchmark.- Tooling — registered media type
text/vnd.bovnar(+.bvnr), syntax
highlighters (VS Code, Sublime, Vim, Geany), and a 207-case conformance suite
with an IUT protocol for verifying third-party implementations.
Breaking changes (the 1.0 freeze — finalized before this line)
These tightened the format and cannot change within 1.x:
- Currencies require a mandatory
$sigil ($USD,$BTC), so a currency
code can never collide with a physical-unit symbol. - Special floats are bare keywords —
nan,inf,ninf(the previous
$-sigil form was removed). - Array elements must be homogeneous — same kind and dimension; sibling
sub-arrays must be rectangular. Heterogeneous/ragged data uses a struct. float_fixvalues are range-validated against the declared Q-format
(out-of-range iserror_value_out_of_range).
Stability contract (spec §17)
- Frozen at 1.0: the grammar, type families and annotations, arrays/structs/
octet-streams/references, the homogeneity rules, and the error-code values. - Additive in 1.x (non-breaking): new units/prefixes/currencies, new error
codes appended after the current maximum, and new optional reader/writer flags. - Reserved for 2.0: anything that could invalidate a 1.x document, change how
it decodes, renumber an error code, or alter the grammar.
Documentation
Full docs — tutorial, specification, unit/currency reference, C and Python API,
formal EBNF grammar, FAQ, conformance protocol, and cheat sheet — are available
at https://www.bovnar.io (each also downloadable as PDF), and in the
doc/ directory.
License
MIT.