interface_rs/interface/
interface_struct.rs

1use super::{Family, InterfaceBuilder, Mapping};
2use std::fmt;
3
4/// Represents a network interface configuration in an `interfaces(5)` file.
5///
6/// The `Interface` struct encapsulates all the configuration details for a
7/// network interface, including its name, whether it starts automatically,
8/// allowed hotplug options, address family, method of configuration, and
9/// additional options.
10///
11/// To construct an `Interface`, it is recommended to use the [`InterfaceBuilder`]
12/// via the [`Interface::builder`] method for a more ergonomic and fluent API.
13///
14/// # Examples
15///
16/// Creating a new `Interface` using the builder pattern:
17///
18/// ```rust
19/// use interface_rs::interface::{Interface, Family};
20///
21/// let iface = Interface::builder("eth0")
22///     .with_auto(true)
23///     .with_allow("hotplug")
24///     .with_family(Family::Inet)
25///     .with_method("dhcp")
26///     .with_option("mtu", "1500")
27///     .build();
28/// ```
29#[derive(Debug, Clone)]
30pub struct Interface {
31    /// The name of the interface (e.g., `"eth0"`).
32    pub name: String,
33    /// Indicates if the interface is set to start automatically.
34    pub auto: bool,
35    /// A list of `allow-*` directives associated with the interface.
36    pub allow: Vec<String>,
37    /// The address family (e.g., `inet`).
38    pub family: Option<Family>,
39    /// The method of configuration (e.g., `"static"`, `"dhcp"`).
40    pub method: Option<String>,
41    /// A list of options specified under the `iface` stanza.
42    pub options: Vec<(String, String)>,
43    /// Optional mapping configuration for the interface.
44    pub mapping: Option<Mapping>,
45}
46
47impl Interface {
48    /// Creates a new [`InterfaceBuilder`] for constructing an `Interface`.
49    ///
50    /// # Arguments
51    ///
52    /// * `name` - The name of the interface (e.g., `"eth0"`).
53    ///
54    /// # Examples
55    ///
56    /// ```rust
57    /// use interface_rs::interface::Interface;
58    ///
59    /// let builder = Interface::builder("eth0");
60    /// ```
61    pub fn builder(name: impl Into<String>) -> InterfaceBuilder {
62        InterfaceBuilder::new(name)
63    }
64
65    /// Creates a new [`InterfaceBuilder`] initialized with this `Interface`'s data.
66    ///
67    /// This method allows you to modify an existing `Interface` using the builder pattern.
68    ///
69    /// # Examples
70    ///
71    /// ```rust
72    /// use interface_rs::interface::{Interface, Family};
73    ///
74    /// let iface = Interface::builder("eth0")
75    ///     .with_auto(true)
76    ///     .with_family(Family::Inet)
77    ///     .with_method("dhcp")
78    ///     .build();
79    ///
80    /// // Modify the existing interface
81    /// let modified_iface = iface.edit()
82    ///     .with_method("static")
83    ///     .with_option("address", "192.168.1.50")
84    ///     .build();
85    /// ```
86    pub fn edit(&self) -> InterfaceBuilder {
87        InterfaceBuilder {
88            name: self.name.clone(),
89            auto: self.auto,
90            allow: self.allow.clone(),
91            family: self.family.clone(),
92            method: self.method.clone(),
93            options: self.options.clone(),
94            mapping: self.mapping.clone(),
95        }
96    }
97}
98
99impl fmt::Display for Interface {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        if self.auto {
102            writeln!(f, "auto {}", self.name)?;
103        }
104        for allow_type in &self.allow {
105            writeln!(f, "allow-{} {}", allow_type, self.name)?;
106        }
107        if let Some(mapping) = &self.mapping {
108            writeln!(f, "mapping {}", self.name)?;
109            writeln!(f, "    script {}", mapping.script)?;
110            for map in &mapping.maps {
111                writeln!(f, "    map {}", map)?;
112            }
113        }
114        write!(f, "iface {}", self.name)?;
115        if let Some(family) = &self.family {
116            write!(f, " {}", family)?;
117        }
118        if let Some(method) = &self.method {
119            write!(f, " {}", method)?;
120        }
121        writeln!(f)?;
122        // Sort options before printing
123        let mut sorted_options = self.options.clone();
124        sorted_options.sort_by(|a, b| a.0.cmp(&b.0));
125        for (option_name, option_value) in &sorted_options {
126            writeln!(f, "    {} {}", option_name, option_value)?;
127        }
128        Ok(())
129    }
130}