dbc_rs/receivers/
receivers_builder.rs

1use super::Receivers;
2use crate::{error::Error, error::Result};
3
4#[derive(Debug, Default)]
5pub struct ReceiversBuilder {
6    is_broadcast: bool,
7    is_none: bool,
8    nodes: Vec<String>,
9}
10
11impl ReceiversBuilder {
12    pub fn new() -> Self {
13        Self::default()
14    }
15
16    #[must_use]
17    pub fn broadcast(mut self) -> Self {
18        self.is_broadcast = true;
19        self.is_none = false;
20        self.nodes.clear();
21        self
22    }
23
24    #[must_use]
25    pub fn none(mut self) -> Self {
26        self.is_none = true;
27        self.is_broadcast = false;
28        self.nodes.clear();
29        self
30    }
31
32    #[must_use]
33    pub fn add_node(mut self, node: impl AsRef<str>) -> Self {
34        self.is_broadcast = false;
35        self.is_none = false;
36        self.nodes.push(node.as_ref().to_string());
37        self
38    }
39
40    #[must_use]
41    pub fn add_nodes<I, S>(mut self, nodes: I) -> Self
42    where
43        I: IntoIterator<Item = S>,
44        S: AsRef<str>,
45    {
46        self.is_broadcast = false;
47        self.is_none = false;
48        self.nodes.extend(nodes.into_iter().map(|s| s.as_ref().to_string()));
49        self
50    }
51
52    #[must_use]
53    pub fn clear(mut self) -> Self {
54        self.nodes.clear();
55        self.is_broadcast = false;
56        self.is_none = false;
57        self
58    }
59
60    pub fn build(self) -> Result<Receivers<'static>> {
61        if self.is_broadcast {
62            Ok(Receivers::new_broadcast())
63        } else if self.is_none || self.nodes.is_empty() {
64            Ok(Receivers::new_none())
65        } else {
66            // Convert owned Strings to static references by leaking Box<str>
67            let mut node_refs: Vec<&'static str> = Vec::new();
68            for s in self.nodes {
69                let boxed: Box<str> = s.into_boxed_str();
70                node_refs.push(Box::leak(boxed));
71            }
72            // Validate before construction
73            const MAX_RECEIVER_NODES: usize = 64;
74            if node_refs.len() > MAX_RECEIVER_NODES {
75                return Err(Error::Signal(String::from(
76                    crate::error::messages::SIGNAL_RECEIVERS_TOO_MANY,
77                )));
78            }
79            Ok(Receivers::new_nodes(&node_refs))
80        }
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use crate::error::Error;
88
89    #[test]
90    fn test_receivers_builder_broadcast() {
91        let receivers = ReceiversBuilder::new().broadcast().build().unwrap();
92        assert_eq!(receivers, Receivers::Broadcast);
93    }
94
95    #[test]
96    fn test_receivers_builder_none() {
97        let receivers = ReceiversBuilder::new().none().build().unwrap();
98        assert_eq!(receivers, Receivers::None);
99    }
100
101    #[test]
102    fn test_receivers_builder_empty() {
103        let receivers = ReceiversBuilder::new().build().unwrap();
104        assert_eq!(receivers, Receivers::None);
105    }
106
107    #[test]
108    fn test_receivers_builder_single_node() {
109        let receivers = ReceiversBuilder::new().add_node("TCM").build().unwrap();
110        match receivers {
111            Receivers::Nodes(_, count) => assert_eq!(count, 1),
112            _ => panic!("Expected Nodes variant"),
113        }
114    }
115
116    #[test]
117    fn test_receivers_builder_multiple_nodes() {
118        let receivers = ReceiversBuilder::new()
119            .add_node("TCM")
120            .add_node("BCM")
121            .add_node("ECM")
122            .build()
123            .unwrap();
124        match receivers {
125            Receivers::Nodes(_, count) => assert_eq!(count, 3),
126            _ => panic!("Expected Nodes variant"),
127        }
128    }
129
130    #[test]
131    fn test_receivers_builder_too_many() {
132        let mut builder = ReceiversBuilder::new();
133        for i in 0..65 {
134            builder = builder.add_node(format!("Node{i}"));
135        }
136        let result = builder.build();
137        assert!(result.is_err());
138        match result.unwrap_err() {
139            Error::Signal(_) => {}
140            _ => panic!("Expected Signal error"),
141        }
142    }
143}