Skip to main content

appletheia_application/outbox/
outbox_relay_instance.rs

1use std::{fmt, fmt::Display, str::FromStr};
2
3use super::{OutboxRelayInstanceError, OutboxRelayInstanceId, OutboxRelayProcessId};
4
5#[derive(Clone, Debug, Eq, PartialEq, Hash)]
6pub struct OutboxRelayInstance {
7    instance_id: OutboxRelayInstanceId,
8    process_id: OutboxRelayProcessId,
9}
10
11impl OutboxRelayInstance {
12    pub fn new(instance_id: OutboxRelayInstanceId, process_id: OutboxRelayProcessId) -> Self {
13        Self {
14            instance_id,
15            process_id,
16        }
17    }
18
19    pub fn instance_id(&self) -> &OutboxRelayInstanceId {
20        &self.instance_id
21    }
22
23    pub fn process_id(&self) -> OutboxRelayProcessId {
24        self.process_id
25    }
26}
27
28impl Display for OutboxRelayInstance {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        write!(f, "{}:{}", self.instance_id, self.process_id)
31    }
32}
33
34impl FromStr for OutboxRelayInstance {
35    type Err = OutboxRelayInstanceError;
36
37    fn from_str(s: &str) -> Result<Self, Self::Err> {
38        if s.matches(':').count() != 1 {
39            return Err(OutboxRelayInstanceError::MissingSeparator);
40        }
41        let (instance_raw, process_raw) = s
42            .split_once(':')
43            .ok_or(OutboxRelayInstanceError::MissingSeparator)?;
44
45        if instance_raw.is_empty() {
46            return Err(OutboxRelayInstanceError::EmptyInstanceId);
47        }
48        if process_raw.is_empty() {
49            return Err(OutboxRelayInstanceError::EmptyProcessId);
50        }
51
52        let instance_id = OutboxRelayInstanceId::new(instance_raw.to_string())?;
53        let process_num = process_raw
54            .parse::<u32>()
55            .map_err(OutboxRelayInstanceError::InvalidProcessId)?;
56        let process_id = OutboxRelayProcessId::from(process_num);
57
58        Ok(OutboxRelayInstance::new(instance_id, process_id))
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn formats_and_parses_round_trip() {
68        let instance = OutboxRelayInstanceId::new("instance-1".to_string()).unwrap();
69        let process = OutboxRelayProcessId::new(42);
70        let owner = OutboxRelayInstance::new(instance.clone(), process);
71
72        let text = owner.to_string();
73        let parsed = OutboxRelayInstance::from_str(&text).unwrap();
74
75        assert_eq!(parsed.instance_id(), &instance);
76        assert_eq!(parsed.process_id(), process);
77    }
78
79    #[test]
80    fn fails_without_separator() {
81        let err = OutboxRelayInstance::from_str("noseparator").expect_err("should fail");
82        assert!(matches!(err, OutboxRelayInstanceError::MissingSeparator));
83    }
84
85    #[test]
86    fn fails_on_empty_instance_id() {
87        let err = OutboxRelayInstance::from_str(":123").expect_err("should fail");
88        assert!(matches!(err, OutboxRelayInstanceError::EmptyInstanceId));
89    }
90
91    #[test]
92    fn fails_on_empty_process_id() {
93        let err = OutboxRelayInstance::from_str("instance-1:").expect_err("should fail");
94        assert!(matches!(err, OutboxRelayInstanceError::EmptyProcessId));
95    }
96}