macOS/iOS Implementation (IOKit/objc2)
Relevant source files
The following files were used as context for generating this wiki page:
The macOS and iOS implementation in the rust-battery project provides a specialized backend for retrieving battery telemetry on Apple platforms. This module leverages the IOKit framework and has recently migrated to use objc2 bindings (specifically objc2-io-kit and objc2-core-foundation) to interface with system-level power source information.
The implementation follows the project's standard platform abstraction, where IoKitManager, IoKitIterator, and IoKitDevice serve as the concrete types for Apple operating systems. It is designed to handle hardware-specific nuances, such as the difference between raw capacity values on Apple Silicon (M-series) chips versus Intel-based Macs.
Sources: src/platform/mod.rs:11-15, CHANGELOG.md:10-12, Cargo.toml:40-43
Architecture Overview
The Apple platform implementation is structured into a hierarchy that moves from low-level system wrappers to high-level battery device abstractions.
The diagram shows the flow of data from the system frameworks through internal data structures to the public trait implementations.
Sources: src/platform/darwin/iokit/power_source.rs, src/platform/darwin/device.rs:24-26, src/platform/darwin/traits.rs:11-13
Core Components
PowerSource and InstantData
The PowerSource struct is the primary internal handler for a specific battery. It contains an IoObject (a wrapper around IOKit objects) and a cached InstantData struct. InstantData represents a snapshot of the battery's state, parsed from a CFDictionary of properties provided by IOKit.
Key fields in InstantData include:
fully_charged: Boolean indicating if the battery is at 100%.voltage:ElectricPotentialmeasured in millivolts.amperage:ElectricCurrentmeasured in milliamperes.max_capacityandcurrent_capacity: Charge values in mAh.
Sources: src/platform/darwin/iokit/power_source.rs:33-50, src/platform/darwin/iokit/power_source.rs:136-144
Data Retrieval and Raw Values
A significant aspect of the Darwin implementation is the handling of Apple Silicon (M1/M2/M3) chips. On these devices, standard IOKit keys often return percentages (1-100) instead of actual milliampere-hours (mAh). To maintain accuracy, the implementation specifically looks for "Raw" keys.
| Key Constant | Description | Usage |
|---|---|---|
MAX_CAPACITY_KEY_RAW | AppleRawMaxCapacity | Used for accurate full capacity on M-series chips. |
CURRENT_CAPACITY_KEY_RAW | AppleRawCurrentCapacity | Used for accurate current charge on M-series chips. |
kIOPMPSMaxCapacityKey | MaxCapacity | Standard IOKit key; fallback if raw is unavailable. |
kIOPMPSVoltageKey | Voltage | Used for millivolt readings. |
Sources: src/platform/darwin/iokit/power_source.rs:26-31, src/platform/darwin/iokit/power_source.rs:55-83
Data Flow: Refreshing State
When a user calls refresh() on a battery device, the system follows a sequence to update the underlying data from IOKit.
The sequence shows how the device triggers a re-query of the IOKit property registry.
Sources: src/platform/darwin/device.rs:31-33, src/platform/darwin/iokit/power_source.rs:153-157
Implementation Details
Unit Conversions and Calculations
The IoKitDevice implements the BatteryDevice trait, which requires converting raw IOKit values into uom (Units of Measurement) types.
- Energy: Calculated as
current_capacity_raw * voltage. - Energy Rate: Calculated as
amperage * voltage. - State of Charge: Calculated as
current_capacity / max_capacity, bounded to the range0.0..=1.0. - Time Calculations:
time_to_fullandtime_to_emptyleverage thekIOPMPSTimeRemainingKey. If the value isi32::MAX, it is treated asNone(unavailable).
Sources: src/platform/darwin/device.rs:37-56, src/platform/darwin/iokit/power_source.rs:88-96
Battery State Mapping
The physical state of the battery is determined by combining several IOKit flags:
| logic Condition | Resulting State |
|---|---|
!external_connected() | Discharging |
is_charging() | Charging |
current_capacity().is_zero() | Empty |
fully_charged() | Full |
| Otherwise | Unknown |
Sources: src/platform/darwin/device.rs:58-66
Summary
The macOS/iOS implementation provides a robust interface to Apple's Power Source IOKit API. By migrating to objc2, the project ensures modern Rust compatibility while maintaining specific logic to handle the transition from Intel to Apple Silicon hardware. It prioritizes raw hardware values to provide accurate SI units for energy and charge metrics, abstracting the complexities of CoreFoundation and IOKit dictionaries away from the end user.