Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions nmrs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ All notable changes to the `nmrs` crate will be documented in this file.

## [Unreleased]

## [2.1.0] - 2026-02-28
### Added
- `#[must_use]` attributes across public API: constructors, builder methods, and pure functions ([#220](https://github.com/cachebag/nmrs/issues/220))

## [2.0.1] - 2026-02-25
### Changed
- Completed IPv6 support ([#208](https://github.com/cachebag/nmrs/issues/208))
- Completed IPv6 support ([#208](https://github.com/cachebag/nmrs/pull/208))
- Replace magic number with named constant for device states ([#230](https://github.com/cachebag/nmrs/pull/230))
- Replaced hardcoded root paths with `Default` impl ([#224](https://github.com/cachebag/nmrs/issues/224))
- Add context to D-Bus operation errors ([#240](https://github.com/cachebag/nmrs/issues/240))
- Replace `println!` with `debug!` ([#234](https://github.com/cachebag/nmrs/issues/234))
- Idempotence enforcement for `forget_vpn()` ([#232](https://github.com/cachebag/nmrs/issues/232))
- Replaced hardcoded root paths with `Default` impl ([#224](https://github.com/cachebag/nmrs/pull/224))
- Add context to D-Bus operation errors ([#240](https://github.com/cachebag/nmrs/pull/240))
- Replace `println!` with `debug!` ([#234](https://github.com/cachebag/nmrs/pull/234))
- Idempotence enforcement for `forget_vpn()` ([#232](https://github.com/cachebag/nmrs/pull/232))

### Added
- validate bluetooth address in `populate_bluez_info` & `BluetoothIdentity::new` ([#215](https://github.com/cachebag/nmrs/issues/215))
Expand Down
2 changes: 1 addition & 1 deletion nmrs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "nmrs"
version = "2.0.1"
version = "2.1.0"
authors = ["Akrm Al-Hakimi <alhakimiakrmj@gmail.com>"]
edition.workspace = true
rust-version = "1.85.1"
Expand Down
2 changes: 2 additions & 0 deletions nmrs/src/api/builders/bluetooth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use crate::{
};

/// Builds the `connection` section with type, id, uuid, and autoconnect settings.
#[must_use]
pub fn base_connection_section(
name: &str,
opts: &ConnectionOptions,
Expand Down Expand Up @@ -64,6 +65,7 @@ fn bluetooth_section(settings: &BluetoothIdentity) -> HashMap<&'static str, Valu
s
}

#[must_use]
pub fn build_bluetooth_connection(
name: &str,
settings: &BluetoothIdentity,
Expand Down
29 changes: 29 additions & 0 deletions nmrs/src/api/builders/connection_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub struct IpConfig {

impl IpConfig {
/// Creates a new IP configuration.
#[must_use]
pub fn new(address: impl Into<String>, prefix: u32) -> Self {
Self {
address: address.into(),
Expand All @@ -60,6 +61,7 @@ pub struct Route {

impl Route {
/// Creates a new route configuration.
#[must_use]
pub fn new(dest: impl Into<String>, prefix: u32) -> Self {
Self {
dest: dest.into(),
Expand All @@ -70,12 +72,14 @@ impl Route {
}

/// Sets the next hop gateway for this route.
#[must_use]
pub fn next_hop(mut self, gateway: impl Into<String>) -> Self {
self.next_hop = Some(gateway.into());
self
}

/// Sets the metric (priority) for this route.
#[must_use]
pub fn metric(mut self, metric: u32) -> Self {
self.metric = Some(metric);
self
Expand Down Expand Up @@ -130,6 +134,7 @@ impl ConnectionBuilder {
///
/// let builder = ConnectionBuilder::new("802-11-wireless", "HomeNetwork");
/// ```
#[must_use]
pub fn new(connection_type: &str, id: impl Into<String>) -> Self {
let mut settings = HashMap::new();
let mut connection = HashMap::new();
Expand All @@ -147,6 +152,7 @@ impl ConnectionBuilder {
///
/// By default, a random UUID is generated. Use this to specify a deterministic
/// UUID for testing or when recreating existing connections.
#[must_use]
pub fn uuid(mut self, uuid: Uuid) -> Self {
if let Some(conn) = self.settings.get_mut("connection") {
conn.insert("uuid", Value::from(uuid.to_string()));
Expand All @@ -157,6 +163,7 @@ impl ConnectionBuilder {
/// Sets the network interface name for this connection.
///
/// This restricts the connection to a specific interface (e.g., "wlan0", "eth0").
#[must_use]
pub fn interface_name(mut self, name: impl Into<String>) -> Self {
if let Some(conn) = self.settings.get_mut("connection") {
conn.insert("interface-name", Value::from(name.into()));
Expand All @@ -165,6 +172,7 @@ impl ConnectionBuilder {
}

/// Enables or disables automatic connection on boot/availability.
#[must_use]
pub fn autoconnect(mut self, enabled: bool) -> Self {
if let Some(conn) = self.settings.get_mut("connection") {
conn.insert("autoconnect", Value::from(enabled));
Expand All @@ -176,6 +184,7 @@ impl ConnectionBuilder {
///
/// When multiple connections are available, NetworkManager connects to the
/// one with the highest priority. Default is 0.
#[must_use]
pub fn autoconnect_priority(mut self, priority: i32) -> Self {
if let Some(conn) = self.settings.get_mut("connection") {
conn.insert("autoconnect-priority", Value::from(priority));
Expand All @@ -187,6 +196,7 @@ impl ConnectionBuilder {
///
/// After this many failed attempts, the connection won't auto-retry.
/// Default is -1 (unlimited retries).
#[must_use]
pub fn autoconnect_retries(mut self, retries: i32) -> Self {
if let Some(conn) = self.settings.get_mut("connection") {
conn.insert("autoconnect-retries", Value::from(retries));
Expand All @@ -197,6 +207,7 @@ impl ConnectionBuilder {
/// Applies multiple connection options at once.
///
/// This is a convenience method to apply all fields from `ConnectionOptions`.
#[must_use]
pub fn options(mut self, opts: &ConnectionOptions) -> Self {
if let Some(conn) = self.settings.get_mut("connection") {
conn.insert("autoconnect", Value::from(opts.autoconnect));
Expand All @@ -213,6 +224,7 @@ impl ConnectionBuilder {
}

/// Configures IPv4 to use automatic configuration (DHCP).
#[must_use]
pub fn ipv4_auto(mut self) -> Self {
let mut ipv4 = HashMap::new();
ipv4.insert("method", Value::from("auto"));
Expand All @@ -233,6 +245,7 @@ impl ConnectionBuilder {
/// ])
/// .build();
/// ```
#[must_use]
pub fn ipv4_manual(mut self, addresses: Vec<IpConfig>) -> Self {
let mut ipv4 = HashMap::new();
ipv4.insert("method", Value::from("manual"));
Expand All @@ -254,6 +267,7 @@ impl ConnectionBuilder {
}

/// Disables IPv4 for this connection.
#[must_use]
pub fn ipv4_disabled(mut self) -> Self {
let mut ipv4 = HashMap::new();
ipv4.insert("method", Value::from("disabled"));
Expand All @@ -262,6 +276,7 @@ impl ConnectionBuilder {
}

/// Configures IPv4 to use link-local addressing (169.254.x.x).
#[must_use]
pub fn ipv4_link_local(mut self) -> Self {
let mut ipv4 = HashMap::new();
ipv4.insert("method", Value::from("link-local"));
Expand All @@ -272,6 +287,7 @@ impl ConnectionBuilder {
/// Configures IPv4 for internet connection sharing.
///
/// The connection will provide DHCP and NAT for other devices.
#[must_use]
pub fn ipv4_shared(mut self) -> Self {
let mut ipv4 = HashMap::new();
ipv4.insert("method", Value::from("shared"));
Expand All @@ -282,6 +298,7 @@ impl ConnectionBuilder {
/// Sets IPv4 DNS servers.
///
/// DNS servers are specified as integers (network byte order).
#[must_use]
pub fn ipv4_dns(mut self, servers: Vec<Ipv4Addr>) -> Self {
let dns_u32: Vec<u32> = servers.into_iter().map(u32::from).collect();

Expand All @@ -292,6 +309,7 @@ impl ConnectionBuilder {
}

/// Sets the IPv4 gateway.
#[must_use]
pub fn ipv4_gateway(mut self, gateway: Ipv4Addr) -> Self {
if let Some(ipv4) = self.settings.get_mut("ipv4") {
ipv4.insert("gateway", Value::from(gateway.to_string()));
Expand All @@ -300,6 +318,7 @@ impl ConnectionBuilder {
}

/// Adds IPv4 static routes.
#[must_use]
pub fn ipv4_routes(mut self, routes: Vec<Route>) -> Self {
let route_data: Vec<HashMap<String, Value<'static>>> = routes
.into_iter()
Expand Down Expand Up @@ -327,6 +346,7 @@ impl ConnectionBuilder {
}

/// Configures IPv6 to use automatic configuration (SLAAC/DHCPv6).
#[must_use]
pub fn ipv6_auto(mut self) -> Self {
let mut ipv6 = HashMap::new();
ipv6.insert("method", Value::from("auto"));
Expand All @@ -335,6 +355,7 @@ impl ConnectionBuilder {
}

/// Configures IPv6 with manual (static) addresses.
#[must_use]
pub fn ipv6_manual(mut self, addresses: Vec<IpConfig>) -> Self {
let mut ipv6 = HashMap::new();
ipv6.insert("method", Value::from("manual"));
Expand All @@ -355,6 +376,7 @@ impl ConnectionBuilder {
}

/// Disables IPv6 for this connection.
#[must_use]
pub fn ipv6_ignore(mut self) -> Self {
let mut ipv6 = HashMap::new();
ipv6.insert("method", Value::from("ignore"));
Expand All @@ -363,6 +385,7 @@ impl ConnectionBuilder {
}

/// Configures IPv6 to use link-local addressing only.
#[must_use]
pub fn ipv6_link_local(mut self) -> Self {
let mut ipv6 = HashMap::new();
ipv6.insert("method", Value::from("link-local"));
Expand All @@ -371,6 +394,7 @@ impl ConnectionBuilder {
}

/// Sets IPv6 DNS servers.
#[must_use]
pub fn ipv6_dns(mut self, servers: Vec<Ipv6Addr>) -> Self {
let dns_strings: Vec<String> = servers.into_iter().map(|s| s.to_string()).collect();

Expand All @@ -381,6 +405,7 @@ impl ConnectionBuilder {
}

/// Sets the IPv6 gateway.
#[must_use]
pub fn ipv6_gateway(mut self, gateway: Ipv6Addr) -> Self {
if let Some(ipv6) = self.settings.get_mut("ipv6") {
ipv6.insert("gateway", Value::from(gateway.to_string()));
Expand All @@ -389,6 +414,7 @@ impl ConnectionBuilder {
}

/// Adds IPv6 static routes.
#[must_use]
pub fn ipv6_routes(mut self, routes: Vec<Route>) -> Self {
let route_data: Vec<HashMap<String, Value<'static>>> = routes
.into_iter()
Expand Down Expand Up @@ -435,6 +461,7 @@ impl ConnectionBuilder {
/// .with_section("bridge", bridge_section)
/// .build();
/// ```
#[must_use]
pub fn with_section(
mut self,
name: &'static str,
Expand Down Expand Up @@ -462,6 +489,7 @@ impl ConnectionBuilder {
/// })
/// .build();
/// ```
#[must_use]
pub fn update_section<F>(mut self, name: &'static str, f: F) -> Self
where
F: FnOnce(&mut HashMap<&'static str, Value<'static>>),
Expand All @@ -476,6 +504,7 @@ impl ConnectionBuilder {
///
/// This consumes the builder and returns the complete settings structure
/// ready to be passed to NetworkManager's D-Bus API.
#[must_use]
pub fn build(self) -> HashMap<&'static str, HashMap<&'static str, Value<'static>>> {
self.settings
}
Expand Down
2 changes: 2 additions & 0 deletions nmrs/src/api/builders/wifi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ use crate::api::models::{self, ConnectionOptions};
///
/// This function is maintained for backward compatibility. For new code,
/// consider using `WifiConnectionBuilder` for a more ergonomic API.
#[must_use]
pub fn build_wifi_connection(
ssid: &str,
security: &models::WifiSecurity,
Expand Down Expand Up @@ -91,6 +92,7 @@ pub fn build_wifi_connection(
///
/// This function is maintained for backward compatibility. For new code,
/// consider using `EthernetConnectionBuilder` for a more ergonomic API.
#[must_use]
pub fn build_ethernet_connection(
connection_id: &str,
opts: &ConnectionOptions,
Expand Down
Loading