//! Encoding, decoding, outboard creation, and slice extraction.
//!
//! All operations are parameterized by a `HashBackend`, making the
//! serialization format hash-agnostic.

pub mod content;
pub mod decode;
pub mod encode;
pub mod error;
pub mod mixed;
pub mod outboard;
pub mod pre_order;
pub mod slice;
pub mod sync;
pub mod traits;

#[cfg(feature = "tokio_fsm")]
pub mod fsm;

// Re-export commonly used types at the io level.
pub use content::{BaoContentItem, Leaf, Parent};
pub use error::{DecodeError, EncodeError};
pub use traits::{Outboard, OutboardMut, ReadAt, ReadBytesAt, Size, WriteAt};

use range_collections::range_set::RangeSetRange;

use crate::hash::{HashBackend, Poseidon2Backend};
use crate::tree::{BlockSize, ChunkNum, CHUNK_SIZE};
use crate::{ByteRanges, ChunkRanges};

/// Compute the root hash for a single block (possibly multi-chunk).
///
/// Hashes each chunk individually, then reduces via parent_hash
/// to produce the block's root. Used by both sync and async encode/decode paths.
pub fn hash_block(
    backend: &Poseidon2Backend,
    data: &[u8],
    start_chunk: u64,
    is_root: bool,
    block_bytes: usize,
) -> hemera::Hash {
    if data.is_empty() {
        return backend.chunk_hash(&[], start_chunk, is_root);
    }

    let mut chunk_hashes: Vec<hemera::Hash> = Vec::new();
    let mut offset = 0usize;
    let mut counter = start_chunk;
    while offset < data.len() {
        let end = (offset + CHUNK_SIZE).min(data.len());
        let chunk_data = &data[offset..end];
        let is_single_chunk = data.len() <= CHUNK_SIZE && is_root;
        chunk_hashes.push(backend.chunk_hash(chunk_data, counter, is_single_chunk));
        offset += CHUNK_SIZE;
        counter += 1;
    }

    if chunk_hashes.len() == 1 {
        return chunk_hashes.into_iter().next().unwrap();
    }

    let _ = block_bytes;
    let mut level = chunk_hashes;
    while level.len() > 1 {
        let mut next = Vec::with_capacity(level.len().div_ceil(2));
        let mut i = 0;
        while i < level.len() {
            if i + 1 < level.len() {
                let parent = backend.parent_hash(&level[i], &level[i + 1], false);
                next.push(parent);
            } else {
                next.push(level[i].clone());
            }
            i += 2;
        }
        level = next;
    }

    level.into_iter().next().unwrap()
}

/// Round byte ranges up to chunk ranges.
pub fn round_up_to_chunks(ranges: &ByteRanges) -> ChunkRanges {
    let mut result = ChunkRanges::empty();
    for range in ranges.iter() {
        let (start, end) = match range.cloned() {
            RangeSetRange::Range(r) => {
                let start = ChunkNum(r.start / CHUNK_SIZE as u64);
                let end = ChunkNum(r.end.div_ceil(CHUNK_SIZE as u64));
                (start, Some(end))
            }
            RangeSetRange::RangeFrom(r) => {
                let start = ChunkNum(r.start / CHUNK_SIZE as u64);
                (start, None)
            }
        };
        match end {
            Some(end) if start < end => {
                result |= ChunkRanges::from(start..end);
            }
            None => {
                result |= ChunkRanges::from(start..);
            }
            _ => {}
        }
    }
    result
}

/// Round chunk ranges up to full chunk groups (block-aligned).
pub fn round_up_to_chunks_groups(ranges: &ChunkRanges, block_size: BlockSize) -> ChunkRanges {
    if block_size.chunk_log() == 0 {
        return ranges.clone();
    }
    let group_size = 1u64 << block_size.chunk_log();
    let mut result = ChunkRanges::empty();
    for range in ranges.iter() {
        let (start, end) = match range.cloned() {
            RangeSetRange::Range(r) => {
                let start = ChunkNum((r.start.0 / group_size) * group_size);
                let end = ChunkNum(r.end.0.div_ceil(group_size) * group_size);
                (start, Some(end))
            }
            RangeSetRange::RangeFrom(r) => {
                let start = ChunkNum((r.start.0 / group_size) * group_size);
                (start, None)
            }
        };
        match end {
            Some(end) if start < end => {
                result |= ChunkRanges::from(start..end);
            }
            None => {
                result |= ChunkRanges::from(start..);
            }
            _ => {}
        }
    }
    result
}

Synonyms

