# no_std Support
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Feature Levels](#feature-levels)
- [1. no_std (no alloc)](#1-no_std-no-alloc)
- [2. no_std + alloc](#2-no_std-alloc)
- [3. std (default)](#3-std-default)
- [Building and Testing](#building-and-testing)
- [Building for no_std](#building-for-no_std)
- [Common Targets](#common-targets)
- [Feature Comparison](#feature-comparison)
- [Memory Usage](#memory-usage)
- [Stack Usage](#stack-usage)
- [Heap Usage](#heap-usage)
- [Common Patterns](#common-patterns)
- [Embedded Systems](#embedded-systems)
- [WebAssembly](#webassembly)
- [Derive Macro Support](#derive-macro-support)
- [Troubleshooting](#troubleshooting)
- ["Cannot find crate `std`"](#cannot-find-crate-std)
- ["Cannot allocate memory"](#cannot-allocate-memory)
- ["Feature 'alloc' is required"](#feature-alloc-is-required)
- [Future Enhancements](#future-enhancements)
Synta is designed to work in `no_std` environments, making it suitable for embedded systems and other constrained environments.
## Feature Levels
Synta provides three feature levels:
### 1. no_std (no alloc)
The most minimal configuration, suitable for the most constrained environments.
**Features**:
- Zero-copy tag and length parsing
- Primitive types with stack allocation
- Fixed-size types
- SmallVec optimization for Integer and OID types
**Limitations**:
- No dynamic memory allocation
- Limited to types that can be decoded without heap allocation
- No indefinite length support
- Error messages are &'static str
**Cargo.toml**:
```toml
[dependencies]
synta = { version = "0.1", default-features = false }
```
**Example**:
```rust
#![no_std]
use synta::{Decoder, Encoding};
use synta::types::primitive::Integer;
fn decode_integer(data: &[u8]) -> Result<i64, synta::Error> {
let mut decoder = Decoder::new(data, Encoding::Der);
let int: Integer = decoder.decode()?;
int.as_i64()
}
```
### 2. no_std + alloc
Provides full ASN.1 functionality without requiring std.
**Features**:
- All features from no_std
- Dynamic memory allocation via `alloc`
- Full SEQUENCE, SET, and constructed type support
- Indefinite length support (for BER/CER)
- Vec-based types (SequenceOf, SetOf)
- String types with dynamic allocation
**Limitations**:
- Error messages are still simplified (String instead of formatted)
- No std-specific I/O traits
**Cargo.toml**:
```toml
[dependencies]
synta = { version = "0.1", default-features = false, features = ["alloc"] }
```
**Example**:
```rust
#![no_std]
extern crate alloc;
use synta::{Decoder, Encoding};
use synta::types::constructed::Sequence;
use synta::types::primitive::Integer;
fn decode_sequence(data: &[u8]) -> Result<Sequence, synta::Error> {
let mut decoder = Decoder::new(data, Encoding::Der);
decoder.decode()
}
```
### 3. std (default)
Full standard library support with all features enabled.
**Features**:
- All features from no_std + alloc
- Detailed error messages with formatting
- std::error::Error trait implementation
- Future: std::io integration
**Cargo.toml**:
```toml
[dependencies]
synta = "0.1" # std is default
```
## Building and Testing
### Building for no_std
Test that your code builds for no_std using a bare-metal target:
```bash
# Install target
rustup target add thumbv7em-none-eabihf
# Build for no_std (no alloc)
cargo build --target thumbv7em-none-eabihf --no-default-features
# Build for no_std + alloc
cargo build --target thumbv7em-none-eabihf --no-default-features --features alloc
```
### Common Targets
- **ARM Cortex-M**: `thumbv7em-none-eabihf`, `thumbv6m-none-eabi`
- **RISC-V**: `riscv32imac-unknown-none-elf`
- **AVR**: `avr-unknown-gnu-atmega328`
## Feature Comparison
| Tag/Length parsing | yes | yes | yes |
| Primitive types | yes | yes | yes |
| SmallVec optimization | yes | yes | yes |
| SEQUENCE/SET | no | yes | yes |
| SequenceOf/SetOf | no | yes | yes |
| String types | Limited | yes | yes |
| Indefinite length | no | yes | yes |
| Derive macros | no | no | yes |
| Detailed errors | no | no | yes |
| std::error::Error | no | no | yes |
## Memory Usage
### Stack Usage
With SmallVec optimization (enabled with `alloc` feature):
- Integer: Stack-allocated for values up to 16 bytes
- OID: Stack-allocated for paths up to 8 components
- Other types: Depends on content
### Heap Usage
When `alloc` is enabled:
- SEQUENCE/SET: Allocate for element storage
- Strings: Allocate for content
- Large integers/OIDs: Spill to heap when exceeding SmallVec capacity
## Common Patterns
### Embedded Systems
```rust
#![no_std]
extern crate alloc;
use synta::{Decoder, Encoding};
use synta::types::primitive::Integer;
// Decode from flash/ROM
fn verify_signature(cert_data: &[u8]) -> Result<(), synta::Error> {
let mut decoder = Decoder::new(cert_data, Encoding::Der);
// ... parse certificate structure
Ok(())
}
```
### WebAssembly
```rust
#![no_std]
extern crate alloc;
use synta::{Encoder, Encoding};
use synta::types::primitive::Integer;
#[no_mangle]
pub extern "C" fn encode_number(value: i64) -> *mut u8 {
let int = Integer::from(value);
let mut encoder = Encoder::new(Encoding::Der);
encoder.encode(&int).unwrap();
let bytes = encoder.finish().unwrap();
// Return pointer to wasm host
// (proper memory management omitted for brevity)
bytes.as_ptr() as *mut u8
}
```
## Derive Macro Support
**Note**: Derive macros require proc-macros which need std at compile-time. The `derive` feature is only available when the `std` feature is enabled.
If you need derive-like functionality in no_std environments, manually implement the `Encode`, `Decode`, and `Tagged` traits following the patterns in the library.
## Troubleshooting
### "Cannot find crate `std`"
Make sure you're using `#![no_std]` at the crate root and:
```toml
synta = { version = "0.1", default-features = false }
```
### "Cannot allocate memory"
For constrained environments, use types that don't require heap allocation:
- Use Integer with small values (stack-allocated via SmallVec)
- Use fixed-size primitives (Boolean, Null)
- Avoid large SEQUENCE/SET types
### "Feature 'alloc' is required"
Some types require the `alloc` feature:
```toml
synta = { version = "0.1", default-features = false, features = ["alloc"] }
```
## Future Enhancements
- Support for more types in pure no_std mode (without alloc)
- Compile-time maximum sizes for stack allocation
- Const generics for fixed-size SEQUENCE types