cyclone-runtime-rust 1.0.0

Rust reference runtime for the Cyclone binary wire format: Writer, Reader, DecodeError.
Documentation
//! 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.
//!
//! ```text
//! 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 `InvalidEnum` error. Which `u32` values 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");
//! # Ok::<(), DecodeError>(())
//! ```
//!
//! # References
//!
//! - RFC-0001 - what Cyclone is
//! - RFC-0002 - the wire format specification
//! - RFC-0003 - conformance test vectors

#![warn(missing_docs)]
#![forbid(unsafe_code)]

mod codec;
mod error;
mod reader;
mod writer;

pub use codec::{from_bytes, to_bytes, Decode, Encode};
pub use error::DecodeError;
pub use reader::{Limits, Reader};
pub use writer::Writer;