# Primitives Reference

This chapter documents the foundational types and utilities that the rest of
mosaik builds on. These live in the `primitives` module (public types) and
internal helpers.

## `Digest` / `UniqueId` / `Tag`

The core identifier type — a 32-byte blake3 hash.

```rust,ignore
use mosaik::Digest;  // re-exported at crate root
```

`Digest`, `UniqueId`, and `Tag` are all the same type, aliased for clarity in
different contexts:

| Alias       | Used for                                   |
| ----------- | ------------------------------------------ |
| `Digest`    | General-purpose 32-byte identifier         |
| `UniqueId`  | Derived identity (groups, stores, bonds)   |
| `Tag`       | Discovery tags for peer classification     |
| `NetworkId` | Network identifier (`= Digest`)            |
| `GroupId`   | Group identifier (`= Digest`)              |
| `StreamId`  | Stream identifier (`= Digest`)             |
| `StoreId`   | Collection store identifier (`= UniqueId`) |

### Construction

```rust,ignore
// From a string (hashes the string with blake3)
let tag = Digest::from("validator");

// From a hex string (64 chars = direct decode, otherwise hashed)
let id = Digest::from("a1b2c3d4...");

// From numeric types (little-endian encoded, then hashed)
let id = Digest::from_u64(42);

// From multiple parts (concatenated, then hashed)
let id = Digest::from_parts(&["prefix", "suffix"]);

// Derive a child ID deterministically
let child = parent.derive("child-name");

// Random
let id = Digest::random();

// Zero (sentinel value)
let zero = Digest::zero();
```

### Compile-time construction

Two equivalent macros are available — `id!` is the short alias:

```rust,ignore
use mosaik::{id, unique_id};

const MY_ID: UniqueId = id!("a1b2c3d4e5f6...");         // 64-char hex literal
const MY_ID: UniqueId = unique_id!("a1b2c3d4e5f6...");  // identical, longer name
```

Both accept either a 64-character hex string (decoded directly) or any other
string (hashed with blake3).

### Display

- `Display` — short hex (first 5 bytes): `a1b2c3d4e5`
- `Debug` — full 64-character hex string
- `Short<T>` wrapper — always shows first 5 bytes
- `Abbreviated<const LEN, T>` — shows `first..last` if longer than LEN

### Serialization

- **Human-readable** formats (JSON, TOML): hex string
- **Binary** formats (postcard): raw 32 bytes

---

## `Ticket`

An opaque, typed credential that peers attach to their discovery entry for
authorization purposes.

```rust,ignore
use mosaik::{Ticket, UniqueId, id, Bytes};

const MY_AUTH: UniqueId = id!("my-app.auth");

let ticket = Ticket::new(MY_AUTH, Bytes::from("credential-data"));
let id: UniqueId = ticket.id(); // deterministic, derived from class + data
```

| Field   | Type       | Description                                                |
| ------- | ---------- | ---------------------------------------------------------- |
| `class` | `UniqueId` | Identifies the authorization scheme                        |
| `data`  | `Bytes`    | Opaque payload; format determined by the class             |

Tickets are stored in a peer's `PeerEntry` and propagated via gossip and
catalog sync. The discovery system never interprets ticket data --
validation is done in application code (e.g. inside a producer's
`accept_if` predicate).

See [Discovery > Auth Tickets](../subsystems/discovery/tickets.md) for
a full walkthrough.

---

## `PeerId`

```rust,ignore
type PeerId = iroh::EndpointId;
```

A peer's public identity, derived from their Ed25519 public key. This is an
iroh type, not a mosaik `Digest`. It is used in discovery, bonds, and
connection authentication.

## `SecretKey`

Re-exported from iroh. An Ed25519 secret key that determines a node's
`PeerId`. If not provided to `NetworkBuilder`, a random key is generated
automatically — this is the recommended default for regular nodes.

Specifying a fixed secret key is only recommended for **bootstrap nodes**
that need a stable, well-known peer ID across restarts:

