`portable-atomic` feature on `ratatui` does not forward to `ratatui-widgets`, breaking `no_std` builds on targets without atomic CAS
Description
When building ratatui for a target that lacks native atomic compare-and-swap (e.g. thumbv6m-none-eabi, the Cortex-M0+ core used on the RP2040), the portable-atomic feature on the top-level ratatui crate is insufficient. It forwards to ratatui-core, but not to ratatui-widgets, which still unconditionally imports alloc::sync::Arc in src/block/shadow.rs.
The alloc::sync module is gated behind #[cfg(target_has_atomic = "ptr")], so on these targets the import fails at compile time with:
error[E0432]: unresolved import `alloc::sync`
--> ratatui-widgets-0.3.2/src/block/shadow.rs:1:12
|
1 | use alloc::sync::Arc;
| ^^^^ could not find `sync` in `alloc`
Even adding portable-atomic to ratatui's feature list (as suggested by the ratatui book's embedded chapter) does not resolve this, because the feature is not forwarded to ratatui-widgets.
To Reproduce
Minimal Cargo.toml:
[package]
name = "repro"
version = "0.1.0"
edition = "2021"
[dependencies]
portable-atomic = { version = "1.15", features = ["critical-section"] }
ratatui = { version = "0.30.2", default-features = false, features = ["portable-atomic"] }
src/main.rs:
#![no_std]
#![no_main]
use ratatui::widgets::Block;
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
Build:
rustup target add thumbv6m-none-eabi
cargo build --target thumbv6m-none-eabi
Observe the unresolved import alloc::sync error from ratatui-widgets.
Expected behavior
Either:
The
portable-atomicfeature onratatuiforwards toratatui-widgets, andratatui-widgetsconditionally importsArcfromportable_atomic_utilwhen that feature is enabled. This matches howratatui-corealready handles the situation, and howtracing-coresolved the same problem (portable-atomicfeature switchesArc/Weakimports away fromalloc::sync).Or
ratatui-widgetsexposes its ownportable-atomicfeature, andratatui's feature forwards to it. This is the least intrusive change but requires two feature declarations.
Option 1 is preferable because it keeps the feature name consistent across the workspace.
Screenshots
N/A
Are you willing to contribute a fix?
- I am willing to open a PR for this bug.
- I can try to investigate, but I will need guidance.
- I am not able to work on a fix right now.
Environment
- OS: Linux (x86_64 host,
thumbv6m-none-eabitarget) - Terminal Emulator: N/A (embedded)
- Font: N/A
- Crate version:
ratatui0.30.2,ratatui-widgets0.3.2,ratatui-core0.1.2 - Backend:
mousefood0.5.2 (embedded-graphics backend)
Additional context
portable-atomicis already a transitive dependency, pulled in by bothratatui-coreandkasuari(throughratatui-widgets). The latter also has aportable-atomicfeature that is not forwarded fromratatui.- The
Arc<dyn CellEffect>field inShadowcomplicates a straightforward swap toportable_atomic_util::Arc, because that type cannot implementCoerceUnsizedon stable Rust. My local workaround replaced the field withBox<dyn CellEffect>and added aCellEffectClonesupertrait to preserveCloneonShadow(whichBlockderives). A cleaner upstream fix might useArc<dyn CellEffect>withportable_atomic_utilonno_stdtargets, at the cost of requiring nightly for theCoerceUnsizedimpl. Alternatively,CellEffectcould be given aclone_boxmethod andEffect::Customcould storeBox<dyn CellEffect>unconditionally, removing theArcrequirement entirely. - Related discussion: the Ratatui book's "Embedded" chapter suggests
ratatui = { features = ["portable-atomic"] }as the fix, but this is not sufficient in practice for the reason above.
Source: ratatui/ratatui