interface_rs/interface/
interface_struct.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use super::{Family, InterfaceBuilder, Mapping};
use std::fmt;

/// Represents a network interface configuration in an `interfaces(5)` file.
///
/// The `Interface` struct encapsulates all the configuration details for a
/// network interface, including its name, whether it starts automatically,
/// allowed hotplug options, address family, method of configuration, and
/// additional options.
///
/// To construct an `Interface`, it is recommended to use the [`InterfaceBuilder`]
/// via the [`Interface::builder`] method for a more ergonomic and fluent API.
///
/// # Examples
///
/// Creating a new `Interface` using the builder pattern:
///
/// ```rust
/// use interface_rs::interface::{Interface, Family};
///
/// let iface = Interface::builder("eth0")
///     .with_auto(true)
///     .with_allow("hotplug")
///     .with_family(Family::Inet)
///     .with_method("dhcp")
///     .with_option("mtu", "1500")
///     .build();
/// ```
#[derive(Debug, Clone)]
pub struct Interface {
    /// The name of the interface (e.g., `"eth0"`).
    pub name: String,
    /// Indicates if the interface is set to start automatically.
    pub auto: bool,
    /// A list of `allow-*` directives associated with the interface.
    pub allow: Vec<String>,
    /// The address family (e.g., `inet`).
    pub family: Option<Family>,
    /// The method of configuration (e.g., `"static"`, `"dhcp"`).
    pub method: Option<String>,
    /// A list of options specified under the `iface` stanza.
    pub options: Vec<(String, String)>,
    /// Optional mapping configuration for the interface.
    pub mapping: Option<Mapping>,
}

impl Interface {
    /// Creates a new [`InterfaceBuilder`] for constructing an `Interface`.
    ///
    /// # Arguments
    ///
    /// * `name` - The name of the interface (e.g., `"eth0"`).
    ///
    /// # Examples
    ///
    /// ```rust
    /// use interface_rs::interface::Interface;
    ///
    /// let builder = Interface::builder("eth0");
    /// ```
    pub fn builder(name: impl Into<String>) -> InterfaceBuilder {
        InterfaceBuilder::new(name)
    }

    /// Creates a new [`InterfaceBuilder`] initialized with this `Interface`'s data.
    ///
    /// This method allows you to modify an existing `Interface` using the builder pattern.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use interface_rs::interface::{Interface, Family};
    ///
    /// let iface = Interface::builder("eth0")
    ///     .with_auto(true)
    ///     .with_family(Family::Inet)
    ///     .with_method("dhcp")
    ///     .build();
    ///
    /// // Modify the existing interface
    /// let modified_iface = iface.edit()
    ///     .with_method("static")
    ///     .with_option("address", "192.168.1.50")
    ///     .build();
    /// ```
    pub fn edit(&self) -> InterfaceBuilder {
        InterfaceBuilder {
            name: self.name.clone(),
            auto: self.auto,
            allow: self.allow.clone(),
            family: self.family.clone(),
            method: self.method.clone(),
            options: self.options.clone(),
            mapping: self.mapping.clone(),
        }
    }
}

impl fmt::Display for Interface {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.auto {
            writeln!(f, "auto {}", self.name)?;
        }
        for allow_type in &self.allow {
            writeln!(f, "allow-{} {}", allow_type, self.name)?;
        }
        if let Some(mapping) = &self.mapping {
            writeln!(f, "mapping {}", self.name)?;
            writeln!(f, "    script {}", mapping.script)?;
            for map in &mapping.maps {
                writeln!(f, "    map {}", map)?;
            }
        }
        write!(f, "iface {}", self.name)?;
        if let Some(family) = &self.family {
            write!(f, " {}", family)?;
        }
        if let Some(method) = &self.method {
            write!(f, " {}", method)?;
        }
        writeln!(f)?;
        // Sort options before printing
        let mut sorted_options = self.options.clone();
        sorted_options.sort_by(|a, b| a.0.cmp(&b.0));
        for (option_name, option_value) in &sorted_options {
            writeln!(f, "    {} {}", option_name, option_value)?;
        }
        Ok(())
    }
}