From 2dfc4af2ba1a7c65d9ce4ba27c33299e85dc3c23 Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Tue, 19 Nov 2019 14:45:13 +0100 Subject: [PATCH] Implement initial support for no_std This implements initial support for no_std. Modules such as parsing, saving and rendering are disabled and timing has to be manually provided by registering a global handler. The rendering module is on its way to no_std support as well, but not all Pull Requests to the necessary dependencies are done yet. See #223 for more information. --- .github/workflows/build_shared.sh | 2 +- .github/workflows/build_static.sh | 13 +- .github/workflows/rust.yml | 166 +++++++++++++++++- Cargo.toml | 47 +++-- crates/livesplit-hotkey/Cargo.toml | 23 ++- crates/livesplit-hotkey/src/lib.rs | 61 +++---- crates/livesplit-hotkey/src/other/mod.rs | 2 +- .../livesplit-title-abbreviations/Cargo.toml | 2 +- .../livesplit-title-abbreviations/src/lib.rs | 5 +- crates/no-std-test/Cargo.toml | 15 ++ crates/no-std-test/README.md | 6 + crates/no-std-test/src/lib.rs | 1 + src/analysis/pb_chance/mod.rs | 1 + src/analysis/sum_of_segments/mod.rs | 1 + src/comparison/balanced_pb.rs | 1 + src/comparison/best_segments.rs | 1 + src/comparison/goal.rs | 1 + src/comparison/median_segments.rs | 1 + src/comparison/mod.rs | 3 +- src/comparison/worst_segments.rs | 1 + src/component/blank_space.rs | 10 +- src/component/current_comparison.rs | 1 + src/component/current_pace.rs | 3 +- src/component/delta/mod.rs | 3 +- src/component/detailed_timer/mod.rs | 10 +- src/component/graph.rs | 12 +- src/component/key_value.rs | 12 +- src/component/pb_chance.rs | 1 + src/component/possible_time_save.rs | 5 +- src/component/previous_segment.rs | 5 +- src/component/separator.rs | 9 +- src/component/splits/column.rs | 1 + src/component/splits/mod.rs | 12 +- src/component/sum_of_best.rs | 1 + src/component/text.rs | 14 +- src/component/timer.rs | 13 +- src/component/title/mod.rs | 10 +- src/component/total_playtime.rs | 1 + src/hotkey_config.rs | 13 +- src/hotkey_system.rs | 4 +- src/layout/component.rs | 3 +- src/layout/component_settings.rs | 1 + src/layout/component_state.rs | 1 + src/layout/editor/mod.rs | 2 +- src/layout/editor/state.rs | 10 +- src/layout/general_settings.rs | 1 + src/layout/layout_settings.rs | 16 +- src/layout/layout_state.rs | 10 +- src/layout/mod.rs | 2 + src/layout/parser.rs | 8 +- src/lib.rs | 38 ++-- src/platform/mod.rs | 28 ++- src/platform/no_std/indexmap.rs | 127 ++++++++++++++ src/platform/no_std/mod.rs | 3 + src/platform/no_std/time.rs | 159 +++++++++++++++++ src/platform/normal/mod.rs | 6 +- src/platform/wasm/mod.rs | 6 +- src/platform/wasm/time.rs | 4 +- src/rendering/software/mod.rs | 2 +- src/run/editor/cleaning.rs | 7 +- src/run/editor/fuzzy_list.rs | 5 +- src/run/editor/mod.rs | 11 +- src/run/editor/state.rs | 10 +- src/run/mod.rs | 13 +- src/run/parser/composite.rs | 2 +- src/run/parser/face_split.rs | 6 +- src/run/parser/flitter/mod.rs | 2 +- src/run/parser/flitter/s_expressions.rs | 6 +- src/run/parser/livesplit.rs | 12 +- src/run/parser/llanfair.rs | 4 +- src/run/parser/llanfair2.rs | 10 +- src/run/parser/llanfair_gered.rs | 8 +- src/run/parser/portal2_live_timer.rs | 4 +- src/run/parser/shit_split.rs | 4 +- src/run/parser/source_live_timer.rs | 2 +- src/run/parser/splits_io.rs | 2 +- src/run/parser/splitterz.rs | 6 +- src/run/parser/splitty.rs | 2 +- src/run/parser/time_split_tracker.rs | 4 +- src/run/parser/timer_kind.rs | 2 +- src/run/parser/urn.rs | 2 +- src/run/parser/worstrun.rs | 2 +- src/run/parser/wsplit.rs | 4 +- src/run/run_metadata.rs | 3 +- src/run/saver/livesplit.rs | 8 +- src/run/segment.rs | 3 +- src/run/segment_history.rs | 5 +- src/settings/color.rs | 2 +- src/settings/field.rs | 1 + src/settings/image/mod.rs | 41 +++-- src/settings/image/shrinking.rs | 2 +- src/settings/settings_description.rs | 1 + src/settings/value.rs | 3 +- src/timing/atomic_date_time.rs | 4 +- src/timing/formatter/accuracy.rs | 2 +- src/timing/formatter/complete.rs | 2 +- src/timing/formatter/days.rs | 2 +- src/timing/formatter/delta.rs | 2 +- src/timing/formatter/mod.rs | 6 +- src/timing/formatter/none_wrapper.rs | 2 +- src/timing/formatter/possible_time_save.rs | 2 +- src/timing/formatter/regular.rs | 2 +- src/timing/formatter/short.rs | 2 +- src/timing/formatter/timer.rs | 2 +- src/timing/mod.rs | 4 +- src/timing/time.rs | 2 +- src/timing/time_span.rs | 16 +- src/timing/time_stamp.rs | 2 +- src/timing/timer/mod.rs | 11 +- src/xml_util.rs | 9 +- 110 files changed, 880 insertions(+), 311 deletions(-) create mode 100644 crates/no-std-test/Cargo.toml create mode 100644 crates/no-std-test/README.md create mode 100644 crates/no-std-test/src/lib.rs create mode 100644 src/platform/no_std/indexmap.rs create mode 100644 src/platform/no_std/mod.rs create mode 100644 src/platform/no_std/time.rs diff --git a/.github/workflows/build_shared.sh b/.github/workflows/build_shared.sh index f236d60e7..77dbe2c55 100644 --- a/.github/workflows/build_shared.sh +++ b/.github/workflows/build_shared.sh @@ -10,7 +10,7 @@ main() { release_flag="--release" fi - $cargo build -p cdylib --target $TARGET $release_flag + $cargo build -p cdylib --target $TARGET $release_flag $FEATURES } main diff --git a/.github/workflows/build_static.sh b/.github/workflows/build_static.sh index b80d780d5..9171b536f 100644 --- a/.github/workflows/build_static.sh +++ b/.github/workflows/build_static.sh @@ -10,20 +10,25 @@ main() { release_flag="--release" fi + if [ "$NO_STD" = "true" ]; then + (cd crates/no-std-test && cargo build --target $TARGET $FEATURES) + return + fi + case $TARGET in asmjs-unknown-emscripten) - $cargo build -p livesplit --target $TARGET --release + $cargo build -p livesplit --target $TARGET --release $FEATURES ;; wasm32-unknown-emscripten) rm target/wasm32-unknown-emscripten/release/deps/*.wasm 2>/dev/null || : rm target/wasm32-unknown-emscripten/release/deps/*.js 2>/dev/null || : - $cargo build -p livesplit --target $TARGET --release + $cargo build -p livesplit --target $TARGET --release $FEATURES ;; wasm32-unknown-unknown) - $cargo build -p cdylib --target $TARGET --release + $cargo build -p cdylib --target $TARGET --release $FEATURES ;; *) - $cargo build -p staticlib --target $TARGET $release_flag + $cargo build -p staticlib --target $TARGET $release_flag $FEATURES ;; esac } diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index c5ba4e8f2..478abdd60 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -15,6 +15,21 @@ jobs: fail-fast: false matrix: label: + # Bare Metal + - Bare Metal Nvidia PTX 64 + - Bare Metal ARM Cortex-M thumbv6m + - Bare Metal ARM Cortex-M thumbv7em + - Bare Metal ARM Cortex-M thumbv7em Hardware Float + - Bare Metal ARM Cortex-M thumbv7m + - Bare Metal ARM Cortex-M thumbv8m.base + - Bare Metal ARM Cortex-M thumbv8m.main + - Bare Metal ARM Cortex-M thumbv8m.main Hardware Float + - Bare Metal RISC-V 32 i + - Bare Metal RISC-V 32 imac + - Bare Metal RISC-V 32 imc + - Bare Metal RISC-V 64 gc + - Bare Metal RISC-V 64 imac + # Web # FIXME: asmjs is broken at the moment. It's unclear why. # - Web asmjs @@ -104,6 +119,140 @@ jobs: - macOS Nightly include: + # Bare Metal + - label: Bare Metal Nvidia PTX 64 + target: nvptx64-nvidia-cuda + os: ubuntu-latest + toolchain: stable + tests: skip + dylib: skip + release: skip + no_std: true + install_target: true + + - label: Bare Metal ARM Cortex-M thumbv6m + target: thumbv6m-none-eabi + os: ubuntu-latest + toolchain: stable + tests: skip + dylib: skip + release: skip + no_std: true + install_target: true + features: "--features doesnt-have-atomics" + + - label: Bare Metal ARM Cortex-M thumbv7em + target: thumbv7em-none-eabi + os: ubuntu-latest + toolchain: stable + tests: skip + dylib: skip + release: skip + no_std: true + install_target: true + + - label: Bare Metal ARM Cortex-M thumbv7em Hardware Float + target: thumbv7em-none-eabihf + os: ubuntu-latest + toolchain: stable + tests: skip + dylib: skip + release: skip + no_std: true + install_target: true + + - label: Bare Metal ARM Cortex-M thumbv7m + target: thumbv7m-none-eabi + os: ubuntu-latest + toolchain: stable + tests: skip + dylib: skip + release: skip + no_std: true + install_target: true + + - label: Bare Metal ARM Cortex-M thumbv8m.base + target: thumbv8m.base-none-eabi + os: ubuntu-latest + toolchain: stable + tests: skip + dylib: skip + release: skip + no_std: true + install_target: true + + - label: Bare Metal ARM Cortex-M thumbv8m.main + target: thumbv8m.main-none-eabi + os: ubuntu-latest + toolchain: stable + tests: skip + dylib: skip + release: skip + no_std: true + install_target: true + + - label: Bare Metal ARM Cortex-M thumbv8m.main Hardware Float + target: thumbv8m.main-none-eabihf + os: ubuntu-latest + toolchain: stable + tests: skip + dylib: skip + release: skip + no_std: true + install_target: true + + - label: Bare Metal RISC-V 32 i + target: riscv32i-unknown-none-elf + os: ubuntu-latest + toolchain: stable + tests: skip + dylib: skip + release: skip + no_std: true + install_target: true + features: "--features doesnt-have-atomics" + + - label: Bare Metal RISC-V 32 imac + target: riscv32imac-unknown-none-elf + os: ubuntu-latest + toolchain: stable + tests: skip + dylib: skip + release: skip + no_std: true + install_target: true + + - label: Bare Metal RISC-V 32 imc + target: riscv32imc-unknown-none-elf + os: ubuntu-latest + toolchain: stable + tests: skip + dylib: skip + release: skip + no_std: true + install_target: true + features: "--features doesnt-have-atomics" + + - label: Bare Metal RISC-V 64 gc + target: riscv64gc-unknown-none-elf + os: ubuntu-latest + toolchain: stable + tests: skip + dylib: skip + release: skip + no_std: true + install_target: true + + - label: Bare Metal RISC-V 64 imac + target: riscv64imac-unknown-none-elf + os: ubuntu-latest + toolchain: stable + tests: skip + dylib: skip + release: skip + no_std: true + install_target: true + # Web # - label: Web asmjs # target: asmjs-unknown-emscripten @@ -119,7 +268,6 @@ jobs: toolchain: stable tests: skip dylib: skip - release_anyway: true - label: Web wasm32 target: wasm32-unknown-unknown @@ -127,7 +275,6 @@ jobs: tests: skip dylib: skip install_target: true - release_anyway: true # Windows - label: Windows aarch64 @@ -394,17 +541,20 @@ jobs: target: x86_64-pc-windows-msvc os: windows-latest toolchain: beta + release: skip cross: skip - label: Windows Nightly target: x86_64-pc-windows-msvc os: windows-latest toolchain: nightly + release: skip cross: skip - label: Windows Beta gnu target: x86_64-pc-windows-gnu toolchain: beta-x86_64-pc-windows-gnu + release: skip os: windows-latest cross: skip install_target: true @@ -412,6 +562,7 @@ jobs: - label: Windows Nightly gnu target: x86_64-pc-windows-gnu toolchain: nightly-x86_64-pc-windows-gnu + release: skip os: windows-latest cross: skip install_target: true @@ -420,22 +571,26 @@ jobs: target: x86_64-unknown-linux-gnu os: ubuntu-latest toolchain: beta + release: skip - label: Linux Nightly target: x86_64-unknown-linux-gnu os: ubuntu-latest toolchain: nightly + release: skip - label: macOS Beta target: x86_64-apple-darwin os: macOS-latest toolchain: beta + release: skip cross: skip - label: macOS Nightly target: x86_64-apple-darwin os: macOS-latest toolchain: nightly + release: skip cross: skip steps: @@ -463,6 +618,8 @@ jobs: TARGET: ${{ matrix.target }} SKIP_CROSS: ${{ matrix.cross }} IS_DEPLOY: ${{ startsWith(github.ref, 'refs/tags/') && (matrix.release_anyway != '' || !(startsWith(matrix.toolchain, 'nightly') || startsWith(matrix.toolchain, 'beta'))) }} + FEATURES: ${{ matrix.features }} + NO_STD: ${{ matrix.no_std }} - name: Build Shared Library if: matrix.dylib == '' @@ -471,6 +628,7 @@ jobs: TARGET: ${{ matrix.target }} SKIP_CROSS: ${{ matrix.cross }} IS_DEPLOY: ${{ startsWith(github.ref, 'refs/tags/') && (matrix.release_anyway != '' || !(startsWith(matrix.toolchain, 'nightly') || startsWith(matrix.toolchain, 'beta'))) }} + FEATURES: ${{ matrix.features }} - name: Test if: matrix.tests == '' @@ -480,7 +638,7 @@ jobs: SKIP_CROSS: ${{ matrix.cross }} - name: Prepare Release - if: startsWith(github.ref, 'refs/tags/') && (matrix.release_anyway != '' || !(startsWith(matrix.toolchain, 'nightly') || startsWith(matrix.toolchain, 'beta'))) + if: startsWith(github.ref, 'refs/tags/') && matrix.release == '' shell: bash run: .github/workflows/before_deploy.sh env: @@ -488,7 +646,7 @@ jobs: TARGET: ${{ matrix.target }} - name: Release - if: startsWith(github.ref, 'refs/tags/') && (matrix.release_anyway != '' || !(startsWith(matrix.toolchain, 'nightly') || startsWith(matrix.toolchain, 'beta'))) + if: startsWith(github.ref, 'refs/tags/') && matrix.release == '' uses: softprops/action-gh-release@v1 with: files: livesplit-core-*.* diff --git a/Cargo.toml b/Cargo.toml index 80664cbb6..3a8f1f0b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,29 +32,32 @@ panic = "abort" [workspace] members = ["capi", "capi/bind_gen", "capi/js", "capi/staticlib", "capi/cdylib", "crates/*"] +exclude = ["crates/no-std-test"] [dependencies] -# Required crates +# core base64 = { version = "0.11.0", default-features = false, features = ["alloc"] } -cfg-if = "0.1.7" -chrono = { version = "0.4.0", features = ["serde", "clock"], default-features = false } +cfg-if = "0.1.10" derive_more = { version = "0.99.1", default-features = false, features = ["not", "add", "from", "deref"] } +hashbrown = "0.6.3" +libm = "0.1.4" +livesplit-hotkey = { path = "crates/livesplit-hotkey", version = "0.5.0", default-features = false } odds = { version = "0.3.1", default-features = false } ordered-float = { version = "1.0.2", default-features = false } -palette = { version = "0.5.0", default-features = false, features = ["std"] } -serde = { version = "1.0.98", default-features = false, features = ["derive", "alloc", "std"] } -snafu = { version = "0.6.0", default-features = false, features = ["std"] } +palette = { version = "0.5.0", default-features = false, features = ["libm"] } +serde = { version = "1.0.98", default-features = false, features = ["derive", "alloc"] } +snafu = { version = "0.6.0", default-features = false } unicase = "2.6.0" # std -byteorder = "1.3.2" -image = { version = "0.22.0", features = ["png_codec"], default-features = false } -indexmap = { version = "1.2.0", default-features = false, features = ["serde-1"] } -livesplit-hotkey = { path = "crates/livesplit-hotkey", version = "0.5.0" } -parking_lot = { version = "0.9.0", default-features = false } -quick-xml = { version = "0.17.0", default-features = false } -serde_json = "1.0.8" -utf-8 = "0.7.4" +byteorder = { version = "1.3.2", optional = true } +chrono = { version = "0.4.0", features = ["serde", "clock"], default-features = false, optional = true } +image = { version = "0.22.0", features = ["png_codec"], default-features = false, optional = true } +indexmap = { version = "1.2.0", default-features = false, features = ["serde-1"], optional = true } +parking_lot = { version = "0.9.0", default-features = false, optional = true } +quick-xml = { version = "0.17.0", default-features = false, optional = true } +serde_json = { version = "1.0.8", optional = true } +utf-8 = { version = "0.7.4", optional = true } # Rendering euclid = { version = "0.20.0", default-features = false, optional = true } @@ -73,12 +76,24 @@ criterion = "0.3.0" crc = "1.8.1" [features] -default = ["image-shrinking"] +default = ["image-shrinking", "std"] +doesnt-have-atomics = [] +std = ["byteorder", "chrono", "image", "indexmap", "livesplit-hotkey/std", "palette/std", "parking_lot", "quick-xml", "serde_json", "serde/std", "snafu/std", "utf-8"] more-image-formats = ["image/webp", "image/pnm", "image/ico", "image/jpeg", "image/gif_codec", "image/tiff", "image/tga", "image/bmp", "image/hdr"] image-shrinking = ["more-image-formats"] -rendering = ["more-image-formats", "euclid", "livesplit-title-abbreviations", "lyon", "rusttype", "smallvec"] +rendering = ["std", "more-image-formats", "euclid", "livesplit-title-abbreviations", "lyon", "rusttype", "smallvec"] software-rendering = ["rendering", "euc", "vek", "derive_more/mul"] +# FIXME: Some targets don't have atomics, but we can't test for this properly +# yet. So there's a feature you explicitly have to opt into to deactivate the +# usage of atomics. Vice versa would be too dangerous, as `default-features = +# false` would deactivate atomics then. However there's also `cargo test +# --all-features`, which is equally dangerous. To detect this, we have an +# additional `internal-use-all-features` feature that is only ever activated +# when `--all-features` is passed, so we can ignore the `doesnt-have-atomics` in +# that case. https://github.com/rust-lang/rust/issues/32976 +internal-use-all-features = [] + [[bench]] name = "balanced_pb" harness = false diff --git a/crates/livesplit-hotkey/Cargo.toml b/crates/livesplit-hotkey/Cargo.toml index b9eeaca77..8692303b7 100644 --- a/crates/livesplit-hotkey/Cargo.toml +++ b/crates/livesplit-hotkey/Cargo.toml @@ -14,18 +14,23 @@ winapi = { version = "0.3.2", features = [ "libloaderapi", "processthreadsapi", "winuser" -] } -parking_lot = "0.9.0" +], optional = true } +parking_lot = { version = "0.9.0", optional = true } [target.'cfg(target_os = "linux")'.dependencies] -x11-dl = "2.18.3" -mio = "0.6.16" -promising-future = "0.2.4" +x11-dl = { version = "2.18.3", optional = true } +mio = { version = "0.6.16", optional = true } +promising-future = { version = "0.2.4", optional = true } [target.'cfg(target_os = "emscripten")'.dependencies] -stdweb = "0.3.0" -parking_lot = "0.9.0" +stdweb = { version = "0.3.0", optional = true } +parking_lot = { version = "0.9.0", optional = true } [dependencies] -snafu = { version = "0.6.0", default-features = false, features = ["std"] } -serde = { version = "1.0.98", default-features = false, features = ["derive", "alloc", "std"] } +cfg-if = "0.1.10" +snafu = { version = "0.6.0", default-features = false } +serde = { version = "1.0.98", default-features = false, features = ["derive", "alloc"] } + +[features] +default = ["std"] +std = ["snafu/std", "serde/std", "stdweb", "parking_lot", "x11-dl", "mio", "promising-future", "winapi", "parking_lot"] diff --git a/crates/livesplit-hotkey/src/lib.rs b/crates/livesplit-hotkey/src/lib.rs index 84a3e719c..eac5dd1cf 100644 --- a/crates/livesplit-hotkey/src/lib.rs +++ b/crates/livesplit-hotkey/src/lib.rs @@ -1,40 +1,27 @@ // For js! macro. #![recursion_limit = "1024"] +#![cfg_attr(not(feature = "std"), no_std)] -#[cfg(windows)] -pub mod windows; -#[cfg(windows)] -pub use crate::windows::*; - -#[cfg(target_os = "linux")] -pub mod linux; -#[cfg(target_os = "linux")] -pub use crate::linux::*; - -#[cfg(target_os = "emscripten")] -pub mod emscripten; -#[cfg(target_os = "emscripten")] -pub use crate::emscripten::*; -#[cfg(target_os = "emscripten")] -#[macro_use] -extern crate stdweb; - -#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] -pub mod wasm; -#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] -pub use crate::wasm::*; - -#[cfg(not(any( - windows, - target_os = "linux", - target_os = "emscripten", - all(target_arch = "wasm32", target_os = "unknown") -)))] -pub mod other; -#[cfg(not(any( - windows, - target_os = "linux", - target_os = "emscripten", - all(target_arch = "wasm32", target_os = "unknown") -)))] -pub use crate::other::*; +cfg_if::cfg_if! { + if #[cfg(not(feature = "std"))] { + pub mod other; + pub use crate::other::*; + } else if #[cfg(windows)] { + pub mod windows; + pub use crate::windows::*; + } else if #[cfg(target_os = "linux")] { + pub mod linux; + pub use crate::linux::*; + } else if #[cfg(target_os = "emscripten")] { + pub mod emscripten; + pub use crate::emscripten::*; + #[macro_use] + extern crate stdweb; + } else if #[cfg(all(target_arch = "wasm32", target_os = "unknown"))] { + pub mod wasm; + pub use crate::wasm::*; + } else { + pub mod other; + pub use crate::other::*; + } +} diff --git a/crates/livesplit-hotkey/src/other/mod.rs b/crates/livesplit-hotkey/src/other/mod.rs index 82da62c61..afaa38e29 100644 --- a/crates/livesplit-hotkey/src/other/mod.rs +++ b/crates/livesplit-hotkey/src/other/mod.rs @@ -25,7 +25,7 @@ impl Hook { } } -use std::{result::Result as StdResult, str::FromStr}; +use core::{result::Result as StdResult, str::FromStr}; impl FromStr for KeyCode { type Err = (); diff --git a/crates/livesplit-title-abbreviations/Cargo.toml b/crates/livesplit-title-abbreviations/Cargo.toml index cefad333b..2b25456c9 100644 --- a/crates/livesplit-title-abbreviations/Cargo.toml +++ b/crates/livesplit-title-abbreviations/Cargo.toml @@ -10,4 +10,4 @@ keywords = ["speedrun", "timer", "livesplit", "title", "abbreviation"] edition = "2018" [dependencies] -unicase = "2.2.0" +unicase = "2.6.0" diff --git a/crates/livesplit-title-abbreviations/src/lib.rs b/crates/livesplit-title-abbreviations/src/lib.rs index 97cfccfd8..74ca01d1a 100644 --- a/crates/livesplit-title-abbreviations/src/lib.rs +++ b/crates/livesplit-title-abbreviations/src/lib.rs @@ -1,5 +1,8 @@ -extern crate unicase; +#![no_std] +extern crate alloc; + +use alloc::{format, string::String, vec, vec::Vec}; use unicase::UniCase; fn ends_with_roman_numeral(name: &str) -> bool { diff --git a/crates/no-std-test/Cargo.toml b/crates/no-std-test/Cargo.toml new file mode 100644 index 000000000..7b16a8a49 --- /dev/null +++ b/crates/no-std-test/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "no-std-test" +version = "0.1.0" +authors = ["Christopher Serr "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[workspace] + +[dependencies] +livesplit-core = { path = "../..", default-features = false } + +[features] +doesnt-have-atomics = ["livesplit-core/doesnt-have-atomics"] diff --git a/crates/no-std-test/README.md b/crates/no-std-test/README.md new file mode 100644 index 000000000..5482e37a6 --- /dev/null +++ b/crates/no-std-test/README.md @@ -0,0 +1,6 @@ +# no_std Testing + +In order to test the build for a no_std target, we can't use the same workspace +as the main one as that one includes std-only dev-dependencies that leak their +features into the no_std main dependencies. This is a cargo bug. This crate is +therefore only a temporary workaround. diff --git a/crates/no-std-test/src/lib.rs b/crates/no-std-test/src/lib.rs new file mode 100644 index 000000000..0c9ac1ac8 --- /dev/null +++ b/crates/no-std-test/src/lib.rs @@ -0,0 +1 @@ +#![no_std] diff --git a/src/analysis/pb_chance/mod.rs b/src/analysis/pb_chance/mod.rs index 109a781bc..8c8d065b4 100644 --- a/src/analysis/pb_chance/mod.rs +++ b/src/analysis/pb_chance/mod.rs @@ -9,6 +9,7 @@ //! PB chance is the percentile at which the Balanced PB algorithm finds the PB. use crate::{comparison, Run, Segment, TimeSpan, Timer, TimingMethod}; +use crate::platform::prelude::*; #[cfg(test)] mod tests; diff --git a/src/analysis/sum_of_segments/mod.rs b/src/analysis/sum_of_segments/mod.rs index 261f0ea94..528f0a7eb 100644 --- a/src/analysis/sum_of_segments/mod.rs +++ b/src/analysis/sum_of_segments/mod.rs @@ -14,6 +14,7 @@ pub mod worst; mod tests; use crate::{Segment, Time, TimeSpan, TimingMethod}; +use crate::platform::prelude::*; /// Describes the shortest amount of time it takes to reach a certain segment. /// Since there is the possibility that the shortest path is actually skipping diff --git a/src/comparison/balanced_pb.rs b/src/comparison/balanced_pb.rs index 8164c52a4..398f0bdb0 100644 --- a/src/comparison/balanced_pb.rs +++ b/src/comparison/balanced_pb.rs @@ -13,6 +13,7 @@ use super::{goal, ComparisonGenerator}; use crate::{Attempt, Segment, TimingMethod}; +use crate::platform::prelude::*; /// The Comparison Generator for calculating a comparison which has the same /// final time as the runner's Personal Best. Unlike the Personal Best however, diff --git a/src/comparison/best_segments.rs b/src/comparison/best_segments.rs index d4617d186..fa4d85d56 100644 --- a/src/comparison/best_segments.rs +++ b/src/comparison/best_segments.rs @@ -3,6 +3,7 @@ use super::ComparisonGenerator; use crate::analysis::sum_of_segments::best::calculate; use crate::{Attempt, Segment, Time, TimingMethod}; +use crate::platform::prelude::*; /// The Comparison Generator for calculating the Best Segments of a Run. #[derive(Copy, Clone, Debug)] diff --git a/src/comparison/goal.rs b/src/comparison/goal.rs index eedc4ce84..e6c5533df 100644 --- a/src/comparison/goal.rs +++ b/src/comparison/goal.rs @@ -7,6 +7,7 @@ use crate::{Segment, Time, TimeSpan, TimingMethod}; use ordered_float::OrderedFloat; +use crate::platform::prelude::*; /// The default name of the goal comparison. pub const NAME: &str = "Goal"; diff --git a/src/comparison/median_segments.rs b/src/comparison/median_segments.rs index f0df84393..13c5ffc2d 100644 --- a/src/comparison/median_segments.rs +++ b/src/comparison/median_segments.rs @@ -6,6 +6,7 @@ use super::ComparisonGenerator; use crate::{Attempt, Segment, TimeSpan, TimingMethod}; use ordered_float::OrderedFloat; +use crate::platform::prelude::*; /// The Comparison Generator for calculating the Median Segments of a Run. The /// Median Segments are calculated through a weighted median that gives more diff --git a/src/comparison/mod.rs b/src/comparison/mod.rs index 56711824a..cd3b213fc 100644 --- a/src/comparison/mod.rs +++ b/src/comparison/mod.rs @@ -26,7 +26,8 @@ pub use self::none::None; pub use self::worst_segments::WorstSegments; use crate::{Attempt, Segment, Timer}; -use std::fmt::Debug; +use core::fmt::Debug; +use crate::platform::prelude::*; /// Defines the Personal Best comparison. This module mostly just serves for /// providing the names of the comparison, as the Personal Best is not a diff --git a/src/comparison/worst_segments.rs b/src/comparison/worst_segments.rs index 22a544a91..7f44bda12 100644 --- a/src/comparison/worst_segments.rs +++ b/src/comparison/worst_segments.rs @@ -3,6 +3,7 @@ use super::ComparisonGenerator; use crate::analysis::sum_of_segments::worst::calculate; use crate::{Attempt, Segment, Time, TimingMethod}; +use crate::platform::prelude::*; /// The Comparison Generator for calculating the Worst Segments of a Run. #[derive(Copy, Clone, Debug)] diff --git a/src/component/blank_space.rs b/src/component/blank_space.rs index 97034049b..b6875a9cf 100644 --- a/src/component/blank_space.rs +++ b/src/component/blank_space.rs @@ -3,11 +3,10 @@ //! anything other than a background. It mostly serves as padding between other //! components. +use crate::platform::prelude::*; use crate::settings::{Field, Gradient, SettingsDescription, Value}; use crate::Timer; use serde::{Deserialize, Serialize}; -use serde_json::{to_writer, Result}; -use std::io::Write; /// The Blank Space Component is simply an empty component that doesn't show /// anything other than a background. It mostly serves as padding between other @@ -45,13 +44,14 @@ pub struct State { pub size: u32, } +#[cfg(feature = "std")] impl State { /// Encodes the state object's information as JSON. - pub fn write_json(&self, writer: W) -> Result<()> + pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, self) + serde_json::to_writer(writer, self) } } diff --git a/src/component/current_comparison.rs b/src/component/current_comparison.rs index 7f4b8616a..dac8da208 100644 --- a/src/component/current_comparison.rs +++ b/src/component/current_comparison.rs @@ -3,6 +3,7 @@ //! comparison that is currently selected to be compared against. use super::key_value; +use crate::platform::prelude::*; use crate::settings::{Color, Field, Gradient, SettingsDescription, Value}; use crate::Timer; use serde::{Deserialize, Serialize}; diff --git a/src/component/current_pace.rs b/src/component/current_pace.rs index fc28913ce..9b03976a7 100644 --- a/src/component/current_pace.rs +++ b/src/component/current_pace.rs @@ -5,11 +5,12 @@ use super::key_value; use crate::analysis::current_pace; +use crate::platform::prelude::*; use crate::settings::{Color, Field, Gradient, SettingsDescription, Value}; use crate::timing::formatter::{Accuracy, Regular, TimeFormatter}; use crate::{comparison, Timer, TimerPhase}; +use alloc::borrow::Cow; use serde::{Deserialize, Serialize}; -use std::borrow::Cow; /// The Current Pace Component is a component that shows a prediction of the /// current attempt's final time, if the current attempt's pace matches the diff --git a/src/component/delta/mod.rs b/src/component/delta/mod.rs index 32e1a8deb..bf4191c0f 100644 --- a/src/component/delta/mod.rs +++ b/src/component/delta/mod.rs @@ -4,11 +4,12 @@ use super::key_value; use crate::analysis::{delta, state_helper}; +use crate::platform::prelude::*; use crate::settings::{Color, Field, Gradient, SemanticColor, SettingsDescription, Value}; use crate::timing::formatter::{Accuracy, Delta, TimeFormatter}; use crate::{comparison, GeneralLayoutSettings, Timer}; +use alloc::borrow::Cow; use serde::{Deserialize, Serialize}; -use std::borrow::Cow; #[cfg(test)] mod tests; diff --git a/src/component/detailed_timer/mod.rs b/src/component/detailed_timer/mod.rs index 87722ae49..815350959 100644 --- a/src/component/detailed_timer/mod.rs +++ b/src/component/detailed_timer/mod.rs @@ -15,8 +15,7 @@ use crate::timing::formatter::{ }; use crate::{GeneralLayoutSettings, Segment, TimeSpan, Timer, TimerPhase, TimingMethod}; use serde::{Deserialize, Serialize}; -use serde_json::{to_writer, Result}; -use std::io::Write; +use crate::platform::prelude::*; #[cfg(test)] mod tests; @@ -110,13 +109,14 @@ impl Default for Settings { } } +#[cfg(feature = "std")] impl State { /// Encodes the state object's information as JSON. - pub fn write_json(&self, writer: W) -> Result<()> + pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, self) + serde_json::to_writer(writer, self) } } diff --git a/src/component/graph.rs b/src/component/graph.rs index ff23402c9..c303e5270 100644 --- a/src/component/graph.rs +++ b/src/component/graph.rs @@ -5,10 +5,9 @@ use crate::settings::{Color, Field, SettingsDescription, Value}; use crate::{analysis, comparison, GeneralLayoutSettings, TimeSpan, Timer, TimerPhase}; +use alloc::borrow::Cow; use serde::{Deserialize, Serialize}; -use serde_json::{to_writer, Result}; -use std::borrow::Cow; -use std::io::Write; +use crate::platform::prelude::*; const GRAPH_EDGE_VALUE: f32 = 200.0; const GRAPH_EDGE_MIN: f32 = 5.0; @@ -137,13 +136,14 @@ impl Default for Settings { } } +#[cfg(feature = "std")] impl State { /// Encodes the state object's information as JSON. - pub fn write_json(&self, writer: W) -> Result<()> + pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, self) + serde_json::to_writer(writer, self) } } diff --git a/src/component/key_value.rs b/src/component/key_value.rs index b6261faa8..100b9134f 100644 --- a/src/component/key_value.rs +++ b/src/component/key_value.rs @@ -3,13 +3,12 @@ //! components. They all share the same visual appearance and thus use the same //! state object representation. +use crate::platform::prelude::*; use crate::settings::{Color, Gradient, SemanticColor}; +use core::marker::PhantomData; use palette::rgb::Rgb; use palette::Alpha; use serde::{Deserialize, Serialize}; -use serde_json::{to_writer, Result}; -use std::io::Write; -use std::marker::PhantomData; /// The state object describes the information to visualize for a key value /// based component. @@ -36,13 +35,14 @@ pub struct State { pub display_two_rows: bool, } +#[cfg(feature = "std")] impl State { /// Encodes the state object's information as JSON. - pub fn write_json(&self, writer: W) -> Result<()> + pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, self) + serde_json::to_writer(writer, self) } } diff --git a/src/component/pb_chance.rs b/src/component/pb_chance.rs index ab8dd8d64..d3ff26a4c 100644 --- a/src/component/pb_chance.rs +++ b/src/component/pb_chance.rs @@ -8,6 +8,7 @@ use super::key_value; use crate::settings::{Color, Field, Gradient, SettingsDescription, Value}; use crate::{analysis::pb_chance, Timer}; use serde::{Deserialize, Serialize}; +use crate::platform::prelude::*; /// The PB Chance Component is a component that shows how likely it is to beat /// the Personal Best. If there is no active attempt it shows the general chance diff --git a/src/component/possible_time_save.rs b/src/component/possible_time_save.rs index 85b12f3aa..7de1810b2 100644 --- a/src/component/possible_time_save.rs +++ b/src/component/possible_time_save.rs @@ -10,8 +10,9 @@ use crate::settings::{Color, Field, Gradient, SettingsDescription, Value}; use crate::timing::formatter::{Accuracy, PossibleTimeSave, TimeFormatter}; use crate::{comparison, Timer, TimerPhase}; use serde::{Deserialize, Serialize}; -use std::borrow::Cow; -use std::fmt::Write as FmtWrite; +use alloc::borrow::Cow; +use core::fmt::Write as FmtWrite; +use crate::platform::prelude::*; /// The Possible Time Save Component is a component that shows how much time the /// chosen comparison could've saved for the current segment, based on the Best diff --git a/src/component/previous_segment.rs b/src/component/previous_segment.rs index 85c7baf1a..e268d3fdc 100644 --- a/src/component/previous_segment.rs +++ b/src/component/previous_segment.rs @@ -10,8 +10,9 @@ use crate::settings::{Color, Field, Gradient, SemanticColor, SettingsDescription use crate::timing::formatter::{Accuracy, Delta, PossibleTimeSave, TimeFormatter}; use crate::{analysis, comparison, GeneralLayoutSettings, Timer, TimerPhase}; use serde::{Deserialize, Serialize}; -use std::borrow::Cow; -use std::fmt::Write; +use alloc::borrow::Cow; +use core::fmt::Write as FmtWrite; +use crate::platform::prelude::*; /// The Previous Segment Component is a component that shows how much time was /// saved or lost during the previous segment based on the chosen comparison. diff --git a/src/component/separator.rs b/src/component/separator.rs index 172431c45..9781d9170 100644 --- a/src/component/separator.rs +++ b/src/component/separator.rs @@ -5,8 +5,6 @@ use crate::settings::{SettingsDescription, Value}; use crate::Timer; use serde::{Deserialize, Serialize}; -use serde_json::{to_writer, Result}; -use std::io::Write; /// The Separator Component is a simple component that only serves to render /// separators between components. @@ -17,13 +15,14 @@ pub struct Component; #[derive(Serialize, Deserialize)] pub struct State; +#[cfg(feature = "std")] impl State { /// Encodes the state object's information as JSON. - pub fn write_json(&self, writer: W) -> Result<()> + pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, self) + serde_json::to_writer(writer, self) } } diff --git a/src/component/splits/column.rs b/src/component/splits/column.rs index de5a1c680..4d40a7844 100644 --- a/src/component/splits/column.rs +++ b/src/component/splits/column.rs @@ -6,6 +6,7 @@ use crate::{ GeneralLayoutSettings, Segment, TimeSpan, Timer, TimingMethod, }; use serde::{Deserialize, Serialize}; +use crate::platform::prelude::*; /// The settings of an individual column showing timing information on each /// split. diff --git a/src/component/splits/mod.rs b/src/component/splits/mod.rs index 7679bd515..6c4372e5e 100644 --- a/src/component/splits/mod.rs +++ b/src/component/splits/mod.rs @@ -5,16 +5,15 @@ //! list provides scrolling functionality, so not every segment needs to be //! shown all the time. +use crate::platform::prelude::*; use crate::{ settings::{ CachedImageId, Color, Field, Gradient, ImageData, ListGradient, SettingsDescription, Value, }, GeneralLayoutSettings, Timer, }; +use core::cmp::{max, min}; use serde::{Deserialize, Serialize}; -use serde_json::{to_writer, Result}; -use std::cmp::{max, min}; -use std::io::Write; #[cfg(test)] mod tests; @@ -200,13 +199,14 @@ impl Default for Settings { } } +#[cfg(feature = "std")] impl State { /// Encodes the state object's information as JSON. - pub fn write_json(&self, writer: W) -> Result<()> + pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, self) + serde_json::to_writer(writer, self) } } diff --git a/src/component/sum_of_best.rs b/src/component/sum_of_best.rs index 2ad5ef7f4..fecaec27f 100644 --- a/src/component/sum_of_best.rs +++ b/src/component/sum_of_best.rs @@ -9,6 +9,7 @@ use super::key_value; use crate::analysis::sum_of_segments::calculate_best; +use crate::platform::prelude::*; use crate::settings::{Color, Field, Gradient, SettingsDescription, Value}; use crate::timing::formatter::{Accuracy, Regular, TimeFormatter}; use crate::Timer; diff --git a/src/component/text.rs b/src/component/text.rs index eaf20f787..d0e8a1856 100644 --- a/src/component/text.rs +++ b/src/component/text.rs @@ -5,11 +5,10 @@ use super::key_value; use crate::settings::{Color, Field, Gradient, SettingsDescription, Value}; +use alloc::borrow::Cow; +use core::mem::replace; use serde::{Deserialize, Serialize}; -use serde_json::{to_writer, Result}; -use std::borrow::Cow; -use std::io::Write; -use std::mem::replace; +use crate::platform::prelude::*; /// The Text Component simply visualizes any given text. This can either be a /// single centered text, or split up into a left and right text, which is @@ -125,13 +124,14 @@ impl Default for Settings { } } +#[cfg(feature = "std")] impl State { /// Encodes the state object's information as JSON. - pub fn write_json(&self, writer: W) -> Result<()> + pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, self) + serde_json::to_writer(writer, self) } } diff --git a/src/component/timer.rs b/src/component/timer.rs index 431071b17..21320b414 100644 --- a/src/component/timer.rs +++ b/src/component/timer.rs @@ -4,14 +4,12 @@ //! current attempt is doing compared to the chosen comparison. use crate::analysis::split_color; +use crate::palette::{rgb::LinSrgb, Hsv}; +use crate::platform::prelude::*; use crate::settings::{Color, Field, Gradient, SemanticColor, SettingsDescription, Value}; use crate::timing::formatter::{timer as formatter, Accuracy, DigitsFormat, TimeFormatter}; use crate::{GeneralLayoutSettings, TimeSpan, Timer, TimerPhase, TimingMethod}; -use palette::rgb::LinSrgb; -use palette::Hsv; use serde::{Deserialize, Serialize}; -use serde_json::{to_writer, Result}; -use std::io::Write; /// The Timer Component is a component that shows the total time of the current /// attempt as a digital clock. The color of the time shown is based on a how @@ -81,13 +79,14 @@ pub struct State { pub height: u32, } +#[cfg(feature = "std")] impl State { /// Encodes the state object's information as JSON. - pub fn write_json(&self, writer: W) -> Result<()> + pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, self) + serde_json::to_writer(writer, self) } } diff --git a/src/component/title/mod.rs b/src/component/title/mod.rs index d850d3160..f968015c2 100644 --- a/src/component/title/mod.rs +++ b/src/component/title/mod.rs @@ -9,8 +9,7 @@ use crate::{ Timer, TimerPhase, }; use serde::{Deserialize, Serialize}; -use serde_json::{to_writer, Result}; -use std::io::Write; +use crate::platform::prelude::*; #[cfg(test)] mod tests; @@ -119,13 +118,14 @@ impl Default for Settings { } } +#[cfg(feature = "std")] impl State { /// Encodes the state object's information as JSON. - pub fn write_json(&self, writer: W) -> Result<()> + pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, self) + serde_json::to_writer(writer, self) } } diff --git a/src/component/total_playtime.rs b/src/component/total_playtime.rs index ac6db1b4f..f82964543 100644 --- a/src/component/total_playtime.rs +++ b/src/component/total_playtime.rs @@ -4,6 +4,7 @@ use super::key_value; use crate::analysis::total_playtime; +use crate::platform::prelude::*; use crate::settings::{Color, Field, Gradient, SettingsDescription, Value}; use crate::timing::formatter::{Days, Regular, TimeFormatter}; use crate::Timer; diff --git a/src/hotkey_config.rs b/src/hotkey_config.rs index 4c8eff2a2..e65519c1a 100644 --- a/src/hotkey_config.rs +++ b/src/hotkey_config.rs @@ -1,10 +1,9 @@ #![allow(clippy::trivially_copy_pass_by_ref)] use crate::hotkey::KeyCode; +use crate::platform::prelude::*; use crate::settings::{Field, SettingsDescription, Value}; use serde::{Deserialize, Serialize}; -use serde_json::{self, from_reader, to_writer}; -use std::io::{Read, Write}; /// The configuration to use for a Hotkey System. It describes with keys to use /// as hotkeys for the different actions. @@ -170,18 +169,20 @@ impl HotkeyConfig { } /// Decodes the hotkey configuration from JSON. + #[cfg(feature = "std")] pub fn from_json(reader: R) -> serde_json::Result where - R: Read, + R: std::io::Read, { - from_reader(reader) + serde_json::from_reader(reader) } /// Encodes the hotkey configuration as JSON. + #[cfg(feature = "std")] pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, self) + serde_json::to_writer(writer, self) } } diff --git a/src/hotkey_system.rs b/src/hotkey_system.rs index 02e360f27..52a29b7e3 100644 --- a/src/hotkey_system.rs +++ b/src/hotkey_system.rs @@ -1,7 +1,7 @@ use crate::hotkey::{Hook, KeyCode}; use crate::{HotkeyConfig, SharedTimer}; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; +use alloc::sync::Arc; +use core::sync::atomic::{AtomicBool, Ordering}; pub use crate::hotkey::{Error, Result}; diff --git a/src/layout/component.rs b/src/layout/component.rs index 7af44dc1b..c1847908c 100644 --- a/src/layout/component.rs +++ b/src/layout/component.rs @@ -6,7 +6,8 @@ use crate::component::{ }; use crate::settings::{SettingsDescription, Value}; use crate::Timer; -use std::borrow::Cow; +use alloc::borrow::Cow; +use crate::platform::prelude::*; /// A Component provides information about a run in a way that is easy to /// visualize. This type can store any of the components provided by this crate. diff --git a/src/layout/component_settings.rs b/src/layout/component_settings.rs index 420d38147..e4b1a8a4d 100644 --- a/src/layout/component_settings.rs +++ b/src/layout/component_settings.rs @@ -5,6 +5,7 @@ use crate::component::{ total_playtime, }; use serde::{Deserialize, Serialize}; +use crate::platform::prelude::*; /// The settings for one of the components available. #[derive(Clone, Serialize, Deserialize)] diff --git a/src/layout/component_state.rs b/src/layout/component_state.rs index bae98926f..43d535ab4 100644 --- a/src/layout/component_state.rs +++ b/src/layout/component_state.rs @@ -2,6 +2,7 @@ use crate::component::{ blank_space, detailed_timer, graph, key_value, separator, splits, text, timer, title, }; use serde::{Deserialize, Serialize}; +use crate::platform::prelude::*; /// The state object for one of the components available. #[derive(Serialize, Deserialize)] diff --git a/src/layout/editor/mod.rs b/src/layout/editor/mod.rs index 9df387aeb..ca15fdb51 100644 --- a/src/layout/editor/mod.rs +++ b/src/layout/editor/mod.rs @@ -7,7 +7,7 @@ use super::{Component, Layout, LayoutState}; use crate::settings::Value; use crate::Timer; -use std::result::Result as StdResult; +use core::result::Result as StdResult; mod state; diff --git a/src/layout/editor/state.rs b/src/layout/editor/state.rs index 9000171ba..f68dbf3bf 100644 --- a/src/layout/editor/state.rs +++ b/src/layout/editor/state.rs @@ -1,8 +1,7 @@ use super::Editor; use crate::settings::SettingsDescription; use serde::{Deserialize, Serialize}; -use serde_json::{to_writer, Result as JsonResult}; -use std::io::Write; +use crate::platform::prelude::*; /// Represents the current state of the Layout Editor in order to visualize it /// properly. @@ -38,13 +37,14 @@ pub struct Buttons { pub can_move_down: bool, } +#[cfg(feature = "std")] impl State { /// Encodes the state object's information as JSON. - pub fn write_json(&self, writer: W) -> JsonResult<()> + pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, self) + serde_json::to_writer(writer, self) } } diff --git a/src/layout/general_settings.rs b/src/layout/general_settings.rs index 93e6c22cf..8cc0cacdc 100644 --- a/src/layout/general_settings.rs +++ b/src/layout/general_settings.rs @@ -1,6 +1,7 @@ use super::LayoutDirection; use crate::settings::{Color, Field, Gradient, SettingsDescription, Value}; use serde::{Deserialize, Serialize}; +use crate::platform::prelude::*; /// The general settings of the layout that apply to all components. #[derive(Clone, Serialize, Deserialize)] diff --git a/src/layout/layout_settings.rs b/src/layout/layout_settings.rs index d71016d39..174e44439 100644 --- a/src/layout/layout_settings.rs +++ b/src/layout/layout_settings.rs @@ -1,7 +1,6 @@ use super::{ComponentSettings, GeneralSettings}; use serde::{Deserialize, Serialize}; -use serde_json::{from_reader, to_writer, Result}; -use std::io::{Read, Write}; +use crate::platform::prelude::*; /// Describes a whole layout by its settings in a way that can easily be /// serialized and deserialized. @@ -13,20 +12,21 @@ pub struct LayoutSettings { pub general: GeneralSettings, } +#[cfg(feature = "std")] impl LayoutSettings { /// Decodes the layout's settings from JSON. - pub fn from_json(reader: R) -> Result + pub fn from_json(reader: R) -> serde_json::Result where - R: Read, + R: std::io::Read, { - from_reader(reader) + serde_json::from_reader(reader) } /// Encodes the layout's settings as JSON. - pub fn write_json(&self, writer: W) -> Result<()> + pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, self) + serde_json::to_writer(writer, self) } } diff --git a/src/layout/layout_state.rs b/src/layout/layout_state.rs index 564effbbf..9874a443c 100644 --- a/src/layout/layout_state.rs +++ b/src/layout/layout_state.rs @@ -1,8 +1,7 @@ use super::{ComponentState, LayoutDirection}; use crate::settings::{Color, Gradient}; use serde::{Deserialize, Serialize}; -use serde_json::{to_writer, Result}; -use std::io::Write; +use crate::platform::prelude::*; /// The state object describes the information to visualize for the layout. #[derive(Serialize, Deserialize)] @@ -21,12 +20,13 @@ pub struct LayoutState { pub text_color: Color, } +#[cfg(feature = "std")] impl LayoutState { /// Encodes the state object's information as JSON. - pub fn write_json(&self, writer: W) -> Result<()> + pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, &self) + serde_json::to_writer(writer, self) } } diff --git a/src/layout/mod.rs b/src/layout/mod.rs index c0613ecba..a1da84396 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -10,6 +10,7 @@ mod general_settings; mod layout_direction; mod layout_settings; mod layout_state; +#[cfg(feature = "std")] pub mod parser; pub use self::component::Component; @@ -23,6 +24,7 @@ pub use self::layout_state::LayoutState; use crate::component::{previous_segment, splits, timer, title}; use crate::timing::Timer; +use crate::platform::prelude::*; /// A Layout allows you to combine multiple components together to visualize a /// variety of information the runner is interested in. diff --git a/src/layout/parser.rs b/src/layout/parser.rs index 237f31079..b6b6063a2 100644 --- a/src/layout/parser.rs +++ b/src/layout/parser.rs @@ -43,17 +43,17 @@ pub enum Error { /// Failed to decode a string slice as UTF-8. Utf8Str { /// The underlying error. - source: std::str::Utf8Error, + source: core::str::Utf8Error, }, /// Failed to decode a string as UTF-8. Utf8String { /// The underlying error. - source: std::string::FromUtf8Error, + source: alloc::string::FromUtf8Error, }, /// Failed to parse an integer. ParseInt { /// The underlying error. - source: std::num::ParseIntError, + source: core::num::ParseIntError, }, /// Failed to parse a boolean. ParseBool, @@ -76,7 +76,7 @@ pub enum Error { } /// The Result type for parsing layout files of the original LiveSplit. -pub type Result = std::result::Result; +pub type Result = core::result::Result; enum GradientKind { Transparent, diff --git a/src/lib.rs b/src/lib.rs index 2019cd806..6b851f359 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ clippy::redundant_closure_call, clippy::new_ret_no_self )] +#![cfg_attr(not(feature = "std"), no_std)] //! livesplit-core is a library that provides a lot of functionality for creating a speedrun timer. //! @@ -46,6 +47,8 @@ //! assert_eq!(timer.current_phase(), TimerPhase::NotRunning); //! ``` +extern crate alloc; + mod platform; #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] @@ -60,7 +63,9 @@ macro_rules! catch { pub mod analysis; pub mod comparison; pub mod component; +#[cfg(feature = "std")] mod hotkey_config; +#[cfg(feature = "std")] mod hotkey_system; pub mod layout; #[cfg(feature = "rendering")] @@ -70,21 +75,26 @@ pub mod settings; #[cfg(test)] pub mod tests_helper; pub mod timing; +#[cfg(feature = "std")] mod xml_util; -pub use { - crate::{ - hotkey_config::HotkeyConfig, - hotkey_system::HotkeySystem, - layout::{ - Component, Editor as LayoutEditor, GeneralSettings as GeneralLayoutSettings, Layout, - }, - run::{Attempt, Editor as RunEditor, Run, RunMetadata, Segment, SegmentHistory}, - timing::{ - AtomicDateTime, GameTime, RealTime, SharedTimer, Time, TimeSpan, TimeStamp, Timer, - TimerPhase, TimingMethod, - }, +pub use crate::{ + layout::{Component, Editor as LayoutEditor, GeneralSettings as GeneralLayoutSettings, Layout}, + platform::{indexmap, DateTime, Utc}, + run::{Attempt, Editor as RunEditor, Run, RunMetadata, Segment, SegmentHistory}, + timing::{ + AtomicDateTime, GameTime, RealTime, Time, TimeSpan, TimeStamp, Timer, TimerPhase, + TimingMethod, }, - chrono::{DateTime, Utc}, - indexmap, livesplit_hotkey as hotkey, palette, parking_lot, }; +pub use livesplit_hotkey as hotkey; +pub use palette; + +#[cfg(not(feature = "std"))] +pub use crate::platform::{register_clock, Clock, Duration}; + +#[cfg(feature = "std")] +pub use parking_lot; + +#[cfg(feature = "std")] +pub use crate::{hotkey_config::HotkeyConfig, hotkey_system::HotkeySystem, timing::SharedTimer}; diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 0bb18be6a..b5e7e50b2 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -1,9 +1,21 @@ -#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] -mod wasm; -#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] -pub use self::wasm::*; +cfg_if::cfg_if! { + if #[cfg(not(feature = "std"))] { + mod no_std; + pub use self::no_std::*; + } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] { + mod wasm; + pub use self::wasm::*; + } else { + mod normal; + pub use self::normal::*; + } +} -#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))] -mod normal; -#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))] -pub use self::normal::*; +pub mod prelude { + pub use alloc::borrow::ToOwned; + pub use alloc::boxed::Box; + pub use alloc::string::String; + pub use alloc::string::ToString; + pub use alloc::vec::Vec; + pub use alloc::{format, vec}; +} diff --git a/src/platform/no_std/indexmap.rs b/src/platform/no_std/indexmap.rs new file mode 100644 index 000000000..378363405 --- /dev/null +++ b/src/platform/no_std/indexmap.rs @@ -0,0 +1,127 @@ +//! no-std polyfill for indexmap. + +/// IndexMap is a hash table where the iteration order of the key-value pairs is +/// independent of the hash values of the keys. +pub mod map { + use crate::platform::prelude::*; + use core::{fmt, marker::PhantomData}; + use serde::{ + de::{MapAccess, Visitor}, + ser::SerializeMap, + Deserialize, Deserializer, Serialize, Serializer, + }; + + /// A hash table where the iteration order of the key-value pairs is + /// independent of the hash values of the keys. + #[derive(Default, Clone, Debug, PartialEq)] + pub struct IndexMap(Vec<(K, V)>); + + /// An iterator over the entries of a IndexMap. + pub struct Iter<'a, K, V>(core::slice::Iter<'a, (K, V)>); + + impl IndexMap { + /// Insert a key-value pair in the map. + pub fn insert(&mut self, key: K, value: V) { + if let Some(index) = self.0.iter().position(|(k, _)| k == &key) { + self.0[index] = (key, value); + } else { + self.0.push((key, value)); + } + } + + /// Remove the key-value pair equivalent to key. + pub fn shift_remove(&mut self, key: &K2) + where + K: core::borrow::Borrow, + K2: ?Sized + PartialEq, + { + if let Some(index) = self.0.iter().position(|(k, _)| k.borrow() == key) { + self.0.remove(index); + } + } + + /// Return an iterator over the key-value pairs of the map, in their order. + pub fn iter(&self) -> Iter<'_, K, V> { + Iter(self.0.iter()) + } + + /// Remove all key-value pairs in the map, while preserving its capacity. + pub fn clear(&mut self) { + self.0.clear(); + } + } + + impl<'a, K, V> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + fn next(&mut self) -> Option { + self.0.next().map(|(a, b)| (a, b)) + } + } + + impl Serialize for IndexMap + where + K: PartialEq + Serialize, + V: Serialize, + { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut map = serializer.serialize_map(Some(self.0.len()))?; + for (k, v) in self.iter() { + map.serialize_entry(k, v)?; + } + map.end() + } + } + + impl<'de, K, V> Deserialize<'de> for IndexMap + where + K: PartialEq + Deserialize<'de>, + V: Deserialize<'de>, + { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_map(IndexMapVisitor::new()) + } + } + + struct IndexMapVisitor { + marker: PhantomData IndexMap>, + } + + impl IndexMapVisitor { + fn new() -> Self { + IndexMapVisitor { + marker: PhantomData, + } + } + } + + impl<'de, K, V> Visitor<'de> for IndexMapVisitor + where + K: PartialEq + Deserialize<'de>, + V: Deserialize<'de>, + { + type Value = IndexMap; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a map") + } + + fn visit_map(self, mut access: M) -> Result + where + M: MapAccess<'de>, + { + let mut map = IndexMap(Vec::with_capacity(access.size_hint().unwrap_or(0))); + + while let Some((key, value)) = access.next_entry()? { + map.insert(key, value); + } + + Ok(map) + } + } +} diff --git a/src/platform/no_std/mod.rs b/src/platform/no_std/mod.rs new file mode 100644 index 000000000..efa0ffbc4 --- /dev/null +++ b/src/platform/no_std/mod.rs @@ -0,0 +1,3 @@ +mod time; +pub use self::time::*; +pub mod indexmap; diff --git a/src/platform/no_std/time.rs b/src/platform/no_std/time.rs new file mode 100644 index 000000000..5273a2ecd --- /dev/null +++ b/src/platform/no_std/time.rs @@ -0,0 +1,159 @@ +use crate::platform::prelude::*; +use core::marker::PhantomData; +use core::ops::{Add, Sub}; +use core::sync::atomic::{self, AtomicPtr}; +use derive_more::{Add, Neg, Sub}; + +/// A clock is a global handler that can be registered for providing the high +/// precision time stamps on a `no_std` target. +pub trait Clock: 'static { + /// Returns the current point in time as a Duration. + fn now(&self) -> Duration; +} + +static CLOCK: AtomicPtr> = AtomicPtr::new(core::ptr::null_mut()); + +/// Registers a clock as the global handler for providing the high precision +/// time stamps on a `no_std` target. +pub fn register_clock(clock: impl Clock) { + let clock: Box = Box::new(clock); + let clock = Box::new(clock); + // FIXME: This isn't entirely clean as this should really be + // compare_and_swap, but we can't do that on every platform. + if !CLOCK.load(atomic::Ordering::SeqCst).is_null() { + panic!("The clock has already been registered"); + } + CLOCK.store(Box::into_raw(clock), atomic::Ordering::SeqCst); +} + +#[derive(Copy, Clone, PartialEq, Debug, Default)] +struct FFIDateTime { + year: u16, + month: u8, + day: u8, + hours: u8, + minutes: u8, + seconds: u8, +} + +/// The local time zone. +pub struct Local; + +/// A date and a time of day. +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct DateTime(PhantomData, FFIDateTime); + +/// A time zone. +pub trait TimeZone: Sized { + fn datetime_from_str(&self, s: &str, fmt: &str) -> Result, ParseError>; +} + +/// The UTC time zone. +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct Utc; + +/// Failed to parse a time. +#[derive(Debug)] +pub struct ParseError; + +/// A span of time. +#[derive(Add, Sub, Neg, Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] +pub struct Duration(i128); + +/// A point in time. +#[derive(Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Debug)] +pub struct Instant(i128); + +impl Instant { + /// Accesses the current point in time. + pub fn now() -> Self { + let clock = CLOCK.load(atomic::Ordering::SeqCst); + if clock.is_null() { + panic!("No clock registered"); + } + let clock = unsafe { &*clock }; + let Duration(t) = clock.now(); + Instant(t) + } +} + +impl Sub for Instant { + type Output = Duration; + + fn sub(self, rhs: Instant) -> Duration { + Duration(self.0 - rhs.0) + } +} + +impl Duration { + /// Creates a duration from the provided amount of nanoseconds. + pub fn nanoseconds(nanos: i64) -> Self { + Duration(nanos as _) + } + + /// Creates a duration from the provided amount of microseconds. + pub fn microseconds(micros: i64) -> Self { + Duration(micros as i128 * 1_000) + } + + /// Returns the total amount of microseconds. + pub fn num_microseconds(self) -> Option { + Some(self.0 / 1_000) + } + + /// Converts a core::time::Duration to a Duration. + pub fn from_std(val: core::time::Duration) -> Option { + let secs = val.as_secs() as i128; + let secs_as_nanos = secs * 1_000_000_000; + Some(Duration(val.subsec_nanos() as i128 + secs_as_nanos)) + } +} + +impl TimeZone for Utc { + fn datetime_from_str(&self, _: &str, _: &str) -> Result, ParseError> { + Ok(DateTime(PhantomData, Default::default())) + } +} + +impl Add for DateTime { + type Output = DateTime; + + fn add(self, _: Duration) -> DateTime { + self + } +} + +impl DateTime { + /// Returns the duration between two date times. + pub fn signed_duration_since(self, _: DateTime) -> Duration { + Duration::nanoseconds(0) + } + + /// Formats the date time as a string. + pub fn format(&self, _: &str) -> String { + format!( + "{:02}/{:02}/{:04} {:02}:{:02}:{:02}", + self.1.month, self.1.day, self.1.year, self.1.hours, self.1.minutes, self.1.seconds + ) + } + + /// Formats the date time as a RFC 2822 string. + pub fn to_rfc2822(&self) -> &'static str { + "Tue, 1 Jul 2003 10:52:37 +0200" + } + + /// Formats the date time as a RFC 3339 string. + pub fn to_rfc3339(&self) -> &'static str { + "1996-12-19T16:39:57-08:00" + } + + /// Changes the time zone of a date time (and adjust the time accordingly). + pub fn with_timezone(&self, _: &Tz2) -> DateTime { + DateTime(PhantomData, Default::default()) + } +} + +/// Returns the current date time. +pub fn utc_now() -> DateTime { + DateTime(PhantomData, Default::default()) +} diff --git a/src/platform/normal/mod.rs b/src/platform/normal/mod.rs index 26318252d..e95a0b543 100644 --- a/src/platform/normal/mod.rs +++ b/src/platform/normal/mod.rs @@ -1,8 +1,8 @@ #![allow(missing_docs)] -pub use std::time::{Duration, Instant}; - -use chrono::{DateTime, Utc}; +pub use chrono::{DateTime, Duration, Local, Utc}; +pub use indexmap; +pub use std::time::Instant; pub fn utc_now() -> DateTime { Utc::now() diff --git a/src/platform/wasm/mod.rs b/src/platform/wasm/mod.rs index cbb91dfdd..b028711fe 100644 --- a/src/platform/wasm/mod.rs +++ b/src/platform/wasm/mod.rs @@ -3,8 +3,10 @@ mod time; pub use self::time::*; +pub use chrono::{DateTime, Duration, Local, Utc}; +pub use indexmap; -use std::mem; +use core::mem; #[no_mangle] pub extern "C" fn alloc(size: usize) -> *mut u8 { @@ -21,7 +23,7 @@ pub extern "C" fn dealloc(ptr: *mut u8, cap: usize) { } } -use chrono::{DateTime, NaiveDateTime, Utc}; +use chrono::NaiveDateTime; use std::mem::MaybeUninit; #[repr(C)] diff --git a/src/platform/wasm/time.rs b/src/platform/wasm/time.rs index 60b3b8a04..bc28a7715 100644 --- a/src/platform/wasm/time.rs +++ b/src/platform/wasm/time.rs @@ -1,5 +1,5 @@ use ordered_float::OrderedFloat; -use std::ops::Sub; +use core::ops::Sub; extern "C" { fn Instant_now() -> f64; @@ -24,5 +24,3 @@ impl Sub for Instant { Duration::new(secs, nanos) } } - -pub use std::time::Duration; diff --git a/src/rendering/software/mod.rs b/src/rendering/software/mod.rs index 8141b7b74..cbecc5022 100644 --- a/src/rendering/software/mod.rs +++ b/src/rendering/software/mod.rs @@ -7,7 +7,7 @@ // Without MMX the floating point calculations don't follow IEEE 754. So the // tests fail to produce the correct checksums. - // TODO: We use SSE as an approximation for the cfg, because MMX isn't + // FIXME: We use SSE as an approximation for the cfg, because MMX isn't // supported by Rust just yet. not(all( target_arch = "x86", diff --git a/src/run/editor/cleaning.rs b/src/run/editor/cleaning.rs index be4ba6590..cb0cc078a 100644 --- a/src/run/editor/cleaning.rs +++ b/src/run/editor/cleaning.rs @@ -9,9 +9,10 @@ use crate::analysis::sum_of_segments::{best, track_branch, Prediction}; use crate::timing::formatter::{Short, TimeFormatter}; use crate::{Attempt, Run, Segment, TimeSpan, TimingMethod}; -use chrono::Local; -use std::fmt; -use std::mem::replace; +use crate::platform::Local; +use core::fmt; +use core::mem::replace; +use crate::platform::prelude::*; /// A Sum of Best Cleaner allows you to interactively remove potential issues in /// the Segment History that lead to an inaccurate Sum of Best. If you skip a diff --git a/src/run/editor/fuzzy_list.rs b/src/run/editor/fuzzy_list.rs index 20c1032e9..31aebf559 100644 --- a/src/run/editor/fuzzy_list.rs +++ b/src/run/editor/fuzzy_list.rs @@ -1,5 +1,6 @@ -use std::collections::BinaryHeap; -use std::usize; +use alloc::collections::BinaryHeap; +use core::usize; +use crate::platform::prelude::*; /// With a Fuzzy List, you can implement a fuzzy searching algorithm. The list /// stores all the items that can be searched for. With the `search` method you diff --git a/src/run/editor/mod.rs b/src/run/editor/mod.rs index 8cd3df31a..c84b31f40 100644 --- a/src/run/editor/mod.rs +++ b/src/run/editor/mod.rs @@ -5,16 +5,17 @@ //! kind of User Interface. use super::{ComparisonError, ComparisonResult}; +use crate::platform::prelude::*; use crate::timing::ParseError as ParseTimeSpanError; use crate::{ comparison, settings::{CachedImageId, Image}, Run, Segment, Time, TimeSpan, TimingMethod, }; +use core::mem::swap; +use core::num::ParseIntError; use odds::slice::rotate_left; use snafu::{OptionExt, ResultExt}; -use std::mem::swap; -use std::num::ParseIntError; pub mod cleaning; mod fuzzy_list; @@ -29,7 +30,7 @@ pub use self::segment_row::SegmentRow; pub use self::state::{Buttons as ButtonsState, Segment as SegmentState, State}; /// Describes an Error that occurred while parsing a time. -#[derive(Debug, snafu::Snafu, derive_more::From)] +#[derive(Debug, snafu::Snafu)] pub enum ParseError { /// Couldn't parse the time. ParseTime { @@ -233,7 +234,7 @@ impl Editor { where S: AsRef, { - self.set_offset(offset.as_ref().parse()?); + self.set_offset(offset.as_ref().parse().context(ParseTime)?); Ok(()) } @@ -880,7 +881,7 @@ fn parse_positive(time: S) -> Result, ParseError> where S: AsRef, { - let time = TimeSpan::parse_opt(time)?; + let time = TimeSpan::parse_opt(time).context(ParseTime)?; if time.map_or(false, |t| t < TimeSpan::zero()) { Err(ParseError::NegativeTimeNotAllowed) } else { diff --git a/src/run/editor/state.rs b/src/run/editor/state.rs index 125622018..fb36ddd1b 100644 --- a/src/run/editor/state.rs +++ b/src/run/editor/state.rs @@ -5,8 +5,7 @@ use crate::settings::{CachedImageId, ImageData}; use crate::timing::formatter::none_wrapper::EmptyWrapper; use crate::timing::formatter::{Accuracy, Short, TimeFormatter}; use serde::{Deserialize, Serialize}; -use serde_json::{to_writer, Result as JsonResult}; -use std::io::Write; +use crate::platform::prelude::*; /// Represents the current state of the Run Editor in order to visualize it /// properly. @@ -93,13 +92,14 @@ pub enum SelectionState { Active, } +#[cfg(feature = "std")] impl State { /// Encodes the state object's information as JSON. - pub fn write_json(&self, writer: W) -> JsonResult<()> + pub fn write_json(&self, writer: W) -> serde_json::Result<()> where - W: Write, + W: std::io::Write, { - to_writer(writer, self) + serde_json::to_writer(writer, self) } } diff --git a/src/run/mod.rs b/src/run/mod.rs index c9682d65f..ca287609a 100644 --- a/src/run/mod.rs +++ b/src/run/mod.rs @@ -17,8 +17,10 @@ mod attempt; pub mod editor; +#[cfg(feature = "std")] pub mod parser; mod run_metadata; +#[cfg(feature = "std")] pub mod saver; mod segment; mod segment_history; @@ -34,12 +36,15 @@ pub use segment_history::SegmentHistory; use crate::comparison::{default_generators, personal_best, ComparisonGenerator}; use crate::{settings::Image, AtomicDateTime, Time, TimeSpan, TimingMethod}; +use alloc::borrow::Cow; +use core::cmp::max; use ordered_float::OrderedFloat; -use std::borrow::Cow; -use std::cmp::max; -use std::collections::HashSet; +use hashbrown::HashSet; +#[cfg(feature = "std")] use std::path::PathBuf; -use unicase; +#[cfg(not(feature = "std"))] +use alloc::string::String as PathBuf; +use crate::platform::prelude::*; /// A Run stores the split times for a specific game and category of a runner. /// diff --git a/src/run/parser/composite.rs b/src/run/parser/composite.rs index ecdc2fb16..e9a97ea0d 100644 --- a/src/run/parser/composite.rs +++ b/src/run/parser/composite.rs @@ -36,10 +36,10 @@ use super::{ worstrun, wsplit, TimerKind, }; use crate::Run; +use core::result::Result as StdResult; use snafu::ResultExt; use std::io::{self, BufRead, Seek, SeekFrom}; use std::path::PathBuf; -use std::result::Result as StdResult; /// The Error type for splits files that couldn't be parsed by the Composite /// Parser. diff --git a/src/run/parser/face_split.rs b/src/run/parser/face_split.rs index 70f99fbe1..0d916c406 100644 --- a/src/run/parser/face_split.rs +++ b/src/run/parser/face_split.rs @@ -1,11 +1,11 @@ //! Provides the parser for FaceSplit splits files. use crate::{settings::Image, timing, RealTime, Run, Segment, Time, TimeSpan}; +use alloc::borrow::Cow; +use core::num::ParseIntError; +use core::result::Result as StdResult; use snafu::{OptionExt, ResultExt}; -use std::borrow::Cow; use std::io::{self, BufRead}; -use std::num::ParseIntError; -use std::result::Result as StdResult; /// The Error type for splits files that couldn't be parsed by the FaceSplit /// Parser. diff --git a/src/run/parser/flitter/mod.rs b/src/run/parser/flitter/mod.rs index 831f9c641..256a13b72 100644 --- a/src/run/parser/flitter/mod.rs +++ b/src/run/parser/flitter/mod.rs @@ -1,9 +1,9 @@ //! Provides the parser for Flitter splits files. use crate::{comparison::world_record, Run, Segment, Time, TimeSpan}; +use core::result::Result as StdResult; use serde::Deserialize; use std::io::BufRead; -use std::result::Result as StdResult; mod s_expressions; diff --git a/src/run/parser/flitter/s_expressions.rs b/src/run/parser/flitter/s_expressions.rs index 43eb36a31..d75e1a19b 100644 --- a/src/run/parser/flitter/s_expressions.rs +++ b/src/run/parser/flitter/s_expressions.rs @@ -1,10 +1,10 @@ //! Implements a serde deserializer for S-Expressions. //! http://people.csail.mit.edu/rivest/Sexp.txt +use core::fmt::Display; +use core::num::ParseIntError; use serde::de::{self, DeserializeOwned, DeserializeSeed, MapAccess, SeqAccess, Visitor}; -use std::fmt::Display; use std::io::{self, BufRead}; -use std::num::ParseIntError; use utf8::{BufReadDecoder, BufReadDecoderError}; /// The Error types for splits files that couldn't be parsed by the Flitter @@ -61,7 +61,7 @@ impl de::Error for Error { } } -pub type Result = std::result::Result; +pub type Result = core::result::Result; pub struct Deserializer { decoder: BufReadDecoder, diff --git a/src/run/parser/livesplit.rs b/src/run/parser/livesplit.rs index a174926a8..5b6fcf125 100644 --- a/src/run/parser/livesplit.rs +++ b/src/run/parser/livesplit.rs @@ -7,10 +7,10 @@ use crate::xml_util::{ }; use crate::{AtomicDateTime, Run, RunMetadata, Segment, Time, TimeSpan}; use chrono::{DateTime, TimeZone, Utc}; +use core::str; use quick_xml::Reader; use std::io::BufRead; use std::path::PathBuf; -use std::str; use crate::xml_util::Error as XmlError; use chrono::ParseError as ChronoError; @@ -27,22 +27,22 @@ pub enum Error { /// Failed to decode a string slice as UTF-8. Utf8Str { /// The underlying error. - source: std::str::Utf8Error, + source: core::str::Utf8Error, }, /// Failed to decode a string as UTF-8. Utf8String { /// The underlying error. - source: std::string::FromUtf8Error, + source: alloc::string::FromUtf8Error, }, /// Failed to parse an integer. ParseInt { /// The underlying error. - source: std::num::ParseIntError, + source: core::num::ParseIntError, }, /// Failed to parse a floating point number. ParseFloat { /// The underlying error. - source: std::num::ParseFloatError, + source: core::num::ParseFloatError, }, /// Failed to parse a time. ParseTime { @@ -64,7 +64,7 @@ pub enum Error { } /// The Result type for the LiveSplit Parser. -pub type Result = std::result::Result; +pub type Result = core::result::Result; // FIXME: Generalized Type Ascription (GTA 6) #[inline] diff --git a/src/run/parser/llanfair.rs b/src/run/parser/llanfair.rs index 9efeec836..fbabe67b1 100644 --- a/src/run/parser/llanfair.rs +++ b/src/run/parser/llanfair.rs @@ -5,8 +5,8 @@ use byteorder::{ReadBytesExt, BE}; use image::{png, ColorType, ImageBuffer, Rgba}; use snafu::{OptionExt, ResultExt}; use std::io::{self, Read, Seek, SeekFrom}; -use std::result::Result as StdResult; -use std::str::{from_utf8, Utf8Error}; +use core::result::Result as StdResult; +use core::str::{from_utf8, Utf8Error}; /// The Error type for splits files that couldn't be parsed by the Llanfair /// Parser. diff --git a/src/run/parser/llanfair2.rs b/src/run/parser/llanfair2.rs index e0f3b267c..db335563a 100644 --- a/src/run/parser/llanfair2.rs +++ b/src/run/parser/llanfair2.rs @@ -7,7 +7,7 @@ use crate::{RealTime, Run, Segment, Time, TimeSpan}; use byteorder::{ByteOrder, BE}; use image::{png, ColorType, ImageBuffer, Rgba}; use quick_xml::Reader; -use std::cmp::min; +use core::cmp::min; use std::io::BufRead; use crate::xml_util::Error as XmlError; @@ -24,24 +24,24 @@ pub enum Error { /// Failed to decode a string slice as UTF-8. Utf8Str { /// The underlying error. - source: std::str::Utf8Error, + source: core::str::Utf8Error, }, /// Failed to decode a string as UTF-8. Utf8String { /// The underlying error. - source: std::string::FromUtf8Error, + source: alloc::string::FromUtf8Error, }, /// Failed to parse an integer. Int { /// The underlying error. - source: std::num::ParseIntError, + source: core::num::ParseIntError, }, /// Failed to parse an image. Image, } /// The Result type for the Llanfair Rewrite Parser. -pub type Result = std::result::Result; +pub type Result = core::result::Result; // FIXME: Generalized Type Ascription (GTA 6) #[inline] diff --git a/src/run/parser/llanfair_gered.rs b/src/run/parser/llanfair_gered.rs index 9007afbee..2f9c6dceb 100644 --- a/src/run/parser/llanfair_gered.rs +++ b/src/run/parser/llanfair_gered.rs @@ -26,17 +26,17 @@ pub enum Error { /// Failed to decode a string slice as UTF-8. Utf8Str { /// The underlying error. - source: std::str::Utf8Error, + source: core::str::Utf8Error, }, /// Failed to decode a string as UTF-8. Utf8String { /// The underlying error. - source: std::string::FromUtf8Error, + source: alloc::string::FromUtf8Error, }, /// Failed to parse an integer. Int { /// The underlying error. - source: std::num::ParseIntError, + source: core::num::ParseIntError, }, /// The length of a buffer was too large. LengthOutOfBounds, @@ -45,7 +45,7 @@ pub enum Error { } /// The Result type for the Llanfair (Gered) Parser. -pub type Result = std::result::Result; +pub type Result = core::result::Result; // FIXME: Generalized Type Ascription (GTA 6) #[inline] diff --git a/src/run/parser/portal2_live_timer.rs b/src/run/parser/portal2_live_timer.rs index 36dbec7a2..5a493831d 100644 --- a/src/run/parser/portal2_live_timer.rs +++ b/src/run/parser/portal2_live_timer.rs @@ -1,10 +1,10 @@ //! Provides the parser for Portal 2 Live Timer splits files. use crate::{GameTime, Run, Segment, TimeSpan}; +use core::num::ParseFloatError; +use core::result::Result as StdResult; use snafu::{OptionExt, ResultExt}; use std::io::{self, BufRead}; -use std::num::ParseFloatError; -use std::result::Result as StdResult; /// The Error types for splits files that couldn't be parsed by the Portal 2 /// Live Timer Parser. diff --git a/src/run/parser/shit_split.rs b/src/run/parser/shit_split.rs index 087c7c7e8..e56c2d92e 100644 --- a/src/run/parser/shit_split.rs +++ b/src/run/parser/shit_split.rs @@ -1,10 +1,10 @@ //! Provides the parser for ShitSplit splits files. use crate::{timing, GameTime, Run, Segment, TimeSpan}; +use core::num::ParseIntError; +use core::result::Result as StdResult; use snafu::{OptionExt, ResultExt}; use std::io::{self, BufRead}; -use std::num::ParseIntError; -use std::result::Result as StdResult; /// The Error type for splits files that couldn't be parsed by the ShitSplit /// Parser. diff --git a/src/run/parser/source_live_timer.rs b/src/run/parser/source_live_timer.rs index 023e33696..8a1d1aef7 100644 --- a/src/run/parser/source_live_timer.rs +++ b/src/run/parser/source_live_timer.rs @@ -1,12 +1,12 @@ //! Provides the parser for the SourceLiveTimer splits files. use crate::{GameTime, Run, Segment, TimeSpan}; +use core::result::Result as StdResult; use serde::Deserialize; use serde_json::de::from_reader; use serde_json::Error as JsonError; use snafu::ResultExt; use std::io::Read; -use std::result::Result as StdResult; /// The Error type for splits files that couldn't be parsed by the /// SourceLiveTimer Parser. diff --git a/src/run/parser/splits_io.rs b/src/run/parser/splits_io.rs index 344bd24b1..2c119a0c9 100644 --- a/src/run/parser/splits_io.rs +++ b/src/run/parser/splits_io.rs @@ -1,12 +1,12 @@ //! Provides the parser for generic Splits I/O splits files. use crate::{Run, Segment as LiveSplitSegment, Time, TimeSpan}; +use core::result::Result as StdResult; use serde::{Deserialize, Serialize}; use serde_json::de::from_reader; use serde_json::Error as JsonError; use snafu::ResultExt; use std::io::Read; -use std::result::Result as StdResult; /// The Error type for splits files that couldn't be parsed by the generic /// Splits I/O Parser. diff --git a/src/run/parser/splitterz.rs b/src/run/parser/splitterz.rs index 764ef5a82..581631cb8 100644 --- a/src/run/parser/splitterz.rs +++ b/src/run/parser/splitterz.rs @@ -1,11 +1,11 @@ //! Provides the parser for SplitterZ splits files. use crate::{settings::Image, timing, RealTime, Run, Segment, TimeSpan}; +use alloc::borrow::Cow; +use core::num::ParseIntError; +use core::result::Result as StdResult; use snafu::ResultExt; -use std::borrow::Cow; use std::io::{self, BufRead}; -use std::num::ParseIntError; -use std::result::Result as StdResult; /// The Error type for splits files that couldn't be parsed by the SplitterZ /// Parser. diff --git a/src/run/parser/splitty.rs b/src/run/parser/splitty.rs index 01727d2c3..722ba0290 100644 --- a/src/run/parser/splitty.rs +++ b/src/run/parser/splitty.rs @@ -1,12 +1,12 @@ //! Provides the parser for Splitty splits files. use crate::{Run, Segment, Time, TimeSpan, TimingMethod}; +use core::result::Result as StdResult; use serde::Deserialize; use serde_json::de::from_reader; use serde_json::Error as JsonError; use snafu::ResultExt; use std::io::Read; -use std::result::Result as StdResult; /// The Error type for splits files that couldn't be parsed by the Splitty /// Parser. diff --git a/src/run/parser/time_split_tracker.rs b/src/run/parser/time_split_tracker.rs index ad3506e1f..fa46218d7 100644 --- a/src/run/parser/time_split_tracker.rs +++ b/src/run/parser/time_split_tracker.rs @@ -3,12 +3,12 @@ use super::super::ComparisonError; use crate::{settings::Image, timing, AtomicDateTime, RealTime, Run, Segment, Time, TimeSpan}; use chrono::{TimeZone, Utc}; +use core::num::ParseIntError; +use core::result::Result as StdResult; use snafu::{OptionExt, ResultExt}; use std::fs::File; use std::io::{self, BufRead, BufReader}; -use std::num::ParseIntError; use std::path::PathBuf; -use std::result::Result as StdResult; /// The Error type for splits files that couldn't be parsed by the Time /// Split Tracker Parser. diff --git a/src/run/parser/timer_kind.rs b/src/run/parser/timer_kind.rs index b1c4e5160..07f9e38c1 100644 --- a/src/run/parser/timer_kind.rs +++ b/src/run/parser/timer_kind.rs @@ -1,4 +1,4 @@ -use std::fmt; +use core::fmt; /// Describes the different Timers available that store splits files. #[derive(Clone, Eq, PartialEq, Hash, Debug)] diff --git a/src/run/parser/urn.rs b/src/run/parser/urn.rs index 157656fb2..580b91c80 100644 --- a/src/run/parser/urn.rs +++ b/src/run/parser/urn.rs @@ -1,12 +1,12 @@ //! Provides the parser for Urn splits files. use crate::{Run, Segment, Time, TimeSpan}; +use core::result::Result as StdResult; use serde::Deserialize; use serde_json::de::from_reader; use serde_json::Error as JsonError; use snafu::ResultExt; use std::io::Read; -use std::result::Result as StdResult; /// The Error type for splits files that couldn't be parsed by the Urn /// Parser. diff --git a/src/run/parser/worstrun.rs b/src/run/parser/worstrun.rs index 4e2646775..26b13b56e 100644 --- a/src/run/parser/worstrun.rs +++ b/src/run/parser/worstrun.rs @@ -1,12 +1,12 @@ //! Provides the parser for worstrun splits files. use crate::{Run, Segment, Time, TimeSpan}; +use core::result::Result as StdResult; use serde::Deserialize; use serde_json::de::from_reader; use serde_json::Error as JsonError; use snafu::ResultExt; use std::io::Read; -use std::result::Result as StdResult; /// The Error type for splits files that couldn't be parsed by the worstrun /// Parser. diff --git a/src/run/parser/wsplit.rs b/src/run/parser/wsplit.rs index 6aace61b8..efef860eb 100644 --- a/src/run/parser/wsplit.rs +++ b/src/run/parser/wsplit.rs @@ -1,10 +1,10 @@ //! Provides the parser for WSplit splits files. use crate::{settings::Image, RealTime, Run, Segment, TimeSpan}; +use core::num::{ParseFloatError, ParseIntError}; +use core::result::Result as StdResult; use snafu::ResultExt; use std::io::{self, BufRead}; -use std::num::{ParseFloatError, ParseIntError}; -use std::result::Result as StdResult; /// The Error type for splits files that couldn't be parsed by the WSplit /// Parser. diff --git a/src/run/run_metadata.rs b/src/run/run_metadata.rs index 411265db2..1589935df 100644 --- a/src/run/run_metadata.rs +++ b/src/run/run_metadata.rs @@ -1,5 +1,6 @@ -use indexmap::map::{IndexMap, Iter}; +use crate::indexmap::map::{IndexMap, Iter}; use serde::{Deserialize, Serialize}; +use crate::platform::prelude::*; /// The Run Metadata stores additional information about a run, like the /// platform and region of the game. All of this information is optional. diff --git a/src/run/saver/livesplit.rs b/src/run/saver/livesplit.rs index e98cc2ddc..afe6f8d1a 100644 --- a/src/run/saver/livesplit.rs +++ b/src/run/saver/livesplit.rs @@ -26,15 +26,15 @@ use crate::timing::formatter::{Complete, TimeFormatter}; use crate::{settings::Image, Run, Time, TimeSpan, Timer, TimerPhase}; +use alloc::borrow::Cow; use byteorder::{WriteBytesExt, LE}; use chrono::{DateTime, Utc}; +use core::fmt::Display; +use core::mem::replace; +use core::result::Result as StdResult; use quick_xml::events::{BytesDecl, BytesEnd, BytesStart, BytesText, Event}; use quick_xml::{Error as XmlError, Writer}; -use std::borrow::Cow; -use std::fmt::Display; use std::io::Write; -use std::mem::replace; -use std::result::Result as StdResult; static LSS_IMAGE_HEADER: &[u8; 156] = include_bytes!("lss_image_header.bin"); diff --git a/src/run/segment.rs b/src/run/segment.rs index ff02d8961..b3bf24251 100644 --- a/src/run/segment.rs +++ b/src/run/segment.rs @@ -1,6 +1,7 @@ use crate::comparison::personal_best; use crate::{settings::Image, SegmentHistory, Time, TimeSpan, TimingMethod}; -use std::collections::HashMap; +use hashbrown::HashMap; +use crate::platform::prelude::*; /// A Segment describes a point in a speedrun that is suitable for storing a /// split time. This stores the name of that segment, an icon, the split times diff --git a/src/run/segment_history.rs b/src/run/segment_history.rs index 0e14a2d88..61145a196 100644 --- a/src/run/segment_history.rs +++ b/src/run/segment_history.rs @@ -1,6 +1,7 @@ use crate::Time; -use std::cmp::min; -use std::slice::{Iter, IterMut}; +use core::cmp::min; +use core::slice::{Iter, IterMut}; +use crate::platform::prelude::*; /// Stores the segment times achieved for a certain segment. Each segment is /// tagged with an index. Only segment times with an index larger than 0 are diff --git a/src/settings/color.rs b/src/settings/color.rs index 27d9129c4..5b6d66ba9 100644 --- a/src/settings/color.rs +++ b/src/settings/color.rs @@ -1,4 +1,4 @@ -use palette::{Hsla, LinSrgba, Pixel}; +use crate::palette::{Hsla, LinSrgba, Pixel}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// Colors can be used to describe what color to use for visualizing diff --git a/src/settings/field.rs b/src/settings/field.rs index fc58d7cf8..b6f87ff3b 100644 --- a/src/settings/field.rs +++ b/src/settings/field.rs @@ -1,5 +1,6 @@ use super::Value; use serde::{Deserialize, Serialize}; +use crate::platform::prelude::*; /// A Field describes a single setting by its name and its current value. #[derive(Serialize, Deserialize)] diff --git a/src/settings/image/mod.rs b/src/settings/image/mod.rs index 0187e50b2..823a2a8f9 100644 --- a/src/settings/image/mod.rs +++ b/src/settings/image/mod.rs @@ -1,14 +1,12 @@ +use crate::platform::prelude::*; use base64::{display::Base64Display, STANDARD}; +use core::sync::atomic::{AtomicUsize, Ordering}; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; -use std::fs::File; -use std::io::{self, Read}; -use std::path::Path; -use std::sync::atomic::{AtomicUsize, Ordering}; #[cfg(test)] mod tests; -#[cfg(feature = "image-shrinking")] +#[cfg(all(feature = "std", feature = "image-shrinking"))] mod shrinking; static LAST_IMAGE_ID: AtomicUsize = AtomicUsize::new(0); @@ -112,12 +110,15 @@ impl Image { /// Loads an image from the file system. You need to provide a buffer used /// for temporarily storing the image's data. - pub fn from_file(path: P, mut buf: B) -> io::Result + #[cfg(feature = "std")] + pub fn from_file(path: P, mut buf: B) -> std::io::Result where - P: AsRef, + P: AsRef, B: AsMut>, { - let mut file = File::open(path)?; + use std::io::Read; + + let mut file = std::fs::File::open(path)?; let len = file.metadata()?.len() as usize; let buf = buf.as_mut(); @@ -153,13 +154,33 @@ impl Image { /// Modifies an image by replacing its image data with the new image data /// provided. The image's ID changes to a new unique ID. pub fn modify(&mut self, data: &[u8]) { - #[cfg(feature = "image-shrinking")] + #[cfg(all(feature = "std", feature = "image-shrinking"))] let data = { const MAX_IMAGE_SIZE: u32 = 128; shrinking::shrink(data, MAX_IMAGE_SIZE) }; - self.id = LAST_IMAGE_ID.fetch_add(1, Ordering::Relaxed); + cfg_if::cfg_if! { + // FIXME: Some targets don't have atomics, but we can't test for + // this properly yet. So there's a feature you explicitly have to + // opt into to deactivate the usage of atomics. Vice versa would be + // too dangerous, as `default-features = false` would deactivate + // atomics then. However there's also `cargo test --all-features`, + // which is equally dangerous. To detect this, we have an additional + // `internal-use-all-features` feature that is only ever activated + // when `--all-features` is passed, so we can ignore the + // `doesnt-have-atomics` in that case. + // https://github.com/rust-lang/rust/issues/32976 + if #[cfg(any( + not(feature = "doesnt-have-atomics"), + feature = "internal-use-all-features", + ))] { + self.id = LAST_IMAGE_ID.fetch_add(1, Ordering::Relaxed); + } else { + self.id = LAST_IMAGE_ID.load(Ordering::SeqCst) + 1; + LAST_IMAGE_ID.store(self.id, Ordering::SeqCst); + } + } self.data.clear(); self.data.extend_from_slice(&*data); } diff --git a/src/settings/image/shrinking.rs b/src/settings/image/shrinking.rs index 739225e11..fb8b45cd5 100644 --- a/src/settings/image/shrinking.rs +++ b/src/settings/image/shrinking.rs @@ -2,7 +2,7 @@ use image::{ bmp, gif, guess_format, hdr, ico, jpeg, load_from_memory_with_format, png, pnm, tiff, webp, DynamicImage, ImageDecoder, ImageError, ImageFormat, }; -use std::borrow::Cow; +use alloc::borrow::Cow; use std::io::Cursor; fn shrink_inner(data: &[u8], max_dim: u32) -> Result, ImageError> { diff --git a/src/settings/settings_description.rs b/src/settings/settings_description.rs index bd25e0dbf..20e9581b1 100644 --- a/src/settings/settings_description.rs +++ b/src/settings/settings_description.rs @@ -1,5 +1,6 @@ use super::Field; use serde::{Deserialize, Serialize}; +use crate::platform::prelude::*; /// A generic description of the settings available and their current values. #[derive(Default, Serialize, Deserialize)] diff --git a/src/settings/value.rs b/src/settings/value.rs index 18b2c9ec0..37c55d22e 100644 --- a/src/settings/value.rs +++ b/src/settings/value.rs @@ -6,8 +6,9 @@ use crate::{ timing::formatter::{Accuracy, DigitsFormat}, TimingMethod, }; +use core::result::Result as StdResult; use serde::{Deserialize, Serialize}; -use std::result::Result as StdResult; +use crate::platform::prelude::*; /// Describes a setting's value. Such a value can be of a variety of different /// types. diff --git a/src/timing/atomic_date_time.rs b/src/timing/atomic_date_time.rs index 1efeb9c3d..56866ae9a 100644 --- a/src/timing/atomic_date_time.rs +++ b/src/timing/atomic_date_time.rs @@ -1,7 +1,7 @@ use crate::platform::utc_now; use crate::TimeSpan; -use chrono::{DateTime, Utc}; -use std::ops::Sub; +use crate::platform::{DateTime, Utc}; +use core::ops::Sub; /// An Atomic Date Time represents a UTC Date Time that tries to be as close to /// an atomic clock as possible. diff --git a/src/timing/formatter/accuracy.rs b/src/timing/formatter/accuracy.rs index 99668ee6d..afd7e3651 100644 --- a/src/timing/formatter/accuracy.rs +++ b/src/timing/formatter/accuracy.rs @@ -28,7 +28,7 @@ impl Accuracy { } use super::{extract_hundredths, extract_milliseconds, extract_tenths}; -use std::fmt::{Display, Formatter, Result}; +use core::fmt::{Display, Formatter, Result}; #[derive(Debug, PartialEq, Copy, Clone)] pub struct FormattedSeconds { diff --git a/src/timing/formatter/complete.rs b/src/timing/formatter/complete.rs index 532281934..650b0f157 100644 --- a/src/timing/formatter/complete.rs +++ b/src/timing/formatter/complete.rs @@ -1,6 +1,6 @@ use super::{TimeFormatter, ASCII_MINUS}; use crate::TimeSpan; -use std::fmt::{Display, Formatter, Result}; +use core::fmt::{Display, Formatter, Result}; pub struct Inner(Option); diff --git a/src/timing/formatter/days.rs b/src/timing/formatter/days.rs index ff0d79899..5df90a05c 100644 --- a/src/timing/formatter/days.rs +++ b/src/timing/formatter/days.rs @@ -1,6 +1,6 @@ use super::{TimeFormatter, MINUS}; use crate::TimeSpan; -use std::fmt::{Display, Formatter, Result}; +use core::fmt::{Display, Formatter, Result}; pub struct Inner { time: Option, diff --git a/src/timing/formatter/delta.rs b/src/timing/formatter/delta.rs index a8bd3657f..b8916890e 100644 --- a/src/timing/formatter/delta.rs +++ b/src/timing/formatter/delta.rs @@ -1,6 +1,6 @@ use super::{Accuracy, TimeFormatter, DASH, MINUS, PLUS}; use crate::TimeSpan; -use std::fmt::{Display, Formatter, Result}; +use core::fmt::{Display, Formatter, Result}; pub struct Inner { time: Option, diff --git a/src/timing/formatter/mod.rs b/src/timing/formatter/mod.rs index e400ef325..abb501f3f 100644 --- a/src/timing/formatter/mod.rs +++ b/src/timing/formatter/mod.rs @@ -41,8 +41,10 @@ pub use self::regular::Regular; pub use self::short::Short; use crate::TimeSpan; -use std::cmp::min; -use std::fmt::Display; +use core::cmp::min; +use core::fmt::Display; +#[cfg(not(feature = "std"))] +use libm::F64Ext; /// Time Formatters can be used to format optional Time Spans in various ways. pub trait TimeFormatter<'a> { diff --git a/src/timing/formatter/none_wrapper.rs b/src/timing/formatter/none_wrapper.rs index 74e5150c0..e04d587d6 100644 --- a/src/timing/formatter/none_wrapper.rs +++ b/src/timing/formatter/none_wrapper.rs @@ -4,7 +4,7 @@ use super::{TimeFormatter, DASH}; use crate::TimeSpan; -use std::fmt::{Display, Formatter, Result}; +use core::fmt::{Display, Formatter, Result}; /// A Time Span to be formatted by a None Wrapper. pub struct Inner<'a, F, S> { diff --git a/src/timing/formatter/possible_time_save.rs b/src/timing/formatter/possible_time_save.rs index 81dead8d9..eb1a07542 100644 --- a/src/timing/formatter/possible_time_save.rs +++ b/src/timing/formatter/possible_time_save.rs @@ -1,6 +1,6 @@ use super::{Accuracy, TimeFormatter, DASH, MINUS}; use crate::TimeSpan; -use std::fmt::{Display, Formatter, Result}; +use core::fmt::{Display, Formatter, Result}; pub struct Inner { time: Option, diff --git a/src/timing/formatter/regular.rs b/src/timing/formatter/regular.rs index 1ea595c44..1905b0d06 100644 --- a/src/timing/formatter/regular.rs +++ b/src/timing/formatter/regular.rs @@ -1,6 +1,6 @@ use super::{Accuracy, TimeFormatter, DASH, MINUS}; use crate::TimeSpan; -use std::fmt::{Display, Formatter, Result}; +use core::fmt::{Display, Formatter, Result}; pub struct Inner { time: Option, diff --git a/src/timing/formatter/short.rs b/src/timing/formatter/short.rs index aeb492a13..9cb28c7fe 100644 --- a/src/timing/formatter/short.rs +++ b/src/timing/formatter/short.rs @@ -1,6 +1,6 @@ use super::{Accuracy, TimeFormatter, MINUS}; use crate::TimeSpan; -use std::fmt::{Display, Formatter, Result}; +use core::fmt::{Display, Formatter, Result}; pub struct Inner { time: Option, diff --git a/src/timing/formatter/timer.rs b/src/timing/formatter/timer.rs index a8dd987a8..c9a749b27 100644 --- a/src/timing/formatter/timer.rs +++ b/src/timing/formatter/timer.rs @@ -7,7 +7,7 @@ use super::{ TimeFormatter, MINUS, }; use crate::TimeSpan; -use std::fmt::{Display, Formatter, Result}; +use core::fmt::{Display, Formatter, Result}; /// A Time Span to be formatted as the main part of the Time Formatter Pair. pub struct TimeInner { diff --git a/src/timing/mod.rs b/src/timing/mod.rs index 7deb6f885..8df5ea3ff 100644 --- a/src/timing/mod.rs +++ b/src/timing/mod.rs @@ -14,6 +14,8 @@ pub use self::atomic_date_time::AtomicDateTime; pub use self::time::{GameTime, RealTime, Time}; pub use self::time_span::{ParseError, TimeSpan}; pub use self::time_stamp::TimeStamp; -pub use self::timer::{CreationError as TimerCreationError, SharedTimer, Timer}; +#[cfg(feature = "std")] +pub use self::timer::SharedTimer; +pub use self::timer::{CreationError as TimerCreationError, Timer}; pub use self::timer_phase::TimerPhase; pub use self::timing_method::TimingMethod; diff --git a/src/timing/time.rs b/src/timing/time.rs index 8860bb1e2..0e0c66ffe 100644 --- a/src/timing/time.rs +++ b/src/timing/time.rs @@ -1,5 +1,5 @@ use crate::{TimeSpan, TimingMethod}; -use std::ops::{Add, AddAssign, Index, IndexMut, Sub, SubAssign}; +use core::ops::{Add, AddAssign, Index, IndexMut, Sub, SubAssign}; /// A time that can store a Real Time and a Game Time. Both of them are /// optional. diff --git a/src/timing/time_span.rs b/src/timing/time_span.rs index 6d7c8e9e9..9b9287ef1 100644 --- a/src/timing/time_span.rs +++ b/src/timing/time_span.rs @@ -1,10 +1,10 @@ -use crate::platform::Duration as StdDuration; -use chrono::Duration; +use crate::platform::Duration; +use core::num::ParseFloatError; +use core::ops::{AddAssign, SubAssign}; +use core::str::FromStr; use derive_more::{Add, From, Neg, Sub}; use snafu::ResultExt; -use std::num::ParseFloatError; -use std::ops::{AddAssign, SubAssign}; -use std::str::FromStr; +use crate::platform::prelude::*; /// A Time Span represents a certain span of time. #[derive(From, Add, Sub, Neg, Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] @@ -105,8 +105,8 @@ impl Default for TimeSpan { } } -impl From for TimeSpan { - fn from(duration: StdDuration) -> Self { +impl From for TimeSpan { + fn from(duration: core::time::Duration) -> Self { TimeSpan(Duration::from_std(duration).unwrap()) } } @@ -123,8 +123,8 @@ impl SubAssign for TimeSpan { } } +use core::fmt; use serde::de::{self, Deserialize, Deserializer, Visitor}; -use std::fmt; impl<'de> Deserialize<'de> for TimeSpan { fn deserialize(deserializer: D) -> Result diff --git a/src/timing/time_stamp.rs b/src/timing/time_stamp.rs index e976e9901..f61bb801b 100644 --- a/src/timing/time_stamp.rs +++ b/src/timing/time_stamp.rs @@ -1,6 +1,6 @@ use crate::platform::Instant; use crate::TimeSpan; -use std::ops::Sub; +use core::ops::Sub; /// A Time Stamp stores a point in time, that can be used to calculate Time /// Spans. diff --git a/src/timing/timer/mod.rs b/src/timing/timer/mod.rs index 3d0baf5ab..266cc813e 100644 --- a/src/timing/timer/mod.rs +++ b/src/timing/timer/mod.rs @@ -1,9 +1,8 @@ use crate::comparison::personal_best; +use crate::platform::prelude::*; use crate::TimerPhase::*; use crate::{AtomicDateTime, Run, Segment, Time, TimeSpan, TimeStamp, TimerPhase, TimingMethod}; -use parking_lot::RwLock; -use std::mem; -use std::sync::Arc; +use core::mem; #[cfg(test)] mod tests; @@ -61,7 +60,8 @@ pub struct Timer { /// A Shared Timer is a wrapper around the Timer that can be shared across /// multiple threads with multiple owners. -pub type SharedTimer = Arc>; +#[cfg(feature = "std")] +pub type SharedTimer = alloc::sync::Arc>; /// The Error type for creating a new Timer from a Run. #[derive(Debug, snafu::Snafu)] @@ -104,8 +104,9 @@ impl Timer { /// Consumes the Timer and creates a Shared Timer that can be shared across /// multiple threads with multiple owners. + #[cfg(feature = "std")] pub fn into_shared(self) -> SharedTimer { - Arc::new(RwLock::new(self)) + alloc::sync::Arc::new(parking_lot::RwLock::new(self)) } /// Takes out the Run from the Timer and resets the current attempt if there diff --git a/src/xml_util.rs b/src/xml_util.rs index b48e57912..1115f6e42 100644 --- a/src/xml_util.rs +++ b/src/xml_util.rs @@ -1,12 +1,13 @@ use crate::timing; +use alloc::borrow::Cow; +use alloc::string; use chrono::ParseError as ChronoError; +use core::num::{ParseFloatError, ParseIntError}; +use core::ops::Deref; +use core::str; use quick_xml::events::{attributes, BytesStart, Event}; use quick_xml::{Error as XmlError, Reader, Writer}; -use std::borrow::Cow; use std::io::{self, BufRead}; -use std::num::{ParseFloatError, ParseIntError}; -use std::ops::Deref; -use std::{str, string}; /// The Error type for XML-based splits files that couldn't be parsed. #[derive(Debug, snafu::Snafu, derive_more::From)]