Expand description
Rust reference runtime for the Cyclone binary wire format.
Cyclone is a wire format specification: the same logical value must produce exactly one byte sequence, in every language and every implementation. This crate is the smallest layer that turns primitive values into those bytes and back.
User Model → Cyclone Compiler / Derive → Generated Codec → cyclone-runtime → Bytes§What this crate does
Writer- appends primitives, strings and byte blobs to a buffer.Reader- reads them back, rejecting malformed input.Limits- allocation guards for untrusted input.DecodeError- every way a byte stream can fail to conform.Encode/Decode- the traits a codec implements.to_bytes/from_bytes- the two calls that use those traits.
A codec reaches these traits from either direction, and the runtime cannot
tell which: #[derive(Network)] from cyclone-codegen-rust writes an impl
in place, the Cyclone CLI writes one into a *.codec.rs file you own and
may edit, and a hand-written impl is just as valid.
There are no blanket impls of Encode / Decode for u32, String,
Vec<T> or any other Rust type. Which Cyclone type a value has is schema
knowledge - Vec<T> is an Array<T> only because a schema said so - and a
runtime that guessed it from the Rust type would be deciding the wire format
by inference. It writes what a codec tells it to write, nothing more.
§What this crate does not do
It does not parse schemas, read annotations, generate codecs, or hold any registry or type information. It contains no proc macro and no reflection. Composite types - models, arrays, enums - are the generated codec’s job; the runtime only knows bytes. Two consequences worth stating plainly:
- There is no
write_model/read_model. A model is written by writing its fields in declaration order, with nothing in between (RFC-0002 §5). - There is no
InvalidEnumerror. Whichu32values an enum admits is schema knowledge, so the generated codec validates it.
§Format at a glance
| Type | Bytes |
|---|---|
bool | 1 - 0x00 or 0x01, nothing else |
i8 / u8 | 1 |
i16 / u16 | 2, Little Endian |
i32 / u32 | 4, Little Endian |
i64 / u64 | 8, Little Endian |
f32 / f64 | 4 / 8 - raw IEEE 754 bits, never normalized |
String | u32 UTF-8 byte length, then the bytes |
Bytes | u32 length, then the raw bytes |
Array<T> | u32 element count, then each element |
Enum | always u32 |
Model | its fields concatenated in declaration order |
No varint, no padding, no alignment, no tag id, no object header.
§Example
Encoding the model Item { id: u32, name: String }, the way a generated
codec would:
use cyclone_runtime::{from_bytes, to_bytes, Decode, DecodeError, Encode, Reader, Writer};
struct Item {
id: u32,
name: String,
}
impl Encode for Item {
fn encode(&self, writer: &mut Writer) {
writer.write_u32(self.id);
writer.write_string(&self.name);
}
}
impl Decode for Item {
fn decode(reader: &mut Reader<'_>) -> Result<Self, DecodeError> {
Ok(Item {
id: reader.read_u32()?,
name: reader.read_string()?,
})
}
}
let bytes = to_bytes(&Item { id: 42, name: "Sword".to_owned() });
assert_eq!(
bytes,
[0x2A, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x53, 0x77, 0x6F, 0x72, 0x64],
);
let item = from_bytes::<Item>(&bytes)?;
assert_eq!(item.id, 42);
assert_eq!(item.name, "Sword");§References
- RFC-0001 - what Cyclone is
- RFC-0002 - the wire format specification
- RFC-0003 - conformance test vectors
Structs§
- Limits
- Allocation guards applied while decoding.
- Reader
- Reads Cyclone-encoded values from a borrowed byte buffer.
- Writer
- Appends Cyclone-encoded values to a growable byte buffer.
Enums§
- Decode
Error - A byte stream that does not satisfy the Cyclone Specification.
Traits§
- Decode
- A type that can be read back from Cyclone bytes.
- Encode
- A type that can be written as Cyclone bytes.
Functions§
- from_
bytes - Decodes a
Tfrombytes. - to_
bytes - Encodes
valueinto a freshVec<u8>.