creature_feature 0.2.0

Composable n-gram combinators that are ergonomic and bare-metal fast.
Documentation
//! The input-side counterpart to [`FeatureFrom`](crate::traits::FeatureFrom).
//!
//! Every featurizer in this crate ultimately consumes a contiguous slice
//! `&[Token]`. [`AsTokens`] names exactly that requirement — "this type can be
//! viewed as a slice of tokens" — so a single blanket impl per featurizer
//! covers `&str`, `&String`, `&[T]`, `&Vec<T>`, and `&[T; N]` at once, instead
//! of one hand-written (or macro-generated) forwarding impl per container type.
//!
//! # Extending featurization to your own types
//! Implementing `AsTokens` for a local type makes it featurizable by *every*
//! featurizer and combinator in the crate, present and future:
//! ```
//! use creature_feature::traits::{AsTokens, Ftzr};
//! use creature_feature::ftzrs::bislice;
//!
//! struct Dna(Vec<u8>);
//! impl AsTokens for Dna {
//!     type Token = u8;
//!     fn as_tokens(&self) -> &[u8] { &self.0 }
//! }
//!
//! let dna = Dna(vec![b'A', b'C', b'G', b'T']);
//! let feats: Vec<&[u8]> = bislice().featurize(&dna);
//! assert_eq!(feats.len(), 3);
//! ```
//!
//! # Caveat
//! Because the featurizer impls are blanket over `D: AsTokens`, a type that
//! implements `AsTokens` can no longer carry a *bespoke* `IterFtzr<&YourType>`
//! impl for a given featurizer — the blanket already covers it (this is the
//! usual coherence trade-off, not a limitation specific to this crate).

/// A type that can be viewed as a contiguous slice of tokens.
///
/// This is the single trait that dispatches every featurizer across all
/// supported input containers. See the [module docs](self) for the rationale
/// and for how to extend featurization to your own types.
pub trait AsTokens {
    /// The element type of the underlying slice (e.g. `u8` for string types).
    type Token;
    /// View `self` as a contiguous slice of [`Self::Token`].
    fn as_tokens(&self) -> &[Self::Token];
}

impl AsTokens for str {
    type Token = u8;
    #[inline]
    fn as_tokens(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl AsTokens for String {
    type Token = u8;
    #[inline]
    fn as_tokens(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl<T> AsTokens for [T] {
    type Token = T;
    #[inline]
    fn as_tokens(&self) -> &[T] {
        self
    }
}

impl<T> AsTokens for Vec<T> {
    type Token = T;
    #[inline]
    fn as_tokens(&self) -> &[T] {
        self.as_slice()
    }
}

impl<T, const N: usize> AsTokens for [T; N] {
    type Token = T;
    #[inline]
    fn as_tokens(&self) -> &[T] {
        &self[..]
    }
}