Skip to main content

batman_robin/model/
mesh.rs

1use validator::Validate;
2
3/// Selects a BATMAN-adv mesh interface either by interface name or by ifindex.
4#[derive(Clone, Debug, PartialEq, Eq, Default)]
5pub struct MeshSelector {
6    /// Selects the mesh interface by interface name (for example, `"bat0"`).
7    pub name: Option<String>,
8    /// Selects the mesh interface by Linux interface index.
9    pub ifindex: Option<u32>,
10}
11
12impl MeshSelector {
13    /// Creates an empty selector.
14    pub fn builder() -> MeshSelectorBuilder {
15        MeshSelectorBuilder::new()
16    }
17
18    /// Creates a selector from an interface name.
19    pub fn with_name(name: impl Into<String>) -> Self {
20        Self {
21            name: Some(name.into()),
22            ifindex: None,
23        }
24    }
25
26    /// Creates a selector from an interface index.
27    pub const fn with_ifindex(ifindex: u32) -> Self {
28        Self {
29            name: None,
30            ifindex: Some(ifindex),
31        }
32    }
33}
34
35impl validator::Validate for MeshSelector {
36    fn validate(&self) -> Result<(), validator::ValidationErrors> {
37        let mut errors = validator::ValidationErrors::new();
38
39        if self.name.is_none() && self.ifindex.is_none() {
40            errors.add(
41                "mesh_selector",
42                validator::ValidationError {
43                    code: std::borrow::Cow::from("at_least_one_field"),
44                    message: Some(std::borrow::Cow::from(
45                        "At least one of 'name' or 'ifindex' must be set",
46                    )),
47                    params: std::collections::HashMap::new(),
48                },
49            );
50        }
51
52        if let Some(name) = &self.name
53            && name.trim().is_empty()
54        {
55            errors.add(
56                "name",
57                validator::ValidationError {
58                    code: std::borrow::Cow::from("empty_name"),
59                    message: Some(std::borrow::Cow::from("Mesh selector name cannot be empty")),
60                    params: std::collections::HashMap::new(),
61                },
62            );
63        }
64
65        if let Some(ifindex) = self.ifindex
66            && ifindex == 0
67        {
68            errors.add(
69                "ifindex",
70                validator::ValidationError {
71                    code: std::borrow::Cow::from("invalid_ifindex"),
72                    message: Some(std::borrow::Cow::from(
73                        "Mesh selector ifindex must be greater than 0",
74                    )),
75                    params: std::collections::HashMap::new(),
76                },
77            );
78        }
79
80        if errors.is_empty() {
81            Ok(())
82        } else {
83            Err(errors)
84        }
85    }
86}
87
88#[derive(Debug, Default)]
89pub struct MeshSelectorBuilder {
90    selector: MeshSelector,
91}
92
93impl MeshSelectorBuilder {
94    pub fn new() -> Self {
95        Self {
96            selector: MeshSelector::default(),
97        }
98    }
99
100    pub fn with_name(mut self, name: impl Into<String>) -> Self {
101        self.selector.name = Some(name.into());
102        self
103    }
104
105    pub fn with_ifindex(mut self, ifindex: u32) -> Self {
106        self.selector.ifindex = Some(ifindex);
107        self
108    }
109
110    pub fn build(self) -> Result<MeshSelector, validator::ValidationErrors> {
111        self.selector.validate()?;
112        Ok(self.selector)
113    }
114}