dimpl 0.4.3

DTLS 1.2/1.3 implementation (Sans‑IO, Sync)
Documentation
# CLAUDE.md

Code style guide for Claude sessions working on dimpl.

## File Ordering

1. Imports
2. Constants
3. Primary type (matches module name: `foo.rs``struct Foo`)
4. Related types, ordered by first appearance in primary type's fields/variants
5. `impl` block for primary type
6. Helper types and functions
7. Standard trait impls (`Display`, `Debug`, `From`)
8. Tests (`#[cfg(test)] mod tests`)

Example: `struct Foo { bar: Bar, baz: Baz }` → define `Bar` before `Baz`.

## State Machine Files (client.rs, server.rs)

Protocol flow dictates ordering throughout:

1. Module-level comment documenting the protocol flow
2. Imports
3. Primary struct (`Client` / `Server`)
4. `State` enum (variants in protocol order)
5. `impl PrimaryType` (public API: `new`, `handle_*`, `poll_*`)
6. `impl State` (`name()`, `make_progress()`, then handlers in enum order)
7. Free helper functions (ordered by first use in protocol flow)

## Imports

Group: std → external → crate. Alphabetical within groups.

```rust
use std::collections::VecDeque;
use std::time::Instant;

use arrayvec::ArrayVec;

use crate::buffer::Buf;
use crate::engine::Engine;
```

Use short paths: `std::Vec` not `std::vec::Vec`.

## Modules

Private modules with selective re-exports:

```rust
mod certificate;
pub use certificate::Certificate;
```

## Visibility

Prefer `pub` over `pub(crate)`. Only use `pub(crate)` when explicitly preventing
items from becoming part of the public API. Internal modules that are kept private
by their parent don't need `pub(crate)` on their items.

```rust
// Good: parent module is private, so pub here won't leak
mod internal {
    pub struct Helper;  // Not in public API because `internal` is private
}

// Bad: unnecessary restriction
mod internal {
    pub(crate) struct Helper;  // Redundant - parent already private
}
```

## Fields and Methods

Fields are private. Expose via getter methods.

## Documentation

Doc examples must compile and run as tests. Never use `ignore`. Use `no_run` only
when hardware/network required.

## Unwrap

Comment `unwrap()` calls explaining why they're safe:

```rust
// unwrap: is ok because we set the random in handle_timeout
let random = self.random.unwrap();
```

## Sans-IO API Contract

dimpl is Sans-IO: no sockets, no threads, no async. The caller drives I/O.

**Poll-to-Timeout Rule**: Every mutation (`handle_packet`, `handle_timeout`) must
be followed by polling until `Output::Timeout`:

```rust
client.handle_timeout(now);
loop {
    match client.poll_output(&mut buf) {
        Output::Packet(data) => { /* send to peer */ }
        Output::Connected => { /* handshake complete */ }
        Output::Timeout(when) => break,
    }
}
```

Never stop polling early. Internal state is only consistent after reaching `Timeout`.

## Memory

**Summary**: Allocation-conscious design - pool reuse, single-copy, in-place
mutation, boxing for ABI, bounded stack collections.

**Buffer Pooling**
- Reuse allocations instead of malloc/free per packet
- Clear contents but retain capacity

**Single-Copy Parsing**
- One copy from network into working buffer
- Parse and decrypt in-place on that buffer

**ABI Optimization**
- Box large inner data so outer structs fit in registers
- Avoids memmove on function calls

**Bounded Stack Collections**
- Fixed-capacity arrays for small, known-bounded collections
- Fail explicitly if bounds exceeded