daedalus_runtime/
fanin.rs1use std::ops::Deref;
2
3#[derive(Clone, Debug, Default, PartialEq, Eq)]
8pub struct FanIn<T> {
9 values: Vec<T>,
10}
11
12impl<T> FanIn<T> {
13 pub fn new(values: Vec<T>) -> Self {
14 Self { values }
15 }
16
17 pub fn from_indexed(mut values: Vec<(u32, T)>) -> Self {
18 values.sort_by_key(|(i, _)| *i);
19 Self {
20 values: values.into_iter().map(|(_, v)| v).collect(),
21 }
22 }
23
24 pub fn into_vec(self) -> Vec<T> {
25 self.values
26 }
27}
28
29impl<T> Deref for FanIn<T> {
30 type Target = [T];
31
32 fn deref(&self) -> &Self::Target {
33 &self.values
34 }
35}
36
37impl<T> IntoIterator for FanIn<T> {
38 type Item = T;
39 type IntoIter = std::vec::IntoIter<T>;
40
41 fn into_iter(self) -> Self::IntoIter {
42 self.values.into_iter()
43 }
44}
45
46pub(crate) fn parse_indexed_port(prefix: &str, port: &str) -> Option<u32> {
47 let suffix = port.strip_prefix(prefix)?;
48 if suffix.is_empty() || !suffix.bytes().all(|b| b.is_ascii_digit()) {
49 return None;
50 }
51 suffix.parse::<u32>().ok()
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn parse_indexed_port_rejects_non_numeric() {
60 assert_eq!(parse_indexed_port("in", "in"), None);
61 assert_eq!(parse_indexed_port("in", "inx"), None);
62 assert_eq!(parse_indexed_port("in", "in-1"), None);
63 }
64
65 #[test]
66 fn parse_indexed_port_parses_numeric_suffix() {
67 assert_eq!(parse_indexed_port("in", "in0"), Some(0));
68 assert_eq!(parse_indexed_port("in", "in10"), Some(10));
69 }
70
71 #[test]
72 fn from_indexed_sorts_by_index() {
73 let v = FanIn::from_indexed(vec![(10, "a"), (2, "b"), (1, "c")]);
74 assert_eq!(v.into_vec(), vec!["c", "b", "a"]);
75 }
76}