capnp-json
A Cap'n Proto JSON codec for capnp-rust,
implementing the codec defined in
json.capnp.
It encodes a Cap'n Proto message to JSON, and decodes JSON into a Cap'n Proto message, using the schema's runtime type information. The wire format is compatible with the C++ JSON codec that ships with Cap'n Proto.
Compatibility
Compatibile with capnp: 0.27.
capnp-json is only compatible with a particular minor release of capnp due
to breaking changes and schema updates upstream.
Usage
Add the dependency:
[]
= "0.27"
= "0.3.0"
Encoding a message reader to a JSON string, and decoding JSON back into a message builder:
use message;
use ;
#
If your schema uses any of the JSON annotations ($Json.name, $Json.flatten,
$Json.discriminator, $Json.base64, $Json.hex), import them by adding the
following to your build.rs, so that the generated code links against the
annotations defined in this crate:
And in your schema:
using Json = import "/capnp/compat/json.capnp";
struct MyStruct {
myField @0 :Text $Json.name("my_field");
}
Supported features
- All primitive Cap'n Proto types, including
Int64/UInt64encoded as JSON strings (matching the C++ codec). Integer fields andDatabytes are range-checked on decode, so an out-of-range or fractional number is an error rather than being silently clamped; floats and enum ordinals are not checked, matching C++. Float32/Float64NaN,Infinity, and-Infinityencoded as JSON strings.- Structs, lists, lists of lists, and lists of structs.
- Enums, encoded by name (or by ordinal if the enumerant is missing).
- Named and unnamed unions.
- Annotations:
$Json.name— rename a field, enumerant, method, group, or union member in the JSON representation.$Json.flatten— flatten a struct, group, or union into its parent. Flattening must terminate: a schema that flattens a field of its own type, directly or through a chain, cannot be represented as JSON. Callcapnp_json::validate_schema::<MyStruct::Owned>()once (from a test, or at startup) to get the same "cyclic JSON flattening detected" verdict the C++ codec gives. Encoding and decoding skip the check, since a schema is compile-time data; a cyclic schema is still rejected when decoded, just via the recursion limit.$Json.discriminator— encode a union's variant as a sibling discriminator field.$Json.base64/$Json.hex— encodeDatafields as Base64 or hex strings instead of arrays of bytes.
- Custom per-field and per-type encodings, via the
FieldCodectrait andCodec::with_field_override/with_type_override. This is the equivalent of the C++ codec'sHandlerAPI, and is what makesAnyPointerand interface fields encodable. - Named codecs selected from the schema with this crate's own
$Rust.codec("name")annotation (seerust-json.capnp), registered withCodec::with_named_codec.
Not yet supported
- The
Value/Call/rawextensions fromjson.capnp. AnyPointerand interface fields, unless aFieldCodecis registered for them.- Pretty-printed output.
Known divergences from the C++ codec
These matter mainly when decoding input you do not control; see the crate documentation for the full list.
\uXXXXsurrogate pairs are combined into the character they denote, and unpaired surrogates are rejected. C++ decodes each escape separately and produces WTF-8, which is not valid UTF-8. Round-tripping is unaffected: the C++ encoder writes non-BMP characters as literal UTF-8, never as escapes.- Only
Int64/UInt64accept the string form of an integer when decoding; C++ accepts it for every integer width.
Note that a JSON null for a pointer-typed field is accepted as "field absent",
matching the C++ v2 branch. That is not in any v1 C++ release, so released
versions reject it — this crate is the more permissive of the two.