# ax-codec-core
Low-level binary codec primitives for ax_codec. This crate provides the core encoding/decoding traits, buffer abstractions, and utility functions.
## Features
- **`no_std`** compatible (with `alloc` feature)
- **Zero-copy** borrow decoding via `View<'a>`
- **Varint** encoding (LEB128 / Protocol Buffers style)
- **SIMD fast-path** for varint decode on x86_64 (optional)
- **Decode limits** — configurable max allocation, depth, string/vec length
- **CRC32 checksums** for data integrity (optional)
- **Version-gated** decoding for wire format evolution
## Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
ax-codec-core = { version = "0.1", features = ["std"] }
```
### Feature Flags
- `std` - Enables std library support (default)
- `alloc` - Enables alloc library support (required for most types)
- `simd` - Enables SIMD-accelerated varint decoding (x86_64, aarch64)
- `crc32` - Enables CRC32 checksum support
- `bytes` - Enables integration with `bytes` crate
- `axhash` - Enables integration with `axhash-map` crate
- `dhat-heap` - Enables dhat heap profiling
- `jemalloc` - Enables jemalloc allocator integration
## Core Traits
### Encode
```rust
use ax_codec_core::{Encode, BufferWriter};
use ax_codec_core::buffer::VecWriter;
#[derive(Encode)]
struct MyData {
id: u32,
value: u64,
}
let data = MyData { id: 42, value: 100 };
let mut writer = VecWriter::new();
data.encode(&mut writer).unwrap();
let encoded = writer.into_vec();
```
### Decode
```rust
use ax_codec_core::{Decode, BufferReader};
use ax_codec_core::buffer::SliceReader;
let mut reader = SliceReader::new(&encoded);
let decoded = MyData::decode(&mut reader).unwrap();
```
### View (Zero-Copy)
```rust
use ax_codec_core::{View, BufferReader};
use ax_codec_core::buffer::SliceReader;
#[derive(View)]
struct MyView<'a> {
id: u32,
data: &'a [u8],
}
let mut reader = SliceReader::new(&encoded);
let view = MyView::view(&mut reader).unwrap();
// No allocation - borrows directly from input
```
### Validate
```rust
use ax_codec_core::{Validate, BufferReader};
use ax_codec_core::buffer::SliceReader;
let mut reader = SliceReader::new(w.as_slice());
// Validates wire format without constructing the type
MyData::validate(&mut reader).unwrap();
```
## Buffer Types
### VecWriter
Allocating writer that grows as needed:
```rust
use ax_codec_core::buffer::VecWriter;
let mut writer = VecWriter::new();
writer.write_all(b"hello").unwrap();
let bytes = writer.into_vec();
```
### PooledVecWriter
Thread-local pooled writer for reduced allocations:
```rust
use ax_codec_core::buffer::PooledVecWriter;
let mut writer = PooledVecWriter::new();
writer.write_all(b"hello").unwrap();
let bytes = writer.into_vec(); // Returns buffer, doesn't recycle
// Writer automatically recycles on drop if not finished
```
### SliceReader
Non-allocating reader from byte slices:
```rust
use ax_codec_core::buffer::SliceReader;
let data = b"hello world";
let mut reader = SliceReader::new(data);
let byte = reader.next().unwrap();
let remaining = reader.remaining();
```
## Decode Limits
Control resource usage during decoding:
```rust
use ax_codec_core::limits::{DecodeLimits, LimitedReader};
use ax_codec_core::buffer::SliceReader;
let limits = DecodeLimits {
max_alloc: 1024 * 1024, // 1 MiB max allocation
max_depth: 32, // Max nesting depth
max_string_len: 4096, // Max string length
max_vec_len: 1024, // Max vec/collection size
max_slice_len: 1024, // Max slice length for zero-copy
};
let reader = SliceReader::new(&data);
let mut limited = LimitedReader::new(reader, limits);
let decoded = MyData::decode(&mut limited).unwrap();
```
### Preset Limits
```rust
use ax_codec_core::limits::DecodeLimits;
// Conservative limits for untrusted input
let limits = DecodeLimits::conservative();
// Unlimited limits (use with caution)
let limits = DecodeLimits::unlimited();
// Custom limits
let limits = DecodeLimits {
max_alloc: 16 * 1024 * 1024, // 16 MiB
..DecodeLimits::default()
};
```
## Varint Encoding
Variable-length integer encoding (LEB128 style):
```rust
use ax_codec_core::varint;
let mut writer = VecWriter::new();
varint::encode_uvarint(300, &mut writer).unwrap();
varint::encode_svarint(-150, &mut writer).unwrap();
let mut reader = SliceReader::new(writer.as_slice());
let decoded_u = varint::decode_uvarint(&mut reader).unwrap();
let decoded_s = varint::decode_svarint(&mut reader).unwrap();
```
## Checksums
CRC32 checksums for data integrity:
```rust
use ax_codec_core::checksum;
let data = MyData { id: 42, value: 100 };
let mut writer = VecWriter::new();
// Encode with checksum
checksum::encode_with_checksum(&data, &mut writer).unwrap();
// Decode with checksum verification
let mut reader = SliceReader::new(writer.as_slice());
let decoded = checksum::decode_with_checksum::<MyData, _>(&mut reader).unwrap();
```
## Versioned Encoding
Wire format versioning:
```rust
use ax_codec_core::version;
let data = MyData { id: 42, value: 100 };
let mut writer = VecWriter::new();
// Encode with version
version::encode_versioned(1, &data, &mut writer).unwrap();
// Decode with version range check
let mut reader = SliceReader::new(writer.as_slice());
let (ver, decoded) = version::decode_versioned::<MyData, _>(0, 2, &mut reader).unwrap();
assert_eq!(ver, 1);
```
## Supported Types
### Primitives
- All integer types: `u8`, `u16`, `u32`, `u64`, `u128`, `i8`, `i16`, `i32`, `i64`, `i128`
- Floating point: `f32`, `f64`
- Boolean: `bool`
### Collections
- `Vec<T>` - with `alloc` feature
- `&[T]` - zero-copy for FixedSize types
- `Option<T>`
- `String` - with `alloc` feature
- `&str` - zero-copy
- `HashMap<K, V>` - with `axhash` feature
- `HashSet<T>` - with `axhash` feature
- `Cow<'a, str>` - with `alloc` feature
- `Cow<'a, [u8]>` - with `alloc` feature
## FixedSize Trait
Types with known constant size can implement `FixedSize` for optimizations:
```rust
use ax_codec_core::FixedSize;
impl FixedSize for MyType {
const SIZE: usize = 8; // Size in bytes
}
```
## License
MIT