```rust,ignore
use mosaik::SecretKey;

// Auto-generated (default) — new identity each run
let network = Network::builder()
    .network_id("my-network")
    .build().await?;

// Fixed key — stable identity, recommended only for bootstrap nodes
let key = SecretKey::generate(&mut rand::rng());
let bootstrap = Network::builder()
    .network_id("my-network")
    .secret_key(key)
    .build().await?;
```

---

## The `collection!` macro

The recommended way to declare named collection definitions. It generates a
struct with a compile-time `StoreId` and implements `CollectionReader` and/or
`CollectionWriter`.

```rust,ignore
use mosaik::collection;

// Full (reader + writer)
collection!(pub Prices = mosaik::collections::Map<String, f64>, "prices");

// Reader only
collection!(pub reader Prices = mosaik::collections::Map<String, f64>, "prices");

// Writer only
collection!(pub writer Prices = mosaik::collections::Map<String, f64>, "prices");

// With generics
collection!(pub Items<T> = mosaik::collections::Vec<T>, "app.items");
```

The store ID string is **intent-addressed** — hashed with blake3 at compile
time (or decoded directly if it is exactly 64 hex characters). Two nodes that
independently declare the same string converge on the same `StoreId` without
coordination.

See [Collections > collection! macro](../subsystems/collections.md#the-collection-macro-recommended)
for the full syntax reference, mode table, and usage examples.

## Collection traits and type aliases

These traits and aliases work with types generated by the `collection!` macro.
The traits live in `mosaik::collections`; the type aliases are re-exported at
the crate root.

| Item               | Kind       | Description                                                      |
| ------------------ | ---------- | ---------------------------------------------------------------- |
| `CollectionReader` | Trait      | Provides `fn reader(&Network)` and `fn online_reader(&Network)` |
| `CollectionWriter` | Trait      | Provides `fn writer(&Network)` and `fn online_writer(&Network)` |
| `ReaderOf<C>`      | Type alias | `<C as CollectionReader>::Reader` — the concrete reader          |
| `WriterOf<C>`      | Type alias | `<C as CollectionWriter>::Writer` — the concrete writer          |

The `online_reader` and `online_writer` methods create the handle and await
`.when().online()` in a single call, reducing the common two-step pattern.

```rust,ignore
use mosaik::{collection, collections::CollectionReader, ReaderOf};

collection!(pub MyVec = mosaik::collections::Vec<String>, "my.vec");

// ReaderOf<MyVec> resolves to VecReader<String>
let reader: ReaderOf<MyVec> = MyVec::reader(&network);
```

## The `stream!` macro

The recommended way to declare named stream definitions. It generates a
struct with a compile-time `StreamId` and implements `StreamProducer`
and/or `StreamConsumer`.

```rust,ignore
use mosaik::stream;

// Type-derived StreamId (most common)
stream!(pub PriceFeed = PriceUpdate);

// Explicit StreamId
stream!(pub PriceFeed = PriceUpdate, "oracle.price");

// Producer only
stream!(pub producer PriceFeed = PriceUpdate, "oracle.price");

// Consumer only
stream!(pub consumer PriceFeed = PriceUpdate, "oracle.price");

// With configuration
stream!(pub PriceFeed = PriceUpdate, "oracle.price",
    accept_if: |peer| peer.tags().contains(&tag!("trusted")),
    producer online_when: |c| c.minimum_of(2),
    subscribe_if: |peer| true,
);
```

The stream ID string is **intent-addressed** — hashed with blake3 at compile
time (or decoded directly if it is exactly 64 hex characters). When omitted,
the `StreamId` is derived from the datum type name. Two nodes that
independently declare the same string converge on the same `StreamId` without
coordination.

See [Streams > stream! macro](../subsystems/streams.md#the-stream-macro-recommended)
for the full syntax reference, configuration keys, and usage examples.

## Stream traits and type aliases

These traits and aliases work with types generated by the `stream!` macro.
The traits live in `mosaik::streams`; the type aliases are re-exported at
the crate root.

| Item             | Kind       | Description                                                         |
| ---------------- | ---------- | ------------------------------------------------------------------- |
| `StreamProducer` | Trait      | Provides `fn producer(&Network)` and `fn online_producer(&Network)` |
| `StreamConsumer` | Trait      | Provides `fn consumer(&Network)` and `fn online_consumer(&Network)` |
| `ProducerOf<S>`  | Type alias | `<S as StreamProducer>::Producer` — the concrete producer           |
| `ConsumerOf<S>`  | Type alias | `<S as StreamConsumer>::Consumer` — the concrete consumer           |

The `online_producer` and `online_consumer` methods create the handle and
await `.when().online()` in a single call, reducing the common two-step
pattern.

```rust,ignore
use mosaik::{stream, streams::StreamProducer, ProducerOf};

stream!(pub PriceFeed = PriceUpdate, "oracle.price");

// ProducerOf<PriceFeed> resolves to Producer<PriceUpdate>
let producer: ProducerOf<PriceFeed> = PriceFeed::producer(&network);
```

## Stream definitions (`ProducerDef` / `ConsumerDef`)

> **Note:** The [`stream!` macro](#the-stream-macro) is now the
> recommended approach. `ProducerDef` and `ConsumerDef` still work and
> are useful when you need an explicit definition value.

These types allow you to define a stream's identity at compile time and
create pre-configured builders from it. They live in `mosaik::streams`.

| Type             | Description                                      |
| ---------------- | ------------------------------------------------ |
| `ProducerDef<T>` | Producer definition — creates a producer builder |
| `ConsumerDef<T>` | Consumer definition — creates a consumer builder |

```rust,ignore
use mosaik::{unique_id, streams::ProducerDef};

const PRICES: ProducerDef<PriceUpdate> =
    ProducerDef::new(Some(unique_id!("prices")));

let producer = PRICES.open(&network).build()?;
```

| Method                        | Available on   | Returns            |
| ----------------------------- | -------------- | ------------------ |
| `const fn new(Option<StreamId>)` | Both types  | `Self`             |
| `fn open(&self, &Network)`    | Both types     | Builder            |

---

## Collection definitions (`CollectionDef`)

> **Note:** The [`collection!` macro](#the-collection-macro) is now the
> recommended approach. `CollectionDef`, `ReaderDef`, and `WriterDef` still
> work and are useful when you need an explicit definition value.

These types allow you to define a collection's identity at compile time and
create readers or writers from it. They live in `mosaik::collections`.

| Type                | Description                                                            |
| ------------------- | ---------------------------------------------------------------------- |
| `CollectionDef<C>`  | Full definition — can create both writers and readers for collection C |
| `ReaderDef<C>`      | Reader-only definition — typically exported by library authors         |
| `WriterDef<C>`      | Writer-only definition                                                 |
| `CollectionFromDef` | Trait implemented for all collection types; associates Reader/Writer   |

The type parameter `C` is the collection type (e.g., `Map<String, u64>`) and
`T` encodes the value types as a tuple (`(String, u64)` for Map, `T` directly
for single-type collections like `Vec<T>`).

```rust,ignore
use mosaik::{unique_id, collections::{CollectionDef, ReaderDef, Map}};

const MY_MAP: CollectionDef<Map<String, u64>> =
	CollectionDef::new(unique_id!("my-map"));

const MY_MAP_READER: ReaderDef<Map<String, u64>> =
	MY_MAP.as_reader();
```

| Method                       | Available on                 | Returns     |
| ---------------------------- | ---------------------------- | ----------- |
| `const fn new(StoreId)`      | All three types              | `Self`      |
| `const fn as_reader(&self)`  | `CollectionDef`              | `ReaderDef` |
| `const fn as_writer(&self)`  | `CollectionDef`              | `WriterDef` |
| `fn reader(&self, &Network)` | `CollectionDef`, `ReaderDef` | `C::Reader` |
| `fn writer(&self, &Network)` | `CollectionDef`, `WriterDef` | `C::Writer` |

See [Collections > CollectionDef](../subsystems/collections.md#collection-definitions-collectiondef)
for usage examples and the full type-parameter mapping table.

---

## Wire encoding

All network messages use **postcard** — a compact, `#[no_std]`-compatible
binary format using variable-length integers.

| Function                                                          | Description                            |
| ----------------------------------------------------------------- | -------------------------------------- |
| `serialize<T: Serialize>(&T) -> Bytes`                            | Serialize to bytes (panics on failure) |
| `deserialize<T: DeserializeOwned>(impl AsRef<[u8]>) -> Result<T>` | Deserialize from bytes                 |

These are internal crate functions. Application code interacts with them
indirectly through `Link<P>` send/receive and collection operations.

---

## `Bytes` / `BytesMut`

Re-exported from the `bytes` crate. Used throughout mosaik for zero-copy
byte buffers:

```rust,ignore
use mosaik::Bytes;

let data: Bytes = serialize(&my_message);
```

---

## `BackoffFactory`

A factory type for creating retry backoff strategies:

```rust,ignore
type BackoffFactory = Arc<
    dyn Fn() -> Box<dyn Backoff + Send + Sync + 'static>
        + Send + Sync + 'static
>;
```

Used in `streams::Config` to configure consumer reconnection. The `backoff`
crate is re-exported at `mosaik::streams::backoff`.

---

## Formatting utilities

Internal helpers for consistent debug output:

| Type                        | Description                                          |
| --------------------------- | ---------------------------------------------------- |
| `Pretty<T>`                 | Pass-through wrapper (for trait integration)         |
| `Short<T>`                  | Display first 5 bytes as hex                         |
| `Abbreviated<const LEN, T>` | Show `first..last` hex if longer than LEN bytes      |
| `Redacted<T>`               | Always prints `<redacted>`                           |
| `FmtIter<W, I>`             | Format iterator elements comma-separated in brackets |

---

## `IntoIterOrSingle<T>`

An ergonomic trait that lets API methods accept either a single item or an
iterator:

```rust,ignore
// Both work:
discovery.with_tags("validator");            // single tag
discovery.with_tags(["validator", "relay"]); // multiple tags
```

This is implemented via two blanket impls using `Variant<0>` (single item
via `Into<T>`) and `Variant<1>` (iterator of `Into<T>`).

---

## Internal async primitives

These are `pub(crate)` and not part of the public API, but understanding them
helps when reading mosaik's source code.

### `UnboundedChannel<T>`

A wrapper around `tokio::sync::mpsc::unbounded_channel` that keeps both the
sender and receiver in one struct:

```rust,ignore
let channel = UnboundedChannel::new();
channel.send(42);
let val = channel.recv().await;
```

| Method                           | Description                     |
| -------------------------------- | ------------------------------- |
| `sender()`                       | Get `&UnboundedSender<T>`       |
| `receiver()`                     | Get `&mut UnboundedReceiver<T>` |
| `send(T)`                        | Send (errors silently ignored)  |
| `recv()`                         | Async receive                   |
| `poll_recv(cx)`                  | Poll-based receive              |
| `poll_recv_many(cx, buf, limit)` | Batch poll receive              |
| `is_empty()` / `len()`           | Queue inspection                |

### `AsyncWorkQueue<T>`

A `FuturesUnordered` wrapper with a permanently-pending sentinel future so
that polling never returns `None`:

```rust,ignore
let queue = AsyncWorkQueue::new();
queue.enqueue(async { do_work().await });

// Poll via Stream trait — never completes while empty
while let Some(result) = queue.next().await {
    handle(result);
}
```

### `BoxPinFut<T>`

Type alias for boxed, pinned, send futures:

```rust,ignore
type BoxPinFut<T> = Pin<Box<dyn Future<Output = T> + Send + 'static>>;
```

The `InternalFutureExt` trait adds a `.pin()` method to any
`Future + Send + 'static` for ergonomic boxing.
