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 Label {
21    pub fn enrolled(&self) -> Option<&SpeakerName> {
22        match self {
23            Self::Enrolled(name) => Some(name),
24            Self::Anonymous(_) => None,
25        }
26    }
27}
28
29impl fmt::Display for Label {
30    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
31        match self {
32            Self::Enrolled(name) => write!(formatter, "{name}"),
33            Self::Anonymous(number) => write!(formatter, "{ANONYMOUS_PREFIX}{number}"),
34        }
35    }
36}
37
38pub(super) fn reads_as_anonymous(name: &str) -> bool {
39    name.strip_prefix(ANONYMOUS_PREFIX)
40        .is_some_and(|number| number.parse::<u32>().is_ok())
41}
42
43/// Hands out anonymous speaker numbers from 1, never reusing one: a number
44/// retired by a merge leaves a gap rather than renaming a label somebody
45/// already read.
46#[derive(Debug, Default)]
47pub(crate) struct AnonymousNumbering {
48    issued: u32,
49}
50
51impl AnonymousNumbering {
52    pub(crate) fn issue(&mut self) -> Label {
53        self.issued += 1;
54        Label::Anonymous(self.issued)
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn a_label_renders_as_a_name_or_a_numbered_speaker() {
64        let alex = Label::Enrolled(SpeakerName::new("alex").expect("a usable name"));
65        assert_eq!(alex.to_string(), "alex");
66        assert_eq!(Label::Anonymous(3).to_string(), "Speaker 3");
67    }
68}