Platform Traits & Extensibility
Relevant source files
The following files were used as context for generating this wiki page:
The rust-battery crate employs a trait-based abstraction layer to provide a unified, cross-platform API for accessing battery information. By defining a set of core traits, the library decouples the high-level representation of battery data from the low-level, OS-specific implementation details. This architecture allows the library to support diverse operating systems including Linux, macOS, Windows, and various BSD flavors while exposing a consistent interface to the end user.
The extensibility of the system is rooted in the platform module, which uses conditional compilation to alias platform-specific types (e.g., SysFsManager, IoKitManager, PowerManager) to common type names like Manager, Iterator, and Device. Each platform-specific implementation must adhere to the behavioral contracts defined in the platform traits to ensure interoperability.
Sources: src/platform/traits.rs, src/platform/mod.rs:1-33, src/lib.rs:1-15
Core Platform Traits
The library defines three primary traits that every platform implementation must satisfy: BatteryManager, BatteryIterator, and BatteryDevice. These traits define how the system interacts with the underlying hardware or OS subsystems to discover, iterate, and query power sources.
BatteryManager Trait
The BatteryManager is the entry point for battery discovery. It is responsible for initializing the platform-specific backend and providing a mechanism to refresh existing battery data.
| Method | Description |
|---|---|
new() | Initializes the platform-specific manager. Returns a Result<Self>. |
refresh(&self, battery) | Updates the state of a specific BatteryDevice in-place. |
Sources: src/platform/traits.rs:13-19
BatteryIterator Trait
The BatteryIterator bridges the manager and individual devices. It is required to preload battery data during the iteration process (next()) because the subsequent BatteryDevice methods are designed to be infallible.
Sources: src/platform/traits.rs:21-32
BatteryDevice Trait
This trait defines the data accessors for battery properties. While platforms must implement the raw data retrieval methods, the trait provides default implementations for calculated metrics like state_of_health and time_to_full.
The diagram above illustrates the relationship between raw data requirements and derived calculations provided by the trait.
Sources: src/platform/traits.rs:35-115
Cross-Platform Type Mapping
The src/platform/mod.rs file acts as a central registry that maps platform-specific implementations to generic type aliases using cfg_if!. This allows the rest of the crate to use platform::Manager or platform::Device without concern for the target OS.
| Target OS | Manager Implementation | Device Implementation | Data Source |
|---|---|---|---|
| Linux | linux::SysFsManager | linux::SysFsDevice | Sysfs (/sys/class/power_supply) |
| macOS/iOS | darwin::IoKitManager | darwin::IoKitDevice | IOKit Framework |
| Windows | windows::PowerManager | windows::PowerDevice | Win32 Power API / IOCTL |
| NetBSD | netbsd::SysMonManager | netbsd::SysMonDevice | Envsys / Sysmon |
| FreeBSD | freebsd::IoCtlManager | freebsd::IoCtlDevice | ACPI IOCTL (/dev/acpi) |
Sources: src/platform/mod.rs:1-33, src/platform/linux/device.rs:13-17, src/platform/windows/device.rs:13-28, src/platform/netbsd/device.rs:125-144
Derived Metrics Logic
A key feature of the extensibility model is the provision of default logic for complex battery metrics within BatteryDevice. This ensures that even if an OS only provides raw energy and rate data, the library can calculate consistent values for the user.
State of Charge & Health
The trait calculates health and charge by bounding the ratios between current, full, and design energy values to a range of 0.0..=1.0.
- State of Health:
energy_full / energy_full_design - State of Charge:
energy / energy_full
Sources: src/platform/traits.rs:36-46
Time Calculations
The time_to_full and time_to_empty methods use the current energy_rate and the remaining energy capacity. The implementation includes safety checks, such as ignoring zero rates to prevent division by zero and capping results at 10 hours (for charging) or 10 days (for discharging) to filter out unrealistic driver data.
Diagram shows the logic for calculating time until the battery is fully charged.
Sources: src/platform/traits.rs:77-101
Platform Implementation Examples
Linux (Sysfs)
The Linux implementation uses a DataBuilder to aggregate values from various files in /sys/class/power_supply/. It specifically filters for devices where type is "Battery" and scope is "System".
Sources: src/platform/linux/device.rs:24-34
Windows (IOCTL)
The Windows implementation relies on DeviceHandle to perform IOCTL queries. It retrieves a BATTERY_INFORMATION struct and converts raw milliwatt-hour values into the crate's internal Energy types.
Sources: src/platform/windows/device.rs:56-83
macOS (Darwin Traits)
Darwin provides a specialized DataSource trait in src/platform/darwin/traits.rs that maps directly to Apple's IOPMPowerSource keys (e.g., kIOPMPSExternalConnectedKey).
Sources: src/platform/darwin/traits.rs:11-38
Summary
The platform traits and extensibility architecture of rust-battery allow the project to maintain a unified interface while handling the significant variations in how different operating systems expose battery hardware. By providing default implementations for calculations like state_of_health and time_to_full within the BatteryDevice trait, the library ensures consistent behavior across all supported platforms with minimal duplicated logic.
Sources: src/platform/traits.rs, src/platform/mod.rs