diff --git a/.github/workflows/miri.yml b/.github/workflows/miri.yml new file mode 100644 index 000000000..8894dbace --- /dev/null +++ b/.github/workflows/miri.yml @@ -0,0 +1,123 @@ +name: Miri Tests + +on: + push: + # Run in PRs and for bors, but not on master. + branches: + - 'auto' + - 'try' + pull_request: + branches: + - 'master' + schedule: + - cron: '6 6 * * *' # At 6:06 UTC every day. + +env: + CARGO_UNSTABLE_SPARSE_REGISTRY: 'true' + RUSTFLAGS: -Dwarnings + RUST_BACKTRACE: 1 + # Change to specific Rust release to pin + rust_stable: stable + rust_nightly: nightly-2022-11-03 + rust_clippy: 1.65.0 + # When updating this, also update: + # - README.md + # - tokio/README.md + # - CONTRIBUTING.md + # - tokio/Cargo.toml + # - tokio-util/Cargo.toml + # - tokio-test/Cargo.toml + # - tokio-stream/Cargo.toml + # rust_min: 1.49.0 + + + +jobs: + test: + runs-on: ${{ matrix.os }} + env: + RUST_BACKTRACE: 1 + HOST_TARGET: ${{ matrix.host_target }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + host_target: x86_64-unknown-linux-gnu + # - os: macos-latest + # host_target: x86_64-apple-darwin + # - os: windows-latest + # host_target: i686-pc-windows-msvc + # - os: windows-latest + # host_target: i686-pc-windows-msvc + # - os: windows-latest + # host_target: i686-pc-windows-msvc + # - os: windows-latest + # host_target: i686-pc-windows-msvc + steps: + - name: Set the tag GC interval to 1 on linux + if: runner.os == 'Linux' + run: echo "MIRIFLAGS=-Zmiri-tag-gc=1" >> $GITHUB_ENV + + - uses: actions/checkout@v3 + - name: Install Rust ${{ env.rust_nightly }} + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ env.rust_nightly }} + components: miri + - uses: Swatinem/rust-cache@v2 + - name: miri + # Many of tests in tokio/tests and doctests use #[tokio::test] or + # #[tokio::main] that calls epoll_create1 that Miri does not support. + # run: cargo miri test --features full --lib --no-fail-fast + run: | + cargo miri test --package dioxus-core --test miri_stress -- --exact --nocapture + cargo miri test --package dioxus-native-core --test miri_native -- --exact --nocapture + + # working-directory: tokio + env: + # todo: disable memory leaks ignore + MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-retag-fields -Zmiri-ignore-leaks + PROPTEST_CASES: 10 + + # Cache the global cargo directory, but NOT the local `target` directory which + # we cannot reuse anyway when the nightly changes (and it grows quite large + # over time). + # - name: Add cache for cargo + # id: cache + # uses: actions/cache@v3 + # with: + # path: | + # # Taken from . + # ~/.cargo/bin + # ~/.cargo/registry/index + # ~/.cargo/registry/cache + # ~/.cargo/git/db + # # contains package information of crates installed via `cargo install`. + # ~/.cargo/.crates.toml + # ~/.cargo/.crates2.json + # key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + # restore-keys: ${{ runner.os }}-cargo + + # - name: Install rustup-toolchain-install-master + # if: ${{ steps.cache.outputs.cache-hit != 'true' }} + # shell: bash + # run: | + # cargo install -f rustup-toolchain-install-master + # - name: Install "master" toolchain + # shell: bash + # run: | + # if [[ ${{ github.event_name }} == 'schedule' ]]; then + # echo "Building against latest rustc git version" + # git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1 > rust-version + # fi + # toolchain --host ${{ matrix.host_target }} + # - name: Show Rust version + # run: | + # rustup show + # rustc -Vv + # cargo -V + # - name: Test + # run: | + # MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks" cargo +nightly miri test --package dioxus-core --test miri_stress -- --exact --nocapture + # MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-ignore-leaks" cargo +nightly miri test --package dioxus-native-core --test miri_native -- --exact --nocapture diff --git a/packages/core/src/lazynodes.rs b/packages/core/src/lazynodes.rs index 2b7c4feb3..811dbb734 100644 --- a/packages/core/src/lazynodes.rs +++ b/packages/core/src/lazynodes.rs @@ -11,6 +11,7 @@ //! The logic for this was borrowed from . Unfortunately, this crate does not //! support non-static closures, so we've implemented the core logic of `ValueA` in this module. +#[allow(unused_imports)] use smallbox::{smallbox, space::S16, SmallBox}; use crate::{innerlude::VNode, ScopeState}; diff --git a/packages/core/tests/miri_stress.rs b/packages/core/tests/miri_stress.rs index 160baa25d..c73847c19 100644 --- a/packages/core/tests/miri_stress.rs +++ b/packages/core/tests/miri_stress.rs @@ -137,6 +137,82 @@ fn free_works_on_root_hooks() { assert_eq!(Rc::strong_count(&ptr), 1); } +#[test] +fn supports_async() { + use std::time::Duration; + use tokio::time::sleep; + + fn app(cx: Scope) -> Element { + let colors = use_state(&cx, || vec!["green", "blue", "red"]); + let padding = use_state(&cx, || 10); + + use_effect(&cx, colors, |colors| async move { + sleep(Duration::from_millis(1000)).await; + colors.with_mut(|colors| colors.reverse()); + }); + + use_effect(&cx, padding, |padding| async move { + sleep(Duration::from_millis(10)).await; + padding.with_mut(|padding| { + if *padding < 65 { + *padding += 1; + } else { + *padding = 5; + } + }); + }); + + let big = colors[0]; + let mid = colors[1]; + let small = colors[2]; + + cx.render(rsx! { + div { + background: "{big}", + height: "stretch", + width: "stretch", + padding: "50", + label { + "hello", + } + div { + background: "{mid}", + height: "auto", + width: "stretch", + padding: "{padding}", + label { + "World", + } + div { + background: "{small}", + height: "auto", + width: "stretch", + padding: "20", + label { + "ddddddd", + } + } + }, + } + }) + } + + let rt = tokio::runtime::Builder::new_current_thread() + .enable_time() + .build() + .unwrap(); + + rt.block_on(async { + let mut dom = VirtualDom::new(app); + let _ = dom.rebuild(); + + for x in 0..10 { + let _ = dom.wait_for_work().await; + let edits = dom.render_immediate(); + } + }); +} + // #[test] // fn old_props_arent_stale() { // fn app(cx: Scope) -> Element { diff --git a/packages/native-core/Cargo.toml b/packages/native-core/Cargo.toml index 67cbdd8e4..c414258c7 100644 --- a/packages/native-core/Cargo.toml +++ b/packages/native-core/Cargo.toml @@ -30,3 +30,5 @@ lightningcss = "1.0.0-alpha.39" [dev-dependencies] rand = "0.8.5" dioxus = { path = "../dioxus", version = "^0.3.0" } +dioxus-native-core-macro = { path = "../native-core-macro" } +tokio = { version = "*", features = ["full"] } diff --git a/packages/native-core/tests/miri_native.rs b/packages/native-core/tests/miri_native.rs new file mode 100644 index 000000000..5823fb5a1 --- /dev/null +++ b/packages/native-core/tests/miri_native.rs @@ -0,0 +1,146 @@ +use dioxus::prelude::*; +use dioxus_native_core::*; +use dioxus_native_core::{ + node_ref::{AttributeMask, NodeView}, + real_dom::RealDom, + state::{ParentDepState, State}, + NodeMask, SendAnyMap, +}; +use dioxus_native_core_macro::{sorted_str_slice, State}; +use std::{ + sync::{Arc, Mutex}, + time::Duration, +}; +use tokio::time::sleep; + +#[derive(Debug, Clone, PartialEq, Default)] +pub struct BlablaState {} + +/// Font style are inherited by default if not specified otherwise by some of the supported attributes. +impl ParentDepState for BlablaState { + type Ctx = (); + type DepState = (Self,); + + const NODE_MASK: NodeMask = + NodeMask::new_with_attrs(AttributeMask::Static(&sorted_str_slice!(["blabla",]))); + + fn reduce<'a>( + &mut self, + _node: NodeView, + _parent: Option<(&'a Self,)>, + _ctx: &Self::Ctx, + ) -> bool { + false + } +} + +#[derive(Clone, State, Default, Debug)] +pub struct NodeState { + #[parent_dep_state(blabla)] + blabla: BlablaState, +} + +mod dioxus_elements { + macro_rules! builder_constructors { + ( + $( + $(#[$attr:meta])* + $name:ident { + $( + $(#[$attr_method:meta])* + $fil:ident: $vil:ident, + )* + }; + )* + ) => { + $( + #[allow(non_camel_case_types)] + $(#[$attr])* + pub struct $name; + + impl $name { + pub const TAG_NAME: &'static str = stringify!($name); + pub const NAME_SPACE: Option<&'static str> = None; + + $( + pub const $fil: (&'static str, Option<&'static str>, bool) = (stringify!($fil), None, false); + )* + } + + impl GlobalAttributes for $name {} + )* + } + } + + pub trait GlobalAttributes {} + + pub trait SvgAttributes {} + + builder_constructors! { + blabla { + + }; + } +} + +#[test] +fn native_core_is_okay() { + use std::time::Duration; + + fn app(cx: Scope) -> Element { + let colors = use_state(&cx, || vec!["green", "blue", "red"]); + let padding = use_state(&cx, || 10); + + use_effect(&cx, colors, |colors| async move { + sleep(Duration::from_millis(1000)).await; + colors.with_mut(|colors| colors.reverse()); + }); + + use_effect(&cx, padding, |padding| async move { + sleep(Duration::from_millis(10)).await; + padding.with_mut(|padding| { + if *padding < 65 { + *padding += 1; + } else { + *padding = 5; + } + }); + }); + + let big = colors[0]; + let mid = colors[1]; + let small = colors[2]; + + cx.render(rsx! { + blabla {} + }) + } + + let rt = tokio::runtime::Builder::new_current_thread() + .enable_time() + .build() + .unwrap(); + + rt.block_on(async { + let rdom = Arc::new(Mutex::new(RealDom::::new())); + let mut dom = VirtualDom::new(app); + + let muts = dom.rebuild(); + let (to_update, _diff) = rdom.lock().unwrap().apply_mutations(muts); + + let ctx = SendAnyMap::new(); + let ctx = SendAnyMap::new(); + rdom.lock().unwrap().update_state(to_update, ctx); + + for x in 0..10 { + dom.wait_for_work().await; + + let mutations = dom.render_immediate(); + let (to_update, _diff) = rdom.lock().unwrap().apply_mutations(mutations); + + let ctx = SendAnyMap::new(); + let ctx = SendAnyMap::new(); + rdom.lock().unwrap().update_state(to_update, ctx); + } + }); +}