piper-phoneme-streaming 0.1.1

A high-performance Rust library for streaming Text-to-Phoneme (G2P) conversion.
Documentation
use crate::text_expand::{ExpandResult, ExpandTask, ExpandUnit};
use std::collections::VecDeque;

pub struct EnNegativeExpandTask;

impl ExpandTask for EnNegativeExpandTask {
    fn expand(&self, queue: &VecDeque<ExpandUnit>) -> Option<ExpandResult> {
        if queue.len() < 2 {
            if let Some(ExpandUnit::Mark('-')) = queue.front() {
                return Some(ExpandResult::Maybe);
            }
            return None;
        }

        match (queue.front(), queue.get(1)) {
            (Some(ExpandUnit::Mark('-')), Some(ExpandUnit::Number(n))) => {
                // Only expand Mark('-') followed by a Number, not a word (hyphen in compounds)
                Some(ExpandResult::Replace(
                    2,
                    vec![
                        ExpandUnit::Word("negative".into()),
                        ExpandUnit::Number(n.clone()),
                    ],
                ))
            }
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_en_negative_expansion() {
        let task = EnNegativeExpandTask;
        let mut queue = VecDeque::new();
        queue.push_back(ExpandUnit::Mark('-'));
        queue.push_back(ExpandUnit::Number("42".into()));

        let res = task.expand(&queue).unwrap();
        if let ExpandResult::Replace(n, units) = res {
            assert_eq!(n, 2);
            assert_eq!(units[0], ExpandUnit::Word("negative".into()));
            assert_eq!(units[1], ExpandUnit::Number("42".into()));
        } else {
            panic!("Expected Replace result");
        }
    }

    #[test]
    fn test_en_negative_no_expand_hyphen_word() {
        // "non-stop" hyphen before a word should NOT trigger negative expansion
        let task = EnNegativeExpandTask;
        let mut queue = VecDeque::new();
        queue.push_back(ExpandUnit::Mark('-'));
        queue.push_back(ExpandUnit::Word("stop".into()));

        let res = task.expand(&queue);
        assert!(
            res.is_none(),
            "Hyphen before word should not expand as negative"
        );
    }

    #[test]
    fn test_en_negative_maybe_single_mark() {
        // Queue has only Mark('-') with len=1 — should return Maybe
        let task = EnNegativeExpandTask;
        let mut queue = VecDeque::new();
        queue.push_back(ExpandUnit::Mark('-'));

        let res = task.expand(&queue);
        assert!(
            matches!(res, Some(ExpandResult::Maybe)),
            "Single '-' mark should return Maybe"
        );
    }

    #[test]
    fn test_en_negative_non_mark_returns_none() {
        // A non-dash mark returns None
        let task = EnNegativeExpandTask;
        let mut queue = VecDeque::new();
        queue.push_back(ExpandUnit::Word("hello".into()));

        let res = task.expand(&queue);
        assert!(res.is_none(), "Non-dash input should return None");
    }
}