viterbi 0.0.1

Pure-Rust, no-unsafe convolutional encoder and hard-decision Viterbi (MLSE) decoder — CCSDS K=7 R=1/2 inner code for concatenated FEC.
Documentation
// Author: BolivarTech
// Version: 1.0.0
// Date: 2026-07-02
//! # `viterbi` — CCSDS K=7 R=1/2 convolutional encoder + hard-decision block Viterbi decoder.
//!
//! This crate is the **inner code** of the classic CCSDS concatenated coding scheme
//! (`K = 7`, `R = 1/2`), designed to pair with an outer Reed–Solomon code via an interleaver:
//!
//! ```text
//! TX:  data → [RS(255,223)] → [interleaver] → [conv. K=7] → CHANNEL
//! RX:  CHANNEL → [Viterbi] → [de-interleaver] → [RS decode] → data
//!                └── this crate
//! ```
//!
//! This increment (`v0.0.x`) provides **hard-decision, block-mode** encode/decode targeting `std`.
//! Soft-decision, puncturing, rate 1/3, and generic `K ≤ 9` are additive in the next minor.
//!
//! ## Design invariants
//! - Pure Rust, no `unsafe` (`forbid`ed crate-wide via `Cargo.toml` lints and here).
//! - Deterministic: same input ⇒ same output, bit-for-bit, on every platform.
//! - No panic in the decode hot path; `Result` only at configuration boundaries.
//!
//! # Examples
//!
//! Encode a payload, then recover it with the Viterbi decoder (clean channel):
//!
//! ```
//! use viterbi::{CcsdsViterbiDecoder, CodeParams, ViterbiEncoder};
//!
//! // Build the encoder and decoder from the first-class CCSDS profile.
//! let encoder = ViterbiEncoder::new(CodeParams::ccsds_r1_2()).unwrap();
//! let mut decoder = CcsdsViterbiDecoder::new(CodeParams::ccsds_r1_2(), 4096).unwrap();
//!
//! let payload = b"hello, viterbi";
//! let coded = encoder.encode(payload).unwrap();
//! let decoded = decoder.decode_block(&coded).unwrap();
//!
//! assert_eq!(&decoded.bytes, payload);
//! ```
#![forbid(unsafe_code)]

/// Constraint length.
pub const K: u8 = 7;
/// Memory (shift-register length) = K - 1.
pub const M: u8 = 6;
/// Trellis states for the CCSDS profile = 2^M.
pub const STATES: usize = 1 << M;
/// Output bits per input bit (rate 1/2).
pub const N: usize = 2;
/// Hard upper bound on `max_info_bits` (R18).
pub const MAX_SUPPORTED_INFO_BITS: usize = 1_000_000;

pub mod decoder;
pub mod encoder;
pub mod metric;
pub mod packing;
pub mod params;
pub(crate) mod trellis;

// Flat public API: re-export the primary types at the crate root.
pub use decoder::{CcsdsViterbiDecoder, ConfigError, DecodeError, ViterbiDecoder};
pub use encoder::{EncodeError, ViterbiEncoder};
pub use metric::{BranchMetric, HardHamming, HARD_ERASURE};
pub use packing::{CodedBlock, DecodedBlock};
pub use params::{CodeParams, ParamError};

#[cfg(test)]
mod tests {
    #[test]
    fn crate_constants_are_ccsds() {
        assert_eq!(super::K, 7);
        assert_eq!(super::M, 6);
        assert_eq!(super::STATES, 1 << super::M); // 64
        assert_eq!(super::N, 2);
        assert_eq!(super::MAX_SUPPORTED_INFO_BITS, 1_000_000);
    }
}