trident/src/typecheck/mod.rs
optica/src/scanner/mod.rs
optica/src/output/mod.rs
trident/src/package/mod.rs
trident/src/gpu/mod.rs
trident/src/ir/mod.rs
trident/src/api/mod.rs
trident/src/config/mod.rs
trident/src/import/mod.rs
optica/src/query/mod.rs
trident/src/runtime/mod.rs
optica/src/render/mod.rs
nox/rs/noun/mod.rs
optica/src/server/mod.rs
trident/src/cost/mod.rs
trident/src/syntax/mod.rs
trident/src/field/mod.rs
nox/rs/patterns/mod.rs
optica/src/parser/mod.rs
trident/src/cli/mod.rs
trident/src/compile/mod.rs
trident/src/neural/mod.rs
trident/src/verify/mod.rs
optica/src/graph/mod.rs
trident/src/diagnostic/mod.rs
trident/src/lsp/mod.rs
trident/src/deploy/mod.rs
trident/src/ast/mod.rs
trident/src/neural/training/mod.rs
trident/src/verify/report/mod.rs
honeycrisp/acpu/src/pulse/mod.rs
trident/src/syntax/lexer/mod.rs
trident/src/ir/tir/mod.rs
trident/src/cost/model/mod.rs
rs/rsc/src/lints/mod.rs
trident/src/lsp/util/mod.rs
trident/src/neural/data/mod.rs
bostrom-mcp/rust/src/tools/mod.rs
rs/core/src/bounded/mod.rs
trident/src/package/store/mod.rs
bostrom-mcp/rust/src/proto/mod.rs
radio/iroh-blobs/examples/common/mod.rs
trident/src/syntax/parser/mod.rs
honeycrisp/acpu/src/probe/mod.rs
bostrom-mcp/rust/src/clients/mod.rs
trident/src/verify/smt/mod.rs
trident/src/typecheck/tests/mod.rs
trident/src/config/scaffold/mod.rs
trident/src/syntax/format/mod.rs
trident/src/lsp/semantic/mod.rs
trident/src/neural/model/mod.rs
honeycrisp/acpu/src/crypto/mod.rs
trident/src/package/hash/mod.rs
honeycrisp/rane/src/mil/mod.rs
honeycrisp/aruminium/src/ffi/mod.rs
strata/nebu/rs/extension/mod.rs
trident/src/ir/tree/mod.rs
trident/src/neural/inference/mod.rs
trident/src/verify/synthesize/mod.rs
trident/src/cost/stack_verifier/mod.rs
rs/macros/src/addressed/mod.rs
trident/src/verify/sym/mod.rs
honeycrisp/acpu/src/matrix/mod.rs
rs/core/src/fixed_point/mod.rs
trident/src/config/resolve/mod.rs
honeycrisp/acpu/src/sync/mod.rs
trident/src/package/registry/mod.rs
trident/src/syntax/grammar/mod.rs
honeycrisp/acpu/src/gemm/mod.rs
radio/iroh-blobs/src/store/mod.rs
trident/src/verify/equiv/mod.rs
honeycrisp/acpu/src/vector/mod.rs
trident/src/package/manifest/mod.rs
rs/macros/src/registers/mod.rs
honeycrisp/acpu/src/field/mod.rs
trident/src/ir/kir/mod.rs
trident/src/ir/lir/mod.rs
trident/src/api/tests/mod.rs
rs/macros/src/cell/mod.rs
honeycrisp/acpu/src/numeric/mod.rs
trident/src/verify/solve/mod.rs
trident/src/ir/lir/lower/mod.rs
trident/src/ir/tir/neural/mod.rs
cyb/cyb/cyb-shell/src/shell/mod.rs
trident/src/ir/tree/lower/mod.rs
cw-cyber/packages/cyber-std/src/tokenfactory/mod.rs
strata/trop/wgsl/src/shaders/mod.rs
trident/src/ir/tir/stack/mod.rs
cw-cyber/contracts/cybernet/src/tests/mod.rs
trident/src/syntax/parser/tests/mod.rs
trident/src/ir/tir/lower/mod.rs
cyb/cyb/cyb-shell/src/worlds/mod.rs
trident/src/neural/data/tir_graph/mod.rs
cyb/cyb/cyb-shell/src/agent/mod.rs
trident/src/ir/tir/optimize/mod.rs
strata/genies/wgsl/src/shaders/mod.rs
trident/src/ir/kir/lower/mod.rs
strata/jali/wgsl/src/shaders/mod.rs
strata/kuro/wgsl/src/shaders/mod.rs
trident/src/ir/tir/builder/mod.rs

Neighbours