Skip to main content

aria_kit/speaker/
label.rs

1//! Who a stretch of speech is attributed to.
2
3use std::fmt;
4
5use super::SpeakerName;
6
7const ANONYMOUS_PREFIX: &str = "Speaker ";
8
9/// An enrolled person, or a voice nobody enrolled, numbered in the order it
10/// was first heard.
11///
12/// An enrolled name is never spelled like an anonymous one, so the text a
13/// transcript or a client shows names one speaker.
14#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub enum Label {
16    Enrolled(SpeakerName),
17    Anonymous(u32),
18}
19
20impl fmt::Display for Label {
21    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
22        match self {
23            Self::Enrolled(name) => write!(formatter, "{name}"),
24            Self::Anonymous(number) => write!(formatter, "{ANONYMOUS_PREFIX}{number}"),
25        }
26    }
27}
28
29pub(super) fn reads_as_anonymous(name: &str) -> bool {
30    name.strip_prefix(ANONYMOUS_PREFIX)
31        .is_some_and(|number| number.parse::<u32>().is_ok())
32}
33
34/// Hands out anonymous speaker numbers from 1, never reusing one: a number
35/// retired by a merge leaves a gap rather than renaming a label somebody
36/// already read.
37#[derive(Debug, Default)]
38pub(crate) struct AnonymousNumbering {
39    issued: u32,
40}
41
42impl AnonymousNumbering {
43    pub(crate) fn issue(&mut self) -> Label {
44        self.issued += 1;
45        Label::Anonymous(self.issued)
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn a_label_renders_as_a_name_or_a_numbered_speaker() {
55        let alex = Label::Enrolled(SpeakerName::new("alex").expect("a usable name"));
56        assert_eq!(alex.to_string(), "alex");
57        assert_eq!(Label::Anonymous(3).to_string(), "Speaker 3");
58    }
59}