appletheia_application/outbox/
outbox_relay_instance.rs1use 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}