diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1c216d3a..4af7f0a98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -467,13 +467,13 @@ jobs: - name: no_std lint run: | - cargo clippy --target=thumbv7em-none-eabihf --no-default-features -p all-is-cubes -p all-is-cubes-render -p all-is-cubes-mesh + cargo clippy --target=thumbv7em-none-eabihf --no-default-features -p all-is-cubes -p all-is-cubes-render -p all-is-cubes-ui -p all-is-cubes-mesh - name: no_std build # This is `cargo build`, not `cargo check`, because `cargo check` won't detect problems like # use of undefined linker symbols. Not sure if that matters. run: | - cargo build --target=thumbv7em-none-eabihf --no-default-features -p all-is-cubes -p all-is-cubes-render -p all-is-cubes-mesh + cargo build --target=thumbv7em-none-eabihf --no-default-features -p all-is-cubes -p all-is-cubes-render -p all-is-cubes-ui -p all-is-cubes-mesh fuzz: # Don't spend time on fuzzing if the build failed indicating the code is bad other ways diff --git a/Cargo.lock b/Cargo.lock index d59c4123b..c516946b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -312,6 +312,7 @@ dependencies = [ "futures-util", "indoc", "log", + "num-traits", "pretty_assertions", "scopeguard", "sync_wrapper 1.0.1", diff --git a/all-is-cubes-content/Cargo.toml b/all-is-cubes-content/Cargo.toml index 4acb7df97..eadd2afef 100644 --- a/all-is-cubes-content/Cargo.toml +++ b/all-is-cubes-content/Cargo.toml @@ -12,7 +12,7 @@ categories = ["games"] keywords = ["all-is-cubes"] [package.metadata.docs.rs] -features = ["_full-documentation"] +features = ["arbitrary"] [lib] # Disable running as benchmark so that the default doesn't interfere with Criterion usage. @@ -25,12 +25,10 @@ harness = false [features] # Adds `UniverseTemplate::Random`. arbitrary = ["dep:arbitrary", "all-is-cubes/arbitrary"] -# Internal use only. Used to ensure that docs.rs builds have complete information; -# in particular, `all-is-cubes/std` would otherwise be missing, making types appear `!Sync`. -_full-documentation = ["all-is-cubes/std", "arbitrary"] [dependencies] -all-is-cubes = { workspace = true } +# std feature is required because this library does not yet participate in `maybe_sync`. +all-is-cubes = { workspace = true, features = ["std"] } all-is-cubes-ui = { workspace = true } arbitrary = { workspace = true, optional = true } exhaust = { workspace = true } @@ -39,9 +37,9 @@ hashbrown = { workspace = true } itertools = { workspace = true } log = { workspace = true } macro_rules_attribute = { workspace = true } -noise = { workspace = true } +noise = { workspace = true } # TODO: not no_std compatible (fixable) paste = { workspace = true } -petgraph = { workspace = true } +petgraph = { workspace = true } # TODO: not no_std compatible (might become so someday) rand = { workspace = true } rand_xoshiro = { workspace = true } strum = { workspace = true, features = ["derive"] } diff --git a/all-is-cubes-content/src/lib.rs b/all-is-cubes-content/src/lib.rs index 2c57f41d4..5413ebb63 100644 --- a/all-is-cubes-content/src/lib.rs +++ b/all-is-cubes-content/src/lib.rs @@ -7,6 +7,10 @@ //! provide [`UniverseTemplate`]; other items should be assumed not particularly //! stable. +// This crate is *almost* `no_std` compatible; critically, some dependencies are not. +// See comments in `Cargo.toml` for details. +// For now, the code is just in a state of “reveal how close it is”, hence using `core` and +// `alloc` imports only. #![no_std] // // Crate-specific lint settings. (General settings can be found in the workspace manifest.) diff --git a/all-is-cubes-desktop/Cargo.toml b/all-is-cubes-desktop/Cargo.toml index 168637f4e..574ba66e0 100644 --- a/all-is-cubes-desktop/Cargo.toml +++ b/all-is-cubes-desktop/Cargo.toml @@ -70,7 +70,7 @@ all-is-cubes-mesh = { workspace = true, optional = true, features = ["dynamic"] all-is-cubes-port = { workspace = true, features = ["import", "native"] } # TODO: make raytracer optional all-is-cubes-render = { workspace = true, features = ["raytracer"] } -all-is-cubes-ui = { workspace = true } +all-is-cubes-ui = { workspace = true, features = ["session"] } anyhow = { workspace = true } cfg-if = { workspace = true } clap = { workspace = true } diff --git a/all-is-cubes-port/Cargo.toml b/all-is-cubes-port/Cargo.toml index aa94c7689..1dbc71a85 100644 --- a/all-is-cubes-port/Cargo.toml +++ b/all-is-cubes-port/Cargo.toml @@ -57,7 +57,7 @@ dot-vox = [ [dependencies] # Non-optional generally required dependencies -# need all-is-cubes/std because we have boxed Send futures +# need all-is-cubes/std because we have boxed Send futures and errors all-is-cubes = { workspace = true, features = ["std"] } cfg-if = { workspace = true } futures-core = { workspace = true } diff --git a/all-is-cubes-ui/Cargo.toml b/all-is-cubes-ui/Cargo.toml index ed818496c..4e7c7e543 100644 --- a/all-is-cubes-ui/Cargo.toml +++ b/all-is-cubes-ui/Cargo.toml @@ -12,27 +12,41 @@ categories = ["games", "gui"] keywords = ["all-is-cubes", "voxel"] [package.metadata.docs.rs] -features = [] +features = ["session"] [lib] # Disable running as benchmark so that the default doesn't interfere with Criterion usage. bench = false +[features] +# Enable the `apps` and `notification` modules, particularly including the `Session` type, +# and require `std` support. +session = [ + "all-is-cubes/std", + "dep:async_fn_traits", + "dep:flume", + "dep:futures-core", + "dep:futures-task", + "dep:futures-util", + "dep:scopeguard", + "dep:sync_wrapper", +] + [dependencies] -# TODO: Disable default features. Requires more `maybe_sync` work. -all-is-cubes = { workspace = true, default-features = true } -all-is-cubes-render = { workspace = true, default-features = true } -async_fn_traits = { workspace = true } +all-is-cubes = { workspace = true, default-features = false } +all-is-cubes-render = { workspace = true, default-features = false } +async_fn_traits = { workspace = true, optional = true } displaydoc = { workspace = true } exhaust = { workspace = true } -flume = { workspace = true } -futures-core = { workspace = true } -futures-task = { workspace = true } -futures-util = { workspace = true } +flume = { workspace = true, optional = true } +futures-core = { workspace = true, optional = true } +futures-task = { workspace = true, optional = true } +futures-util = { workspace = true, optional = true } indoc = { workspace = true } log = { workspace = true } -scopeguard = { workspace = true } -sync_wrapper = { workspace = true } +num-traits = { workspace = true } +scopeguard = { workspace = true, optional = true } +sync_wrapper = { workspace = true, optional = true } [dev-dependencies] futures-channel = { workspace = true } diff --git a/all-is-cubes-ui/src/apps/input.rs b/all-is-cubes-ui/src/apps/input.rs index 7369d9aab..5102a4d97 100644 --- a/all-is-cubes-ui/src/apps/input.rs +++ b/all-is-cubes-ui/src/apps/input.rs @@ -3,6 +3,8 @@ reason = "module is private; https://github.com/rust-lang/rust-clippy/issues/8524" )] + +use alloc::vec::Vec; use core::time::Duration; use std::collections::{HashMap, HashSet}; diff --git a/all-is-cubes-ui/src/apps/session.rs b/all-is-cubes-ui/src/apps/session.rs index 139bf5583..de95ea1d4 100644 --- a/all-is-cubes-ui/src/apps/session.rs +++ b/all-is-cubes-ui/src/apps/session.rs @@ -3,6 +3,8 @@ reason = "module is private; https://github.com/rust-lang/rust-clippy/issues/8524" )] +use alloc::boxed::Box; +use alloc::string::ToString as _; use alloc::sync::{Arc, Weak}; use core::fmt; use core::future::Future; diff --git a/all-is-cubes-ui/src/editor.rs b/all-is-cubes-ui/src/editor.rs index fe6ea5d59..64fc8bd1a 100644 --- a/all-is-cubes-ui/src/editor.rs +++ b/all-is-cubes-ui/src/editor.rs @@ -1,13 +1,15 @@ //! VUI components related to allowing the user to inspect universe contents. -use all_is_cubes::universe::Handle; use alloc::sync::Arc; +use alloc::vec; +use alloc::vec::Vec; use all_is_cubes::arcstr::{self, literal, ArcStr}; use all_is_cubes::block::{self, Block}; use all_is_cubes::character::Cursor; use all_is_cubes::euclid::size3; use all_is_cubes::math::Face6; +use all_is_cubes::universe::Handle; use crate::ui_content::hud::HudInputs; use crate::ui_content::pages::back_button; diff --git a/all-is-cubes-ui/src/inv_watch.rs b/all-is-cubes-ui/src/inv_watch.rs index 9fb90ed0f..9a025e636 100644 --- a/all-is-cubes-ui/src/inv_watch.rs +++ b/all-is-cubes-ui/src/inv_watch.rs @@ -4,7 +4,7 @@ //! "derived information from a `ListenableSource` that requires computation" and should become //! general code that handles the re-listening problem. -use std::sync::Arc; +use alloc::sync::Arc; use all_is_cubes::character::{Character, CharacterChange}; use all_is_cubes::inv::{Inventory, TOOL_SELECTIONS}; diff --git a/all-is-cubes-ui/src/lib.rs b/all-is-cubes-ui/src/lib.rs index 18280a0c9..8964046a4 100644 --- a/all-is-cubes-ui/src/lib.rs +++ b/all-is-cubes-ui/src/lib.rs @@ -18,21 +18,29 @@ //! [`Space`]: all_is_cubes::space::Space //! [`Universe`]: all_is_cubes::universe::Universe -// This crate is not `no_std` because it currently uses `std::sync::mpsc`. - +#![no_std] // Crate-specific lint settings. (General settings can be found in the workspace manifest.) #![forbid(unsafe_code)] extern crate alloc; +#[cfg(any(test, feature = "session"))] +#[macro_use] +extern crate std; + +#[cfg(feature = "session")] mod editor; +#[cfg(feature = "session")] mod inv_watch; +#[cfg(feature = "session")] pub mod apps; pub mod logo; +#[cfg(feature = "session")] mod ui_content; +#[cfg(feature = "session")] pub use ui_content::notification; pub mod vui; diff --git a/all-is-cubes-ui/src/ui_content/notification.rs b/all-is-cubes-ui/src/ui_content/notification.rs index 696ba6a33..9cca6a527 100644 --- a/all-is-cubes-ui/src/ui_content/notification.rs +++ b/all-is-cubes-ui/src/ui_content/notification.rs @@ -1,6 +1,7 @@ //! Types used to create notifications displayed to the user. use alloc::sync::{Arc, Weak}; +use alloc::vec::Vec; use std::sync::Mutex; use all_is_cubes::listen; diff --git a/all-is-cubes-ui/src/ui_content/options.rs b/all-is-cubes-ui/src/ui_content/options.rs index 377de87bd..36cf1cef1 100644 --- a/all-is-cubes-ui/src/ui_content/options.rs +++ b/all-is-cubes-ui/src/ui_content/options.rs @@ -1,4 +1,6 @@ +use alloc::boxed::Box; use alloc::sync::Arc; +use alloc::vec::Vec; use core::fmt; use all_is_cubes::arcstr::{self, literal}; diff --git a/all-is-cubes-ui/src/ui_content/pages.rs b/all-is-cubes-ui/src/ui_content/pages.rs index 44fbd940c..b1984bb34 100644 --- a/all-is-cubes-ui/src/ui_content/pages.rs +++ b/all-is-cubes-ui/src/ui_content/pages.rs @@ -1,5 +1,6 @@ //! Contents of various UI pages. +use alloc::string::String; use alloc::sync::Arc; use all_is_cubes::arcstr::{literal, ArcStr}; diff --git a/all-is-cubes-ui/src/ui_content/vui_manager.rs b/all-is-cubes-ui/src/ui_content/vui_manager.rs index 83eded86a..3f080ae60 100644 --- a/all-is-cubes-ui/src/ui_content/vui_manager.rs +++ b/all-is-cubes-ui/src/ui_content/vui_manager.rs @@ -1,3 +1,4 @@ +use alloc::string::{String, ToString as _}; use alloc::sync::Arc; use core::future::Future; use flume::TryRecvError; diff --git a/all-is-cubes-ui/src/vui/layout.rs b/all-is-cubes-ui/src/vui/layout.rs index 55432e4bd..1b356bd89 100644 --- a/all-is-cubes-ui/src/vui/layout.rs +++ b/all-is-cubes-ui/src/vui/layout.rs @@ -3,8 +3,11 @@ reason = "module is private; https://github.com/rust-lang/rust-clippy/issues/8524" )] +use alloc::boxed::Box; use alloc::rc::Rc; use alloc::sync::Arc; +use alloc::vec; +use alloc::vec::Vec; use core::fmt; use all_is_cubes::euclid::{self, size3, Size3D, Vector3D}; diff --git a/all-is-cubes-ui/src/vui/mod.rs b/all-is-cubes-ui/src/vui/mod.rs index aedf378ce..01b77de22 100644 --- a/all-is-cubes-ui/src/vui/mod.rs +++ b/all-is-cubes-ui/src/vui/mod.rs @@ -6,10 +6,13 @@ #[doc(hidden)] // public for use by test-renderers only pub mod blocks; +#[cfg(feature = "session")] pub(crate) use blocks::UiBlocks; mod layout; pub use layout::*; +#[cfg(feature = "session")] mod page; +#[cfg(feature = "session")] pub(crate) use page::*; mod widget_trait; pub use widget_trait::*; diff --git a/all-is-cubes-ui/src/vui/page.rs b/all-is-cubes-ui/src/vui/page.rs index 84597ca78..9eea84931 100644 --- a/all-is-cubes-ui/src/vui/page.rs +++ b/all-is-cubes-ui/src/vui/page.rs @@ -1,4 +1,5 @@ use alloc::sync::Arc; +use alloc::vec; use all_is_cubes::arcstr::ArcStr; use all_is_cubes::block::{text, AIR}; @@ -336,6 +337,7 @@ pub(crate) mod parts { #[cfg(test)] mod tests { use super::*; + use alloc::vec::Vec; #[test] fn ui_size() { diff --git a/all-is-cubes-ui/src/vui/widget_trait.rs b/all-is-cubes-ui/src/vui/widget_trait.rs index 32b3b7a6f..d502cf91f 100644 --- a/all-is-cubes-ui/src/vui/widget_trait.rs +++ b/all-is-cubes-ui/src/vui/widget_trait.rs @@ -1,17 +1,17 @@ //! UI [`Widget`] trait and related glue. use all_is_cubes::time::Tick; +use alloc::boxed::Box; use alloc::sync::Arc; use core::error::Error; use core::fmt::Debug; -use std::sync::Mutex; use all_is_cubes::behavior::{self, Behavior}; use all_is_cubes::math::GridAab; use all_is_cubes::space::{self, Space, SpaceTransaction}; use all_is_cubes::transaction::{self, Merge as _}; use all_is_cubes::universe::{HandleVisitor, UniverseTransaction, VisitHandles}; -use all_is_cubes::util::maybe_sync::SendSyncIfStd; +use all_is_cubes::util::maybe_sync::{self, SendSyncIfStd}; // reused for WidgetController pub use all_is_cubes::behavior::Then; @@ -113,7 +113,9 @@ pub type StepSuccess = (WidgetTransaction, Then); /// Error return of [`WidgetController::step()`]. /// /// TODO: This should become a more specific error type. -pub type StepError = Box; +//--- +// This is a type alias to cope with the maybe-Sync kludge without exposing that everywhere. +pub type StepError = maybe_sync::BoxError; impl WidgetController for Box { fn step(&mut self, context: &WidgetContext<'_>) -> Result { @@ -137,7 +139,7 @@ impl WidgetController for Box { pub(super) struct WidgetBehavior { /// Original widget -- not used directly but for error reporting widget: Positioned>, - controller: Mutex>, + controller: maybe_sync::Mutex>, } impl WidgetBehavior { @@ -164,7 +166,7 @@ impl WidgetBehavior { space::SpaceBehaviorAttachment::new(widget.position.bounds), Arc::new(WidgetBehavior { widget, - controller: Mutex::new(controller), + controller: maybe_sync::Mutex::new(controller), }), ); init_txn @@ -325,11 +327,11 @@ pub(crate) fn instantiate_widget( #[cfg(test)] mod tests { use super::*; - use all_is_cubes::util::assert_send_sync; + use all_is_cubes::util::assert_conditional_send_sync; #[test] fn error_is_send_sync() { - assert_send_sync::() + assert_conditional_send_sync::() } fn _assert_widget_trait_is_object_safe(_: &dyn Widget) {} diff --git a/all-is-cubes-ui/src/vui/widgets/button.rs b/all-is-cubes-ui/src/vui/widgets/button.rs index 9f4c6be9d..a819119bf 100644 --- a/all-is-cubes-ui/src/vui/widgets/button.rs +++ b/all-is-cubes-ui/src/vui/widgets/button.rs @@ -3,6 +3,9 @@ reason = "module is private; https://github.com/rust-lang/rust-clippy/issues/8524" )] +use alloc::borrow::ToOwned as _; +use alloc::boxed::Box; +use alloc::format; use alloc::sync::Arc; use core::fmt; use core::hash::Hash; @@ -549,7 +552,7 @@ mod theme { /// Build a [`Block`] for [`ButtonBase`]. pub fn common_block(space: Handle, name: &str) -> Block { Block::builder() - .display_name(name.to_string()) + .display_name(name) .voxels_handle(MULTI_RESOLUTION, space) .animation_hint(block::AnimationHint::replacement( block::AnimationChange::Shape, diff --git a/all-is-cubes-ui/src/vui/widgets/crosshair.rs b/all-is-cubes-ui/src/vui/widgets/crosshair.rs index 38cf80fbf..4535589c0 100644 --- a/all-is-cubes-ui/src/vui/widgets/crosshair.rs +++ b/all-is-cubes-ui/src/vui/widgets/crosshair.rs @@ -1,3 +1,4 @@ +use alloc::boxed::Box; use alloc::sync::Arc; use all_is_cubes::block::{Block, AIR}; diff --git a/all-is-cubes-ui/src/vui/widgets/debug.rs b/all-is-cubes-ui/src/vui/widgets/debug.rs index 28fe48a85..290cd0fde 100644 --- a/all-is-cubes-ui/src/vui/widgets/debug.rs +++ b/all-is-cubes-ui/src/vui/widgets/debug.rs @@ -1,3 +1,4 @@ +use alloc::boxed::Box; use alloc::sync::Arc; use all_is_cubes::block::{self, text, Block, Resolution::R64}; diff --git a/all-is-cubes-ui/src/vui/widgets/frame.rs b/all-is-cubes-ui/src/vui/widgets/frame.rs index cd0546ea3..f8e53f41d 100644 --- a/all-is-cubes-ui/src/vui/widgets/frame.rs +++ b/all-is-cubes-ui/src/vui/widgets/frame.rs @@ -1,4 +1,6 @@ +use alloc::boxed::Box; use alloc::sync::Arc; +use alloc::vec; use all_is_cubes::block::Block; use all_is_cubes::euclid::size3; diff --git a/all-is-cubes-ui/src/vui/widgets/mod.rs b/all-is-cubes-ui/src/vui/widgets/mod.rs index 03eb1b379..6efe9edb9 100644 --- a/all-is-cubes-ui/src/vui/widgets/mod.rs +++ b/all-is-cubes-ui/src/vui/widgets/mod.rs @@ -1,5 +1,6 @@ //! Specific UI widgets. +use alloc::boxed::Box; use alloc::sync::Arc; use all_is_cubes::block::Block; @@ -8,7 +9,9 @@ use all_is_cubes::space::SpaceTransaction; use crate::vui; +#[cfg(feature = "session")] mod crosshair; +#[cfg(feature = "session")] pub(crate) use crosshair::*; mod frame; pub use frame::*; @@ -22,9 +25,13 @@ mod progress_bar; pub use progress_bar::*; mod theme; pub use theme::*; +#[cfg(feature = "session")] mod toolbar; +#[cfg(feature = "session")] pub(crate) use toolbar::*; +#[cfg(feature = "session")] mod tooltip; +#[cfg(feature = "session")] pub(crate) use tooltip::*; mod voxels; pub use voxels::*; diff --git a/all-is-cubes-ui/src/vui/widgets/progress_bar.rs b/all-is-cubes-ui/src/vui/widgets/progress_bar.rs index 8496f4885..1f230c427 100644 --- a/all-is-cubes-ui/src/vui/widgets/progress_bar.rs +++ b/all-is-cubes-ui/src/vui/widgets/progress_bar.rs @@ -3,7 +3,13 @@ reason = "module is private; https://github.com/rust-lang/rust-clippy/issues/8524" )] -use std::sync::Arc; +use alloc::boxed::Box; +use alloc::sync::Arc; + +/// Acts as polyfill for float methods +#[cfg(not(feature = "session"))] +#[allow(unused_imports)] +use num_traits::float::FloatCore as _; use all_is_cubes::block::{self, Block, Composite, CompositeOperator, AIR}; use all_is_cubes::color_block; @@ -208,6 +214,8 @@ mod tests { use all_is_cubes::transaction::Transaction as _; use all_is_cubes::util::yield_progress_for_testing; use all_is_cubes::{transaction, universe}; + use alloc::string::String; + use alloc::vec::Vec; #[tokio::test] async fn progress_output() { diff --git a/all-is-cubes-ui/src/vui/widgets/text.rs b/all-is-cubes-ui/src/vui/widgets/text.rs index 1a9d5710d..c524979f4 100644 --- a/all-is-cubes-ui/src/vui/widgets/text.rs +++ b/all-is-cubes-ui/src/vui/widgets/text.rs @@ -3,6 +3,7 @@ reason = "module is private; https://github.com/rust-lang/rust-clippy/issues/8524" )] +use alloc::boxed::Box; use alloc::sync::Arc; use all_is_cubes::arcstr::ArcStr; @@ -114,6 +115,7 @@ impl Label { /// Constructs a [`Label`] that draws the given text, with a specified font. //--- // TODO: undecided what's a good API + #[cfg_attr(not(feature = "session"), expect(dead_code))] pub(crate) fn with_font( string: ArcStr, font: text::Font, diff --git a/all-is-cubes-ui/src/vui/widgets/theme.rs b/all-is-cubes-ui/src/vui/widgets/theme.rs index 2228a0d95..6380b6dfb 100644 --- a/all-is-cubes-ui/src/vui/widgets/theme.rs +++ b/all-is-cubes-ui/src/vui/widgets/theme.rs @@ -3,8 +3,9 @@ reason = "module is private; https://github.com/rust-lang/rust-clippy/issues/8524" )] +use alloc::format; +use alloc::sync::Arc; use core::fmt; -use std::sync::Arc; use exhaust::Exhaust; @@ -207,16 +208,18 @@ impl WidgetBlocks { } WidgetBlocks::ProgressBar { full } => { + let image = if full { + include_image!("theme/progress-bar-full.png") + } else { + include_image!("theme/progress-bar-empty.png") + }; + Block::builder() .display_name(format! {"Progress Bar {}", if full {"Full"} else {"Empty"}}) .voxels_handle( R64, // 16 res × 4 tiles txn.insert_anonymous(space_from_image( - if full { - include_image!("theme/progress-bar-full.png") - } else { - include_image!("theme/progress-bar-empty.png") - }, + image, GridRotation::IDENTITY, &default_srgb, )?), diff --git a/all-is-cubes-ui/src/vui/widgets/toolbar.rs b/all-is-cubes-ui/src/vui/widgets/toolbar.rs index b53f8156b..c8945811c 100644 --- a/all-is-cubes-ui/src/vui/widgets/toolbar.rs +++ b/all-is-cubes-ui/src/vui/widgets/toolbar.rs @@ -1,3 +1,4 @@ +use alloc::boxed::Box; use alloc::sync::{Arc, Weak}; use core::error::Error; use core::fmt; diff --git a/all-is-cubes-ui/src/vui/widgets/tooltip.rs b/all-is-cubes-ui/src/vui/widgets/tooltip.rs index 9ddabc9d4..eb3ba1b74 100644 --- a/all-is-cubes-ui/src/vui/widgets/tooltip.rs +++ b/all-is-cubes-ui/src/vui/widgets/tooltip.rs @@ -1,3 +1,4 @@ +use alloc::boxed::Box; use alloc::sync::Arc; use std::sync::Mutex; diff --git a/all-is-cubes-ui/src/vui/widgets/voxels.rs b/all-is-cubes-ui/src/vui/widgets/voxels.rs index 53ba816ab..47a37ebb7 100644 --- a/all-is-cubes-ui/src/vui/widgets/voxels.rs +++ b/all-is-cubes-ui/src/vui/widgets/voxels.rs @@ -1,4 +1,6 @@ +use alloc::boxed::Box; use alloc::sync::Arc; +use alloc::vec::Vec; use all_is_cubes::block::{self, Block, Primitive, Resolution}; use all_is_cubes::euclid::Size3D; diff --git a/all-is-cubes-wasm/Cargo.lock b/all-is-cubes-wasm/Cargo.lock index ae819710f..d5ffddbeb 100644 --- a/all-is-cubes-wasm/Cargo.lock +++ b/all-is-cubes-wasm/Cargo.lock @@ -204,6 +204,7 @@ dependencies = [ "futures-util", "indoc", "log", + "num-traits", "scopeguard", "sync_wrapper", ] diff --git a/all-is-cubes-wasm/Cargo.toml b/all-is-cubes-wasm/Cargo.toml index e2ff7eb68..1f91523c2 100644 --- a/all-is-cubes-wasm/Cargo.toml +++ b/all-is-cubes-wasm/Cargo.toml @@ -32,7 +32,7 @@ all-is-cubes-content = { path = "../all-is-cubes-content", version = "0.8.0" } all-is-cubes-gpu = { path = "../all-is-cubes-gpu", version = "0.8.0", features = ["wgpu"] } all-is-cubes-port = { path = "../all-is-cubes-port", version = "0.8.0", features = ["import", "all-formats"] } all-is-cubes-render = { path = "../all-is-cubes-render", version = "0.8.0" } -all-is-cubes-ui = { path = "../all-is-cubes-ui", version = "0.8.0" } +all-is-cubes-ui = { path = "../all-is-cubes-ui", version = "0.8.0", features = ["session"] } console_log = "1.0.0" console_error_panic_hook = "0.1.5" form_urlencoded = "1.0.1" diff --git a/all-is-cubes/src/linking.rs b/all-is-cubes/src/linking.rs index e49ef58e4..08e7d3201 100644 --- a/all-is-cubes/src/linking.rs +++ b/all-is-cubes/src/linking.rs @@ -22,6 +22,7 @@ use crate::block::{Block, BlockDef}; use crate::space::{SetCubeError, SpaceTransaction}; use crate::transaction::ExecuteError; use crate::universe::{Handle, InsertError, Name, Universe, UniverseTransaction}; +use crate::util::maybe_sync; use crate::util::YieldProgress; #[cfg(doc)] @@ -395,10 +396,10 @@ impl From> for GenError { #[non_exhaustive] pub enum InGenError { /// Generic error container for unusual situations. - Other(Box), + Other(maybe_sync::BoxError), /// Something else needed to be generated and that failed. - Gen(Box), + Gen(Box), // boxed due to being a recursive type /// Failed to insert the generated items in the [`Universe`]. Insert(InsertError), @@ -420,7 +421,7 @@ pub enum InGenError { impl InGenError { /// Convert an arbitrary error to `InGenError`. #[cfg_attr(not(feature = "std"), doc(hidden))] - pub fn other(error: E) -> Self { + pub fn other(error: E) -> Self { Self::Other(Box::new(error)) } } @@ -492,7 +493,7 @@ mod tests { use crate::content::make_some_blocks; use crate::math::GridAab; use crate::transaction::Transactional as _; - use crate::util::assert_send_sync; + use crate::util::assert_conditional_send_sync; #[derive(Exhaust, Clone, Debug, Eq, Hash, PartialEq)] enum Key { @@ -570,8 +571,8 @@ mod tests { #[test] fn errors_are_send_sync() { - assert_send_sync::(); - assert_send_sync::(); + assert_conditional_send_sync::(); + assert_conditional_send_sync::(); } #[test] diff --git a/all-is-cubes/src/util/maybe_sync.rs b/all-is-cubes/src/util/maybe_sync.rs index 8c5a6cb27..4539791d2 100644 --- a/all-is-cubes/src/util/maybe_sync.rs +++ b/all-is-cubes/src/util/maybe_sync.rs @@ -1,24 +1,38 @@ +use alloc::boxed::Box; +use core::error::Error; use core::{fmt, ops}; cfg_if::cfg_if! { if #[cfg(feature = "std")] { pub trait SendSyncIfStd: Send + Sync {} impl SendSyncIfStd for T {} + + /// This type alias for a boxed [`Future`] requires `Send` if the `std` feature is + /// enabled. + pub(crate) type MaybeLocalBoxFuture<'a, T> = futures_core::future::BoxFuture<'a, T>; + + /// This type alias for a boxed [`Error`] requires `Send + Sync` if the `std` feature is + /// enabled. + #[doc(hidden)] + pub type BoxError = Box; } else { pub trait SendSyncIfStd {} impl SendSyncIfStd for T {} + + /// This type alias for a boxed [`Future`] requires `Send` if the `std` feature is + /// enabled. + pub(crate) type MaybeLocalBoxFuture<'a, T> = futures_core::future::LocalBoxFuture<'a, T>; + + /// This type alias for a boxed [`Error`] requires `Send + Sync` if the `std` feature is + /// enabled. + #[doc(hidden)] + pub type BoxError = Box; } } cfg_if::cfg_if! { if #[cfg(feature = "std")] { - /// This type alias for a boxed future requires `Sync` if the `std` feature is - /// enabled. - pub(crate) type MaybeLocalBoxFuture<'a, T> = futures_core::future::BoxFuture<'a, T>; } else { - /// This type alias for a boxed future requires `Sync` if the `std` feature is - /// enabled. - pub(crate) type MaybeLocalBoxFuture<'a, T> = futures_core::future::LocalBoxFuture<'a, T>; } } @@ -31,9 +45,10 @@ cfg_if::cfg_if! { /// * This may or may not implement mutex poisoning. /// * This may or may not deadlock if locked again from the same thread. #[derive(Default)] -pub(crate) struct Mutex(InnerMutex); +pub struct Mutex(InnerMutex); -pub(crate) struct MutexGuard<'a, T>(InnerMutexGuard<'a, T>); +#[allow(missing_debug_implementations)] +pub struct MutexGuard<'a, T>(InnerMutexGuard<'a, T>); /// Wrapper around [`core::cell::RefCell`] or [`std::sync::RwLock`] depending on whether /// the `std` feature is enabled. @@ -196,11 +211,8 @@ impl ops::DerefMut for RwLockWriteGuard<'_, T> { } } -pub(crate) enum LockError { - #[cfg_attr( - not(feature = "std"), - expect(dead_code, reason = "no poisoning from RefCell") - )] +#[allow(clippy::exhaustive_enums)] +pub enum LockError { Poisoned(G), } @@ -213,7 +225,7 @@ impl LockError { // } } -impl core::error::Error for LockError {} +impl Error for LockError {} impl fmt::Display for LockError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -240,7 +252,7 @@ pub(crate) enum TryLockError { WouldBlock, } -impl core::error::Error for TryLockError {} +impl Error for TryLockError {} impl fmt::Display for TryLockError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/test-renderers/Cargo.toml b/test-renderers/Cargo.toml index 58d2a1bdb..57593b498 100644 --- a/test-renderers/Cargo.toml +++ b/test-renderers/Cargo.toml @@ -70,7 +70,7 @@ all-is-cubes-gpu = { workspace = true, features = ["wgpu"] } # used only for gltf export+render tests all-is-cubes-port = { workspace = true, optional = true, features = ["export", "gltf"] } all-is-cubes-render = { workspace = true, features = ["raytracer", "std"] } -all-is-cubes-ui = { workspace = true } +all-is-cubes-ui = { workspace = true, features = ["session"] } async_fn_traits = { workspace = true } bytemuck = { workspace = true, optional = true } # Using clap for parsing test command-line arguments diff --git a/tools/xtask/src/xtask.rs b/tools/xtask/src/xtask.rs index 166e44742..4772695f7 100644 --- a/tools/xtask/src/xtask.rs +++ b/tools/xtask/src/xtask.rs @@ -648,13 +648,22 @@ fn do_for_all_packages( } { - // Check `all-is-cubes` with default features disabled, because that's - // more easily broken by accident (such as by introducing an unintended + // Check no_std compatiblepackages with default features disabled, because + // that's more easily broken by accident (such as by introducing an unintended // `Send` bound) then our other features. + // + // TODO: Replace this one-off list of packages with something more centralized, + // and shared with the CI that actually builds a no_std target. let _t = CaptureTime::new(time_log, "check aic no_std"); cargo() .arg(op.non_build_check_subcmd()) - .args(["--package=all-is-cubes", "--no-default-features"]) + .args([ + "--package=all-is-cubes", + "--package=all-is-cubes-mesh", + "--package=all-is-cubes-render", + "--package=all-is-cubes-ui", + "--no-default-features", + ]) .run()?; } }