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}