hypertube/
builder.rs

1use std::ffi::CString;
2
3pub trait Device: Sized {
4    /// # Dont use this!
5    /// Use [`DeviceBuilder`] instead!
6    /// This function should be private.
7    fn new(config: Config) -> std::io::Result<Self>;
8
9    /// Creates a new DeviceBuilder
10    /// This is one of many ways to get a DeviceBuilder including:
11    /// * [`builder()`](crate::builder())
12    /// * [`DeviceBuilder::new()`/`DeviceBuilder::default()`](crate::builder::DeviceBuilder)
13    fn builder() -> DeviceBuilder<Self> {
14        DeviceBuilder::default()
15    }
16}
17
18pub struct Config {
19    pub name: Option<CString>,
20    pub num_queues: Option<usize>,
21    pub(crate) multi_queue: Option<bool>,
22    pub no_pi: bool,
23    pub address: Option<std::net::IpAddr>,
24    pub netmask: Option<cidr::IpCidr>,
25    pub up: bool,
26
27    #[cfg(target_os = "android")]
28    pub raw_fd: Option<std::os::fd::RawFd>,
29}
30
31impl Default for Config {
32    fn default() -> Self {
33        Self {
34            name: None,
35            num_queues: None,
36            multi_queue: None,
37            no_pi: true,
38            address: None,
39            netmask: None,
40            up: false,
41            #[cfg(target_os = "android")]
42            raw_fd: None,
43        }
44    }
45}
46
47/// A builder for [`Device`]
48pub struct DeviceBuilder<D: Device> {
49    _marker: std::marker::PhantomData<D>,
50    config: Config,
51}
52
53impl<D: Device> DeviceBuilder<D> {
54    /// Creates a new builder.
55    pub fn new() -> Self {
56        Self {
57            _marker: std::marker::PhantomData,
58            config: Config {
59                name: None,
60                num_queues: None,
61                multi_queue: None,
62                no_pi: true,
63                address: None,
64                netmask: None,
65                up: true,
66                #[cfg(target_os = "android")]
67                raw_fd: None,
68            },
69        }
70    }
71
72    pub fn with_name(mut self, name: CString) -> Self {
73        self.config.name = Some(name);
74        self
75    }
76
77    /// Sets whether or not the device should have a packet information header.
78    pub fn with_pi(mut self, pi: bool) -> Self {
79        self.config.no_pi = !pi;
80        self
81    }
82
83    pub fn with_address(mut self, address: std::net::IpAddr) -> Self {
84        self.config.address = Some(address);
85        self
86    }
87
88    pub fn with_netmask(mut self, netmask: cidr::IpCidr) -> Self {
89        self.config.netmask = Some(netmask);
90        self
91    }
92
93    /// Set the number of queues the device should have.
94    /// If this is not set, the device will have 1 queue.
95    /// ## Panics
96    /// This function will panic if `num_queues` is less than 1.
97    /// ### Note
98    /// There is no way to increase the number of queues a [`Device`] has after it has been created yet.
99    /// This should be fixed in the future.
100    pub fn with_num_queues(mut self, num_queues: usize) -> Self {
101        if num_queues < 1 {
102            panic!("number of queues must be at least 1")
103        }
104        self.config.num_queues = Some(num_queues);
105        self.config.multi_queue = if num_queues > 1 {
106            Some(true)
107        } else {
108            Some(false)
109        };
110        self
111    }
112
113    /// Sets whether the [`Device`] should be up on creation or not.
114    pub fn with_up(mut self, up: bool) -> Self {
115        self.config.up = up;
116        self
117    }
118
119    #[cfg(target_os = "android")]
120    pub fn with_raw_fd(mut self, raw_fd: std::os::fd::RawFd) -> Self {
121        self.config.raw_fd = Some(raw_fd);
122        self
123    }
124
125    /// Builds the [`Device`].
126    pub fn build(self) -> std::io::Result<D> {
127        Device::new(self.config)
128    }
129}
130
131impl<D: Device> Default for DeviceBuilder<D> {
132    fn default() -> Self {
133        Self::new()
134    }
135}