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;

use super::number_to_words_en;

pub struct EnNumberExpandTask;

impl ExpandTask for EnNumberExpandTask {
    fn expand(&self, queue: &VecDeque<ExpandUnit>) -> Option<ExpandResult> {
        if let Some(ExpandUnit::Number(num)) = queue.front()
            && let Ok(val) = num.parse::<u64>()
        {
            let words = number_to_words_en(val);
            if !words.is_empty() {
                return Some(ExpandResult::Replace(
                    1,
                    words
                        .into_iter()
                        .map(|w| ExpandUnit::Word(w.into()))
                        .collect(),
                ));
            }
        }
        None
    }
}

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

    #[test]
    fn test_en_number_expansion() {
        let task = EnNumberExpandTask;
        let mut queue = VecDeque::new();

        queue.push_back(ExpandUnit::Number("123".into()));
        let res = task.expand(&queue).unwrap();
        if let ExpandResult::Replace(n, units) = res {
            assert_eq!(n, 1);
            assert_eq!(
                units,
                vec![
                    ExpandUnit::Word("one".into()),
                    ExpandUnit::Word("hundred".into()),
                    ExpandUnit::Word("and".into()),
                    ExpandUnit::Word("twenty".into()),
                    ExpandUnit::Word("three".into()),
                ]
            );
        } else {
            panic!("Expected Replace result");
        }

        queue.clear();
        queue.push_back(ExpandUnit::Number("1005".into()));
        let res = task.expand(&queue).unwrap();
        if let ExpandResult::Replace(_, units) = res {
            assert_eq!(units[0], ExpandUnit::Word("one".into()));
            assert_eq!(units[1], ExpandUnit::Word("thousand".into()));
            assert_eq!(units[2], ExpandUnit::Word("and".into()));
            assert_eq!(units[3], ExpandUnit::Word("five".into()));
        } else {
            panic!("Expected Replace result for 1005");
        }
    }

    #[test]
    fn test_en_number_zero() {
        let task = EnNumberExpandTask;
        let mut queue = VecDeque::new();
        queue.push_back(ExpandUnit::Number("0".into()));

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

    #[test]
    fn test_en_number_single_digit() {
        let task = EnNumberExpandTask;
        let mut queue = VecDeque::new();
        queue.push_back(ExpandUnit::Number("7".into()));

        let res = task.expand(&queue).unwrap();
        if let ExpandResult::Replace(n, units) = res {
            assert_eq!(n, 1);
            assert_eq!(units, vec![ExpandUnit::Word("seven".into())]);
        } else {
            panic!("Expected Replace result for single digit");
        }
    }

    #[test]
    fn test_en_number_teens() {
        let task = EnNumberExpandTask;
        let mut queue = VecDeque::new();
        queue.push_back(ExpandUnit::Number("13".into()));

        let res = task.expand(&queue).unwrap();
        if let ExpandResult::Replace(_, units) = res {
            assert_eq!(units, vec![ExpandUnit::Word("thirteen".into())]);
        } else {
            panic!("Expected Replace result for teen number");
        }
    }

    #[test]
    fn test_en_number_millions() {
        let task = EnNumberExpandTask;
        let mut queue = VecDeque::new();
        queue.push_back(ExpandUnit::Number("1000000".into()));

        let res = task.expand(&queue).unwrap();
        if let ExpandResult::Replace(_, units) = res {
            assert_eq!(
                units,
                vec![
                    ExpandUnit::Word("one".into()),
                    ExpandUnit::Word("million".into()),
                ]
            );
        } else {
            panic!("Expected Replace result for one million");
        }
    }

    #[test]
    fn test_en_number_non_number_returns_none() {
        let task = EnNumberExpandTask;
        let mut queue = VecDeque::new();
        queue.push_back(ExpandUnit::Word("hello".into()));

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