toklen 0.2.0

A single-threaded, lightweight, and fast token counter.
Documentation
#[cfg(feature = "split")]
mod split;

#[cfg(feature = "byte_level")]
mod byte_level;

#[cfg(feature = "whitespace")]
mod whitespace;

#[cfg(feature = "whitespace_split")]
mod whitespace_split;

#[cfg(feature = "punctuation")]
mod punctuation;

#[cfg(feature = "metaspace")]
mod metaspace;

#[cfg(feature = "digits")]
mod digits;

#[cfg(feature = "char_delimiter_split")]
mod char_delimiter_split;

// ── PreTokenizerConfig ──────────────────────────────────────────────────────

use serde::Deserialize;

/// Pre-tokenizer pipeline step from `tokenizer.json`.
#[derive(Clone, Debug, Deserialize)]
#[serde(tag = "type")]
pub enum PreTokenizerConfig {
    Sequence {
        #[serde(default)]
        pretokenizers: Vec<PreTokenizerConfig>,
    },
    #[cfg(feature = "byte_level")]
    ByteLevel(byte_level::ByteLevel),
    #[cfg(feature = "split")]
    Split(split::Split),
    #[cfg(feature = "whitespace")]
    Whitespace,
    #[cfg(feature = "whitespace_split")]
    WhitespaceSplit,
    #[cfg(feature = "digits")]
    Digits(digits::Digits),
    #[cfg(feature = "metaspace")]
    Metaspace(metaspace::Metaspace),
    #[cfg(feature = "punctuation")]
    Punctuation(punctuation::Punctuation),
    #[cfg(feature = "char_delimiter_split")]
    CharDelimiterSplit(char_delimiter_split::CharDelimiterSplit),

    // ------------------------------------------------------------------------
    // Unsupported settings.
    #[serde(untagged)]
    Other(serde_json::Value),
    // BertPreTokenizer,
    // UnicodeScripts,
}

// ── PreTokenizer ────────────────────────────────────────────────────────────

use crate::pre_tokenized::PreTokenizedString;

/// Errors from constructing or running a pre-tokenizer.
#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("invalid config value: {0}")]
    Json(#[from] serde_json::Error),

    #[error("regex error: {0}")]
    Regex(#[from] fancy_regex::Error),

    #[error("unsupported pre-tokenizer type: {0}")]
    Unsupported(String),
}

/// A compiled pre-tokenizer ready for use.
#[derive(Clone, Debug)]
pub enum PreTokenizer {
    Sequence(Vec<PreTokenizer>),

    #[cfg(feature = "split")]
    Split(split::Split),
    #[cfg(feature = "byte_level")]
    ByteLevel(byte_level::ByteLevel),
    #[cfg(feature = "whitespace")]
    Whitespace,
    #[cfg(feature = "whitespace_split")]
    WhitespaceSplit,
    #[cfg(feature = "digits")]
    Digits(digits::Digits),
    #[cfg(feature = "metaspace")]
    Metaspace(metaspace::Metaspace),
    #[cfg(feature = "punctuation")]
    Punctuation(punctuation::Punctuation),
    #[cfg(feature = "char_delimiter_split")]
    CharDelimiterSplit(char_delimiter_split::CharDelimiterSplit),
}

impl PreTokenizer {
    /// Build a pre-tokenizer from its JSON configuration.
    pub fn from_config(config: PreTokenizerConfig) -> Result<Self, Error> {
        match config {
            #[cfg(feature = "split")]
            PreTokenizerConfig::Split(s) => Ok(Self::Split(s)),
            #[cfg(feature = "byte_level")]
            PreTokenizerConfig::ByteLevel(bl) => Ok(Self::ByteLevel(bl)),
            #[cfg(feature = "whitespace")]
            PreTokenizerConfig::Whitespace => Ok(Self::Whitespace),
            #[cfg(feature = "whitespace_split")]
            PreTokenizerConfig::WhitespaceSplit => Ok(Self::WhitespaceSplit),
            #[cfg(feature = "digits")]
            PreTokenizerConfig::Digits(d) => Ok(Self::Digits(d)),
            #[cfg(feature = "metaspace")]
            PreTokenizerConfig::Metaspace(m) => Ok(Self::Metaspace(m)),
            #[cfg(feature = "punctuation")]
            PreTokenizerConfig::Punctuation(p) => Ok(Self::Punctuation(p)),
            #[cfg(feature = "char_delimiter_split")]
            PreTokenizerConfig::CharDelimiterSplit(c) => Ok(Self::CharDelimiterSplit(c)),
            PreTokenizerConfig::Sequence { pretokenizers } => {
                let mut steps: Vec<Self> = Vec::with_capacity(pretokenizers.len());
                for pretokenizer in pretokenizers {
                    steps.push(Self::from_config(pretokenizer)?);
                }
                Ok(Self::Sequence(steps))
            }
            PreTokenizerConfig::Other(v) => Err(Error::Unsupported(v.to_string())),
        }
    }

    /// Refine the splits of `pts` in place.
    pub fn pre_tokenize(&self, pts: &mut PreTokenizedString) -> Result<(), Error> {
        match self {
            #[cfg(feature = "split")]
            Self::Split(s) => s.pre_tokenize(pts),
            #[cfg(feature = "byte_level")]
            Self::ByteLevel(bl) => bl.pre_tokenize(pts),
            #[cfg(feature = "whitespace")]
            Self::Whitespace => whitespace::pre_tokenize(pts),
            #[cfg(feature = "whitespace_split")]
            Self::WhitespaceSplit => whitespace_split::pre_tokenize(pts),
            #[cfg(feature = "digits")]
            Self::Digits(d) => d.pre_tokenize(pts),
            #[cfg(feature = "metaspace")]
            Self::Metaspace(m) => m.pre_tokenize(pts),
            #[cfg(feature = "punctuation")]
            Self::Punctuation(p) => p.pre_tokenize(pts),
            #[cfg(feature = "char_delimiter_split")]
            Self::CharDelimiterSplit(c) => c.pre_tokenize(pts),
            Self::Sequence(steps) => {
                for step in steps {
                    step.pre_tokenize(pts)?;
                }
                Ok(())
            }
        }
    }
}