Repository: GuillaumeGomez/sysinfo
Pull request #1064 (2023-09-15 19:26:50)

Extract `Networks` from `System`
Part of #1063.


Patch:
diff --git a/README.md b/README.md
index c08867a..327d6bf 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@ You have an example into the `examples` folder. You can run it with `cargo run -
 Otherwise, here is a little code sample:
 
 ```rust
-use sysinfo::{NetworkExt, NetworksExt, ProcessExt, System, SystemExt};
+use sysinfo::{NetworkExt, Networks, NetworksExt, ProcessExt, System, SystemExt};
 
 // Please note that we use "new_all" to ensure that all list of
 // components, network interfaces, disks and users are already
@@ -51,8 +51,10 @@ for disk in sys.disks().iter() {
 }
 
 // Network interfaces name, data received and data transmitted:
+let mut networks = Networks::new();
+networks.refresh_list();
 println!("=> networks:");
-for (interface_name, data) in sys.networks() {
+for (interface_name, data) in &networks {
     println!("{}: {}/{} B", interface_name, data.received(), data.transmitted());
 }
 
diff --git a/benches/basic.rs b/benches/basic.rs
index a9771e7..e4fedae 100644
--- a/benches/basic.rs
+++ b/benches/basic.rs
@@ -3,7 +3,7 @@
 extern crate test;
 
 use sysinfo::get_current_pid;
-use sysinfo::{DiskExt, SystemExt};
+use sysinfo::{DiskExt, NetworksExt, SystemExt};
 
 #[bench]
 fn bench_new(b: &mut test::Bencher) {
@@ -99,19 +99,21 @@ fn bench_refresh_disks_list(b: &mut test::Bencher) {
 
 #[bench]
 fn bench_refresh_networks(b: &mut test::Bencher) {
-    let mut s = sysinfo::System::new_all();
+    let mut n = sysinfo::Networks::new();
+    n.refresh_list();
 
     b.iter(move || {
-        s.refresh_networks();
+        n.refresh();
     });
 }
 
 #[bench]
 fn bench_refresh_networks_list(b: &mut test::Bencher) {
-    let mut s = sysinfo::System::new();
+    let mut n = sysinfo::Networks::new();
+    n.refresh_list();
 
     b.iter(move || {
-        s.refresh_networks_list();
+        n.refresh_list();
     });
 }
 
diff --git a/examples/simple.rs b/examples/simple.rs
index 6dd81b2..2959684 100644
--- a/examples/simple.rs
+++ b/examples/simple.rs
@@ -8,7 +8,7 @@ use std::io::{self, BufRead, Write};
 use std::str::FromStr;
 use sysinfo::Signal::*;
 use sysinfo::{
-    CpuExt, NetworkExt, NetworksExt, Pid, ProcessExt, Signal, System, SystemExt, UserExt,
+    CpuExt, NetworkExt, Networks, NetworksExt, Pid, ProcessExt, Signal, System, SystemExt, UserExt,
 };
 
 const signals: &[Signal] = &[
@@ -141,7 +141,7 @@ fn print_help() {
     writeln!(&mut io::stdout(), "quit               : Exit the program");
 }
 
-fn interpret_input(input: &str, sys: &mut System) -> bool {
+fn interpret_input(input: &str, sys: &mut System, networks: &mut Networks) -> bool {
     match input.trim() {
         "help" => print_help(),
         "refresh_disks" => {
@@ -156,7 +156,7 @@ fn interpret_input(input: &str, sys: &mut System) -> bool {
         }
         "refresh_networks" => {
             writeln!(&mut io::stdout(), "Refreshing network list...");
-            sys.refresh_networks_list();
+            networks.refresh_list();
             writeln!(&mut io::stdout(), "Done.");
         }
         "signals" => {
@@ -276,7 +276,7 @@ fn interpret_input(input: &str, sys: &mut System) -> bool {
             }
         }
         "network" => {
-            for (interface_name, data) in sys.networks().iter() {
+            for (interface_name, data) in networks.iter() {
                 writeln!(
                     &mut io::stdout(),
                     "{}:\n  ether {}\n  input data  (new / total): {} / {} B\n  output data (new / total): {} / {} B",
@@ -431,8 +431,10 @@ fn interpret_input(input: &str, sys: &mut System) -> bool {
 }
 
 fn main() {
-    println!("Getting processes' information...");
+    println!("Getting system information...");
     let mut t = System::new_all();
+    let mut n = Networks::new();
+    n.refresh_list();
     println!("Done.");
     let t_stin = io::stdin();
     let mut stin = t_stin.lock();
@@ -454,6 +456,6 @@ fn main() {
         if (&input as &str).ends_with('\n') {
             input.pop();
         }
-        done = interpret_input(input.as_ref(), &mut t);
+        done = interpret_input(input.as_ref(), &mut t, &mut n);
     }
 }
diff --git a/src/c_interface.rs b/src/c_interface.rs
index 26bb84e..5f5fb19 100644
--- a/src/c_interface.rs
+++ b/src/c_interface.rs
@@ -1,6 +1,8 @@
 // Take a look at the license at the top of the repository in the LICENSE file.
 
-use crate::{CpuExt, NetworkExt, NetworksExt, Pid, Process, ProcessExt, System, SystemExt};
+use crate::{
+    CpuExt, NetworkExt, Networks, NetworksExt, Pid, Process, ProcessExt, System, SystemExt,
+};
 use libc::{self, c_char, c_float, c_uint, c_void, pid_t, size_t};
 use std::borrow::BorrowMut;
 use std::ffi::CString;
@@ -13,6 +15,8 @@ pub type CProcess = *const c_void;
 pub type RString = *const c_char;
 /// Callback used by [`processes`][crate::System#method.processes].
 pub type ProcessLoop = extern "C" fn(pid: pid_t, process: CProcess, data: *mut c_void) -> bool;
+/// Equivalent of [`System`][crate::System] struct.
+pub type CNetworks = *mut c_void;
 
 /// Equivalent of [`System::new()`][crate::System#method.new].
 #[no_mangle]
@@ -227,17 +231,61 @@ pub extern "C" fn sysinfo_used_swap(system: CSystem) -> size_t {
     }
 }
 
+/// Equivalent of [`Networks::new()`][crate::Networks#method.new].
+#[no_mangle]
+pub extern "C" fn sysinfo_networks_init() -> CNetworks {
+    let networks = Box::new(Networks::new());
+    Box::into_raw(networks) as CNetworks
+}
+
+/// Equivalent of `Networks::drop()`. Important in C to cleanup memory.
+#[no_mangle]
+pub extern "C" fn sysinfo_networks_destroy(networks: CNetworks) {
+    assert!(!networks.is_null());
+    unsafe {
+        drop(Box::from_raw(networks as *mut Networks));
+    }
+}
+
+/// Equivalent of [`Networks::refresh_list()`][crate::Networks#method.refresh_list].
+#[no_mangle]
+pub extern "C" fn sysinfo_networks_refresh_list(networks: CNetworks) {
+    assert!(!networks.is_null());
+    unsafe {
+        let mut networks: Box<Networks> = Box::from_raw(networks as *mut Networks);
+        {
+            let networks: &mut Networks = networks.borrow_mut();
+            networks.refresh_list();
+        }
+        Box::into_raw(networks);
+    }
+}
+
+/// Equivalent of [`Networks::refresh()`][crate::Networks#method.refresh].
+#[no_mangle]
+pub extern "C" fn sysinfo_networks_refresh(networks: CNetworks) {
+    assert!(!networks.is_null());
+    unsafe {
+        let mut networks: Box<Networks> = Box::from_raw(networks as *mut Networks);
+        {
+            let networks: &mut Networks = networks.borrow_mut();
+            networks.refresh();
+        }
+        Box::into_raw(networks);
+    }
+}
+
 /// Equivalent of
 /// `system::networks().iter().fold(0, |acc, (_, data)| acc + data.received() as size_t)`.
 #[no_mangle]
-pub extern "C" fn sysinfo_networks_received(system: CSystem) -> size_t {
-    assert!(!system.is_null());
+pub extern "C" fn sysinfo_networks_received(networks: CNetworks) -> size_t {
+    assert!(!networks.is_null());
     unsafe {
-        let system: Box<System> = Box::from_raw(system as *mut System);
-        let ret = system.networks().iter().fold(0, |acc: size_t, (_, data)| {
+        let networks: Box<Networks> = Box::from_raw(networks as *mut Networks);
+        let ret = networks.iter().fold(0, |acc: size_t, (_, data)| {
             acc.saturating_add(data.received() as size_t)
         });
-        Box::into_raw(system);
+        Box::into_raw(networks);
         ret
     }
 }
@@ -245,14 +293,14 @@ pub extern "C" fn sysinfo_networks_received(system: CSystem) -> size_t {
 /// Equivalent of
 /// `system::networks().iter().fold(0, |acc, (_, data)| acc + data.transmitted() as size_t)`.
 #[no_mangle]
-pub extern "C" fn sysinfo_networks_transmitted(system: CSystem) -> size_t {
-    assert!(!system.is_null());
+pub extern "C" fn sysinfo_networks_transmitted(networks: CNetworks) -> size_t {
+    assert!(!networks.is_null());
     unsafe {
-        let system: Box<System> = Box::from_raw(system as *mut System);
-        let ret = system.networks().iter().fold(0, |acc: size_t, (_, data)| {
+        let networks: Box<Networks> = Box::from_raw(networks as *mut Networks);
+        let ret = networks.iter().fold(0, |acc: size_t, (_, data)| {
             acc.saturating_add(data.transmitted() as size_t)
         });
-        Box::into_raw(system);
+        Box::into_raw(networks);
         ret
     }
 }
diff --git a/src/common.rs b/src/common.rs
index 267ab7e..334cc22 100644
--- a/src/common.rs
+++ b/src/common.rs
@@ -366,8 +366,6 @@ impl CpuRefreshKind {
 /// [`System`]: crate::System
 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
 pub struct RefreshKind {
-    networks: bool,
-    networks_list: bool,
     processes: Option<ProcessRefreshKind>,
     disks_list: bool,
     disks: bool,
@@ -386,8 +384,6 @@ impl RefreshKind {
     ///
     /// let r = RefreshKind::new();
     ///
-    /// assert_eq!(r.networks(), false);
-    /// assert_eq!(r.networks_list(), false);
     /// assert_eq!(r.processes().is_some(), false);
     /// assert_eq!(r.disks_list(), false);
     /// assert_eq!(r.disks(), false);
@@ -408,8 +404,6 @@ impl RefreshKind {
     ///
     /// let r = RefreshKind::everything();
     ///
-    /// assert_eq!(r.networks(), true);
-    /// assert_eq!(r.networks_list(), true);
     /// assert_eq!(r.processes().is_some(), true);
     /// assert_eq!(r.disks_list(), true);
     /// assert_eq!(r.disks(), true);
@@ -421,8 +415,6 @@ impl RefreshKind {
     /// ```
     pub fn everything() -> Self {
         Self {
-            networks: true,
-            networks_list: true,
             processes: Some(ProcessRefreshKind::everything()),
             disks: true,
             disks_list: true,
@@ -441,13 +433,6 @@ impl RefreshKind {
         without_processes,
         ProcessRefreshKind
     );
-    impl_get_set!(RefreshKind, networks, with_networks, without_networks);
-    impl_get_set!(
-        RefreshKind,
-        networks_list,
-        with_networks_list,
-        without_networks_list
-    );
     impl_get_set!(RefreshKind, disks, with_disks, without_disks);
     impl_get_set!(RefreshKind, disks_list, with_disks_list, without_disks_list);
     impl_get_set!(RefreshKind, memory, with_memory, without_memory);
@@ -462,13 +447,17 @@ impl RefreshKind {
     impl_get_set!(RefreshKind, users_list, with_users_list, without_users_list);
 }
 
-/// Networks interfaces.
+/// Network interfaces.
+///
+/// Don't forget to also take a look at the [`NetworksExt`] trait to see the list of available
+/// methods.
 ///
 /// ```no_run
-/// use sysinfo::{NetworksExt, System, SystemExt};
+/// use sysinfo::{Networks, NetworksExt};
 ///
-/// let s = System::new_all();
-/// for network in s.networks().iter() {
+/// let mut networks = Networks::new();
+/// networks.refresh_list();
+/// for network in networks.iter() {
 ///     println!("{:?}", network);
 /// }
 /// ```
@@ -476,14 +465,6 @@ pub struct Networks {
     pub(crate) interfaces: HashMap<String, NetworkData>,
 }
 
-impl Networks {
-    pub(crate) fn new() -> Networks {
-        Networks {
-            interfaces: HashMap::new(),
-        }
-    }
-}
-
 impl<'a> IntoIterator for &'a Networks {
     type Item = (&'a String, &'a NetworkData);
     type IntoIter = NetworksIter<'a>;
@@ -498,10 +479,10 @@ impl<'a> IntoIterator for &'a Networks {
 /// It is returned by [`Networks::iter`][crate::Networks#method.iter].
 ///
 /// ```no_run
-/// use sysinfo::{System, SystemExt, NetworksExt};
+/// use sysinfo::{Networks, NetworksExt};
 ///
-/// let system = System::new_all();
-/// let networks_iter = system.networks().iter();
+/// let networks = Networks::new();
+/// let networks_iter = networks.iter();
 /// ```
 pub struct NetworksIter<'a> {
     inner: std::collections::hash_map::Iter<'a, String, NetworkData>,
diff --git a/src/debug.rs b/src/debug.rs
index 5d4a05a..7ffb1d1 100644
--- a/src/debug.rs
+++ b/src/debug.rs
@@ -29,7 +29,6 @@ impl fmt::Debug for System {
             .field("total swap", &self.total_swap())
             .field("free swap", &self.free_swap())
             .field("nb CPUs", &self.cpus().len())
-            .field("nb network interfaces", &self.networks().iter().count())
             .field("nb processes", &self.processes().len())
             .field("nb disks", &self.disks().len())
             .field("nb components", &self.components().len())
diff --git a/src/serde.rs b/src/serde.rs
index 02d3978..344b475 100644
--- a/src/serde.rs
+++ b/src/serde.rs
@@ -114,7 +114,6 @@ impl serde::Serialize for crate::System {
         state.serialize_field("components", &self.components())?;
         state.serialize_field("users", &self.users())?;
         state.serialize_field("disks", &self.disks())?;
-        state.serialize_field("networks", &self.networks())?;
 
         state.serialize_field("uptime", &self.uptime())?;
         state.serialize_field("boot_time", &self.boot_time())?;
diff --git a/src/traits.rs b/src/traits.rs
index 6cc0109..463aee9 100644
--- a/src/traits.rs
+++ b/src/traits.rs
@@ -5,7 +5,7 @@ use crate::{
     sys::{Component, Cpu, Disk, Process},
 };
 use crate::{
-    CpuRefreshKind, DiskKind, DiskUsage, Disks, Group, LoadAvg, Networks, NetworksIter, Pid,
+    CpuRefreshKind, DiskKind, DiskUsage, Disks, Group, LoadAvg, NetworksIter, Pid,
     ProcessRefreshKind, ProcessStatus, RefreshKind, Signal, User,
 };
 
@@ -610,8 +610,7 @@ pub trait SystemExt: Sized + Debug + Default + Send + Sync {
 
     /// Creates a new [`System`] instance with nothing loaded. If you want to
     /// load components, network interfaces or the disks, you'll have to use the
-    /// `refresh_*_list` methods. [`SystemExt::refresh_networks_list`] for
-    /// example.
+    /// `refresh_*_list` methods.
     ///
     /// Use the [`refresh_all`] method to update its internal information (or any of the `refresh_`
     /// method).
@@ -676,9 +675,9 @@ pub trait SystemExt: Sized + Debug + Default + Send + Sync {
     ///
     /// let mut s = System::new_all();
     ///
-    /// // Let's just update networks and processes:
+    /// // Let's just update processes:
     /// s.refresh_specifics(
-    ///     RefreshKind::new().with_networks().with_processes(ProcessRefreshKind::everything()),
+    ///     RefreshKind::new().with_processes(ProcessRefreshKind::everything()),
     /// );
     /// ```
     fn refresh_specifics(&mut self, refreshes: RefreshKind) {
@@ -693,11 +692,6 @@ pub trait SystemExt: Sized + Debug + Default + Send + Sync {
         } else if refreshes.components() {
             self.refresh_components();
         }
-        if refreshes.networks_list() {
-            self.refresh_networks_list();
-        } else if refreshes.networks() {
-            self.refresh_networks();
-        }
         if let Some(kind) = refreshes.processes() {
             self.refresh_processes_specifics(kind);
         }
@@ -726,7 +720,6 @@ pub trait SystemExt: Sized + Debug + Default + Send + Sync {
         self.refresh_system();
         self.refresh_processes();
         self.refresh_disks();
-        self.refresh_networks();
     }
 
     /// Refreshes system information (RAM, swap, CPU usage and components' temperature).
@@ -958,51 +951,6 @@ pub trait SystemExt: Sized + Debug + Default + Send + Sync {
     /// ```
     fn refresh_users_list(&mut self);
 
-    /// Refreshes networks data.
-    ///
-    /// ```no_run
-    /// use sysinfo::{System, SystemExt};
-    ///
-    /// let mut s = System::new_all();
-    /// s.refresh_networks();
-    /// ```
-    ///
-    /// It is a shortcut for:
-    ///
-    /// ```no_run
-    /// use sysinfo::{NetworksExt, System, SystemExt};
-    ///
-    /// let mut s = System::new_all();
-    /// let networks = s.networks_mut();
-    /// networks.refresh();
-    /// ```
-    fn refresh_networks(&mut self) {
-        self.networks_mut().refresh();
-    }
-
-    /// The network list will be updated: removing not existing anymore interfaces and adding new
-    /// ones.
-    ///
-    /// ```no_run
-    /// use sysinfo::{System, SystemExt};
-    ///
-    /// let mut s = System::new_all();
-    /// s.refresh_networks_list();
-    /// ```
-    ///
-    /// This is a shortcut for:
-    ///
-    /// ```no_run
-    /// use sysinfo::{NetworksExt, System, SystemExt};
-    ///
-    /// let mut s = System::new_all();
-    /// let networks = s.networks_mut();
-    /// networks.refresh_networks_list();
-    /// ```
-    fn refresh_networks_list(&mut self) {
-        self.networks_mut().refresh_networks_list();
-    }
-
     /// Returns the process list.
     ///
     /// ```no_run
@@ -1292,35 +1240,6 @@ pub trait SystemExt: Sized + Debug + Default + Send + Sync {
         self.disks_mut().sort_unstable_by(compare);
     }
 
-    /// Returns the network interfaces object.
-    ///
-    /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
-    ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, data) in networks {
-    ///     println!(
-    ///         "[{}] in: {}, out: {}",
-    ///         interface_name,
-    ///         data.received(),
-    ///         data.transmitted(),
-    ///     );
-    /// }
-    /// ```
-    fn networks(&self) -> &Networks;
-
-    /// Returns a mutable access to network interfaces.
-    ///
-    /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
-    ///
-    /// let mut s = System::new_all();
-    /// let networks = s.networks_mut();
-    /// networks.refresh_networks_list();
-    /// ```
-    fn networks_mut(&mut self) -> &mut Networks;
-
     /// Returns system uptime (in seconds).
     ///
     /// ```no_run
@@ -1469,11 +1388,11 @@ pub trait NetworkExt: Debug {
     /// Returns the number of received bytes since the last refresh.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
     ///     println!("in: {} B", network.received());
     /// }
     /// ```
@@ -1482,11 +1401,11 @@ pub trait NetworkExt: Debug {
     /// Returns the total number of received bytes.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
     ///     println!("in: {} B", network.total_received());
     /// }
     /// ```
@@ -1495,11 +1414,11 @@ pub trait NetworkExt: Debug {
     /// Returns the number of transmitted bytes since the last refresh.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
     ///     println!("out: {} B", network.transmitted());
     /// }
     /// ```
@@ -1508,11 +1427,11 @@ pub trait NetworkExt: Debug {
     /// Returns the total number of transmitted bytes.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
     ///     println!("out: {} B", network.total_transmitted());
     /// }
     /// ```
@@ -1521,11 +1440,11 @@ pub trait NetworkExt: Debug {
     /// Returns the number of incoming packets since the last refresh.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
     ///     println!("in: {}", network.packets_received());
     /// }
     /// ```
@@ -1534,11 +1453,11 @@ pub trait NetworkExt: Debug {
     /// Returns the total number of incoming packets.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
     ///     println!("in: {}", network.total_packets_received());
     /// }
     /// ```
@@ -1547,11 +1466,11 @@ pub trait NetworkExt: Debug {
     /// Returns the number of outcoming packets since the last refresh.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
     ///     println!("out: {}", network.packets_transmitted());
     /// }
     /// ```
@@ -1560,11 +1479,11 @@ pub trait NetworkExt: Debug {
     /// Returns the total number of outcoming packets.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
     ///     println!("out: {}", network.total_packets_transmitted());
     /// }
     /// ```
@@ -1573,11 +1492,11 @@ pub trait NetworkExt: Debug {
     /// Returns the number of incoming errors since the last refresh.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
     ///     println!("in: {}", network.errors_on_received());
     /// }
     /// ```
@@ -1586,11 +1505,11 @@ pub trait NetworkExt: Debug {
     /// Returns the total number of incoming errors.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
     ///     println!("in: {}", network.total_errors_on_received());
     /// }
     /// ```
@@ -1599,11 +1518,11 @@ pub trait NetworkExt: Debug {
     /// Returns the number of outcoming errors since the last refresh.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
     ///     println!("out: {}", network.errors_on_transmitted());
     /// }
     /// ```
@@ -1612,11 +1531,11 @@ pub trait NetworkExt: Debug {
     /// Returns the total number of outcoming errors.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
     ///     println!("out: {}", network.total_errors_on_transmitted());
     /// }
     /// ```
@@ -1625,11 +1544,11 @@ pub trait NetworkExt: Debug {
     /// Returns the MAC address associated to current interface.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
     ///     println!("MAC address: {}", network.mac_address());
     /// }
     /// ```
@@ -1638,15 +1557,32 @@ pub trait NetworkExt: Debug {
 
 /// Interacting with network interfaces.
 pub trait NetworksExt: Debug {
+    /// Creates a new `Networks` type.
+    ///
+    /// ```no_run
+    /// use sysinfo::{Networks, NetworksExt};
+    ///
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, network) in &networks {
+    ///     println!("[{interface_name}]: {network:?}");
+    /// }
+    /// ```
+    fn new() -> Self;
+
     /// Returns an iterator over the network interfaces.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworkExt, NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworkExt, NetworksExt, System, SystemExt};
     ///
-    /// let s = System::new_all();
-    /// let networks = s.networks();
-    /// for (interface_name, network) in networks {
-    ///     println!("in: {} B", network.received());
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
+    /// for (interface_name, data) in &networks {
+    ///     println!(
+    ///         "[{interface_name}] in: {}, out: {}",
+    ///         data.received(),
+    ///         data.transmitted(),
+    ///     );
     /// }
     /// ```
     fn iter(&self) -> NetworksIter;
@@ -1654,21 +1590,23 @@ pub trait NetworksExt: Debug {
     /// Refreshes the network interfaces list.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworksExt, System, SystemExt};
     ///
-    /// let mut s = System::new_all();
-    /// let networks = s.networks_mut();
-    /// networks.refresh_networks_list();
+    /// let mut networks = Networks::new();
+    /// networks.refresh_list();
     /// ```
-    fn refresh_networks_list(&mut self);
+    fn refresh_list(&mut self);
 
-    /// Refreshes the network interfaces' content.
+    /// Refreshes the network interfaces' content. If you didn't run [`NetworksExt::refresh_list`]
+    /// before, calling this method won't do anything as no interfaces are present.
     ///
     /// ```no_run
-    /// use sysinfo::{NetworksExt, System, SystemExt};
+    /// use sysinfo::{Networks, NetworksExt, System, SystemExt};
     ///
-    /// let mut s = System::new_all();
-    /// let networks = s.networks_mut();
+    /// let mut networks = Networks::new();
+    /// // Refreshes the network interfaces list.
+    /// networks.refresh_list();
+    /// // Wait some time...? Then refresh the data of each network.
     /// networks.refresh();
     /// ```
     fn refresh(&mut self);
diff --git a/src/unix/apple/network.rs b/src/unix/apple/network.rs
index 405ade7..3fe90d8 100644
--- a/src/unix/apple/network.rs
+++ b/src/unix/apple/network.rs
@@ -2,7 +2,7 @@
 
 use libc::{self, c_char, if_msghdr2, CTL_NET, NET_RT_IFLIST2, PF_ROUTE, RTM_IFINFO2};
 
-use std::collections::hash_map;
+use std::collections::{hash_map, HashMap};
 use std::ptr::null_mut;
 
 use crate::common::MacAddr;
@@ -20,7 +20,7 @@ impl Networks {
     #[allow(unknown_lints)]
     #[allow(clippy::cast_ptr_alignment)]
     #[allow(clippy::uninit_vec)]
-    fn update_networks(&mut self) {
+    fn update_networks(&mut self, insert: bool) {
         let mib = &mut [CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0];
         let mut len = 0;
         unsafe {
@@ -113,6 +113,9 @@ impl Networks {
                             interface.updated = true;
                         }
                         hash_map::Entry::Vacant(e) => {
+                            if !insert {
+                                continue;
+                            }
                             let current_in = (*if2m).ifm_data.ifi_ibytes;
                             let current_out = (*if2m).ifm_data.ifi_obytes;
                             let packets_in = (*if2m).ifm_data.ifi_ipackets;
@@ -145,22 +148,28 @@ impl Networks {
 }
 
 impl NetworksExt for Networks {
+    fn new() -> Self {
+        Self {
+            interfaces: HashMap::new(),
+        }
+    }
+
     #[allow(clippy::needless_lifetimes)]
     fn iter<'a>(&'a self) -> NetworksIter<'a> {
         NetworksIter::new(self.interfaces.iter())
     }
 
-    fn refresh_networks_list(&mut self) {
+    fn refresh_list(&mut self) {
         for (_, data) in self.interfaces.iter_mut() {
             data.updated = false;
         }
-        self.update_networks();
+        self.update_networks(true);
         self.interfaces.retain(|_, data| data.updated);
         refresh_networks_addresses(&mut self.interfaces);
     }
 
     fn refresh(&mut self) {
-        self.update_networks();
+        self.update_networks(false);
     }
 }
 
diff --git a/src/unix/apple/system.rs b/src/unix/apple/system.rs
index 54df79c..8801850 100644
--- a/src/unix/apple/system.rs
+++ b/src/unix/apple/system.rs
@@ -6,7 +6,7 @@ use crate::sys::process::*;
 use crate::sys::utils::{get_sys_value, get_sys_value_by_name};
 
 use crate::{
-    CpuRefreshKind, Disks, LoadAvg, Networks, Pid, ProcessRefreshKind, RefreshKind, SystemExt, User,
+    CpuRefreshKind, Disks, LoadAvg, Pid, ProcessRefreshKind, RefreshKind, SystemExt, User,
 };
 
 #[cfg(all(target_os = "macos", not(feature = "apple-sandbox")))]
@@ -87,7 +87,6 @@ pub struct System {
     #[cfg(not(any(target_os = "ios", feature = "apple-sandbox")))]
     components: Components,
     disks: Disks,
-    networks: Networks,
     port: mach_port_t,
     users: Vec<User>,
     boot_time: u64,
@@ -155,7 +154,6 @@ impl SystemExt for System {
                 #[cfg(not(any(target_os = "ios", feature = "apple-sandbox")))]
                 components: Components::new(),
                 disks: Disks::new(),
-                networks: Networks::new(),
                 port,
                 users: Vec::new(),
                 boot_time: boot_time(),
@@ -354,14 +352,6 @@ impl SystemExt for System {
         physical_core_count()
     }
 
-    fn networks(&self) -> &Networks {
-        &self.networks
-    }
-
-    fn networks_mut(&mut self) -> &mut Networks {
-        &mut self.networks
-    }
-
     fn total_memory(&self) -> u64 {
         self.mem_total
     }
diff --git a/src/unix/freebsd/network.rs b/src/unix/freebsd/network.rs
index 43d621d..85549ac 100644
--- a/src/unix/freebsd/network.rs
+++ b/src/unix/freebsd/network.rs
@@ -1,6 +1,6 @@
 // Take a look at the license at the top of the repository in the LICENSE file.
 
-use std::collections::hash_map;
+use std::collections::{hash_map, HashMap};
 use std::mem::MaybeUninit;
 
 use super::utils;
@@ -16,11 +16,17 @@ macro_rules! old_and_new {
 }
 
 impl NetworksExt for Networks {
+    fn new() -> Self {
+        Self {
+            interfaces: HashMap::new(),
+        }
+    }
+
     fn iter(&self) -> NetworksIter {
         NetworksIter::new(self.interfaces.iter())
     }
 
-    fn refresh_networks_list(&mut self) {
+    fn refresh_list(&mut self) {
         unsafe {
             self.refresh_interfaces(true);
         }
diff --git a/src/unix/freebsd/system.rs b/src/unix/freebsd/system.rs
index 608ba15..6c5ef5c 100644
--- a/src/unix/freebsd/system.rs
+++ b/src/unix/freebsd/system.rs
@@ -2,8 +2,7 @@
 
 use crate::{
     sys::{component::Component, Cpu, Process},
-    CpuRefreshKind, Disks, LoadAvg, Networks, Pid, ProcessRefreshKind, RefreshKind, SystemExt,
-    User,
+    CpuRefreshKind, Disks, LoadAvg, Pid, ProcessRefreshKind, RefreshKind, SystemExt, User,
 };
 
 use std::cell::UnsafeCell;
@@ -67,7 +66,6 @@ pub struct System {
     swap_used: u64,
     components: Vec<Component>,
     disks: Disks,
-    networks: Networks,
     users: Vec<User>,
     boot_time: u64,
     system_info: SystemInfo,
@@ -91,7 +89,6 @@ impl SystemExt for System {
             swap_used: 0,
             components: Vec::with_capacity(2),
             disks: Disks::new(),
-            networks: Networks::new(),
             users: Vec::new(),
             boot_time: boot_time(),
             system_info,
@@ -198,14 +195,6 @@ impl SystemExt for System {
         self.process_list.get(&pid)
     }
 
-    fn networks(&self) -> &Networks {
-        &self.networks
-    }
-
-    fn networks_mut(&mut self) -> &mut Networks {
-        &mut self.networks
-    }
-
     fn global_cpu_info(&self) -> &Cpu {
         &self.cpus.global_cpu
     }
diff --git a/src/unix/linux/network.rs b/src/unix/linux/network.rs
index 1d2b73b..d94b579 100644
--- a/src/unix/linux/network.rs
+++ b/src/unix/linux/network.rs
@@ -108,6 +108,12 @@ fn refresh_networks_list_from_sysfs(
 }
 
 impl NetworksExt for Networks {
+    fn new() -> Self {
+        Self {
+            interfaces: HashMap::new(),
+        }
+    }
+
     fn iter(&self) -> NetworksIter {
         NetworksIter::new(self.interfaces.iter())
     }
@@ -120,7 +126,7 @@ impl NetworksExt for Networks {
         }
     }
 
-    fn refresh_networks_list(&mut self) {
+    fn refresh_list(&mut self) {
         refresh_networks_list_from_sysfs(&mut self.interfaces, Path::new("/sys/class/net/"));
         refresh_networks_addresses(&mut self.interfaces);
     }
diff --git a/src/unix/linux/system.rs b/src/unix/linux/system.rs
index 2b09a27..a9f66e1 100644
--- a/src/unix/linux/system.rs
+++ b/src/unix/linux/system.rs
@@ -5,7 +5,7 @@ use crate::sys::cpu::*;
 use crate::sys::process::*;
 use crate::sys::utils::{get_all_data, to_u64};
 use crate::{
-    CpuRefreshKind, Disks, LoadAvg, Networks, Pid, ProcessRefreshKind, RefreshKind, SystemExt, User,
+    CpuRefreshKind, Disks, LoadAvg, Pid, ProcessRefreshKind, RefreshKind, SystemExt, User,
 };
 
 use libc::{self, c_char, c_int, sysconf, _SC_CLK_TCK, _SC_HOST_NAME_MAX, _SC_PAGESIZE};
@@ -161,7 +161,6 @@ pub struct System {
     swap_free: u64,
     components: Vec<Component>,
     disks: Disks,
-    networks: Networks,
     users: Vec<User>,
     info: SystemInfo,
     cpus: CpusWrapper,
@@ -236,7 +235,6 @@ impl SystemExt for System {
             cpus: CpusWrapper::new(),
             components: Vec::new(),
             disks: Disks::new(),
-            networks: Networks::new(),
             users: Vec::new(),
             info: SystemInfo::new(),
         };
@@ -391,14 +389,6 @@ impl SystemExt for System {
         self.process_list.tasks.get(&pid)
     }
 
-    fn networks(&self) -> &Networks {
-        &self.networks
-    }
-
-    fn networks_mut(&mut self) -> &mut Networks {
-        &mut self.networks
-    }
-
     fn global_cpu_info(&self) -> &Cpu {
         &self.cpus.global_cpu
     }
diff --git a/src/unknown/network.rs b/src/unknown/network.rs
index f392b5e..1dbd8c0 100644
--- a/src/unknown/network.rs
+++ b/src/unknown/network.rs
@@ -3,12 +3,20 @@
 use crate::common::MacAddr;
 use crate::{NetworkExt, Networks, NetworksExt, NetworksIter};
 
+use std::collections::HashMap;
+
 impl NetworksExt for Networks {
+    fn new() -> Self {
+        Self {
+            interfaces: HashMap::new(),
+        }
+    }
+
     fn iter(&self) -> NetworksIter {
         NetworksIter::new(self.interfaces.iter())
     }
 
-    fn refresh_networks_list(&mut self) {}
+    fn refresh_list(&mut self) {}
 
     fn refresh(&mut self) {}
 }
diff --git a/src/unknown/system.rs b/src/unknown/system.rs
index a8da84e..5256654 100644
--- a/src/unknown/system.rs
+++ b/src/unknown/system.rs
@@ -2,8 +2,7 @@
 
 use crate::{
     sys::{component::Component, Cpu, Process},
-    CpuRefreshKind, Disks, LoadAvg, Networks, Pid, ProcessRefreshKind, RefreshKind, SystemExt,
-    User,
+    CpuRefreshKind, Disks, LoadAvg, Pid, ProcessRefreshKind, RefreshKind, SystemExt, User,
 };
 
 use std::collections::HashMap;
@@ -17,7 +16,6 @@ declare_signals! {
 #[doc = include_str!("../../md_doc/system.md")]
 pub struct System {
     processes_list: HashMap<Pid, Process>,
-    networks: Networks,
     global_cpu: Cpu,
     disks: Disks,
 }
@@ -30,7 +28,6 @@ impl SystemExt for System {
     fn new_with_specifics(_: RefreshKind) -> System {
         System {
             processes_list: Default::default(),
-            networks: Networks::new(),
             global_cpu: Cpu::new(),
             disks: Disks::new(),
         }
@@ -62,14 +59,6 @@ impl SystemExt for System {
         None
     }
 
-    fn networks(&self) -> &Networks {
-        &self.networks
-    }
-
-    fn networks_mut(&mut self) -> &mut Networks {
-        &mut self.networks
-    }
-
     fn global_cpu_info(&self) -> &Cpu {
         &self.global_cpu
     }
diff --git a/src/windows/network.rs b/src/windows/network.rs
index eb5f69a..3998d7a 100644
--- a/src/windows/network.rs
+++ b/src/windows/network.rs
@@ -20,12 +20,18 @@ macro_rules! old_and_new {
 }
 
 impl NetworksExt for Networks {
+    fn new() -> Self {
+        Self {
+            interfaces: HashMap::new(),
+        }
+    }
+
     #[allow(clippy::needless_lifetimes)]
     fn iter<'a>(&'a self) -> NetworksIter<'a> {
         NetworksIter::new(self.interfaces.iter())
     }
 
-    fn refresh_networks_list(&mut self) {
+    fn refresh_list(&mut self) {
         let mut table: PMIB_IF_TABLE2 = std::ptr::null_mut();
 
         unsafe {
diff --git a/src/windows/system.rs b/src/windows/system.rs
index 17466e9..2fa388c 100644
--- a/src/windows/system.rs
+++ b/src/windows/system.rs
@@ -1,8 +1,8 @@
 // Take a look at the license at the top of the repository in the LICENSE file.
 
 use crate::{
-    CpuRefreshKind, Disks, LoadAvg, Networks, Pid, ProcessExt, ProcessRefreshKind, RefreshKind,
-    SystemExt, User,
+    CpuRefreshKind, Disks, LoadAvg, Pid, ProcessExt, ProcessRefreshKind, RefreshKind, SystemExt,
+    User,
 };
 use winapi::um::winreg::HKEY_LOCAL_MACHINE;
 
@@ -53,7 +53,6 @@ pub struct System {
     components: Vec<Component>,
     disks: Disks,
     query: Option<Query>,
-    networks: Networks,
     boot_time: u64,
     users: Vec<User>,
 }
@@ -105,7 +104,6 @@ impl SystemExt for System {
             components: Vec::new(),
             disks: Disks::new(),
             query: None,
-            networks: Networks::new(),
             boot_time: unsafe { boot_time() },
             users: Vec::new(),
         };
@@ -426,14 +424,6 @@ impl SystemExt for System {
         &self.users
     }
 
-    fn networks(&self) -> &Networks {
-        &self.networks
-    }
-
-    fn networks_mut(&mut self) -> &mut Networks {
-        &mut self.networks
-    }
-
     fn uptime(&self) -> u64 {
         unsafe { GetTickCount64() / 1_000 }
     }


Test patch:
diff --git a/tests/network.rs b/tests/network.rs
index 6925cb3..d1df092 100644
--- a/tests/network.rs
+++ b/tests/network.rs
@@ -4,12 +4,14 @@
 
 #[test]
 fn test_networks() {
-    use sysinfo::{NetworksExt, SystemExt};
+    use sysinfo::{Networks, NetworksExt, SystemExt};
 
     if sysinfo::System::IS_SUPPORTED {
-        let s = sysinfo::System::new();
-        assert_eq!(s.networks().iter().count(), 0);
-        let s = sysinfo::System::new_all();
-        assert!(s.networks().iter().count() > 0);
+        let mut n = Networks::new();
+        assert_eq!(n.iter().count(), 0);
+        n.refresh();
+        assert_eq!(n.iter().count(), 0);
+        n.refresh_list();
+        assert!(n.iter().count() > 0);
     }
 }