From 48d2fafcc215a5c25573b6975a574e4711171342 Mon Sep 17 00:00:00 2001 From: tison Date: Mon, 21 Sep 2026 14:44:54 +0800 Subject: [PATCH 1/2] test: organize integration targets by primitive --- LICENSE | 4 - asyncband/src/broadcast/mpmc/bounded/tests.rs | 2 +- licenserc.toml | 2 - .../composition.rs} | 24 -- .../{barrier_test.rs => barrier_test/main.rs} | 3 + .../tests/barrier_test/traits.rs | 27 ++ .../tests/blocking_test/composition.rs | 44 +++ .../main.rs} | 2 + .../bounded.rs} | 0 .../tests/broadcast_test/main.rs | 20 ++ .../tests/broadcast_test/traits.rs | 39 +++ .../unbounded.rs} | 0 .../main.rs} | 2 + .../tests/completion_test/traits.rs | 38 +++ .../{condvar_test.rs => condvar_test/main.rs} | 2 + .../tests/condvar_test/traits.rs | 27 ++ .../auto_reset.rs} | 0 tests-integration/tests/event_test/main.rs | 20 ++ .../manual_reset.rs} | 0 tests-integration/tests/event_test/traits.rs | 30 ++ .../{latch_test.rs => latch_test/main.rs} | 2 + tests-integration/tests/latch_test/traits.rs | 27 ++ .../main.rs} | 3 + .../tests/lazy_cell_test/traits.rs | 27 ++ .../tests/lazy_cell_test/unsafe_paths.rs | 73 +++++ tests-integration/tests/mpmc_test/main.rs | 1 + tests-integration/tests/mpmc_test/traits.rs | 50 +++ tests-integration/tests/mpsc_test/main.rs | 1 + tests-integration/tests/mpsc_test/traits.rs | 74 +++++ .../{mutex_test.rs => mutex_test/main.rs} | 3 + tests-integration/tests/mutex_test/traits.rs | 30 ++ .../tests/mutex_test/unsafe_paths.rs | 51 +++ .../main.rs} | 2 + .../tests/once_cell_test/traits.rs | 27 ++ .../main.rs} | 2 + .../tests/once_map_test/traits.rs | 27 ++ .../tests/{once_test.rs => once_test/main.rs} | 2 + tests-integration/tests/once_test/traits.rs | 27 ++ tests-integration/tests/oneshot_test/main.rs | 1 + .../tests/oneshot_test/traits.rs | 34 ++ .../{phaser_test.rs => phaser_test/main.rs} | 2 + tests-integration/tests/phaser_test/traits.rs | 36 ++ .../tests/pool_recycle_cancelled_test.rs | 245 -------------- .../tests/pool_replenish_test.rs | 308 ------------------ .../acquire.rs} | 87 ++--- .../behavior.rs} | 68 +--- tests-integration/tests/pool_test/main.rs | 23 ++ tests-integration/tests/pool_test/recycle.rs | 193 +++++++++++ .../tests/pool_test/replenish.rs | 152 +++++++++ tests-integration/tests/pool_test/support.rs | 100 ++++++ tests-integration/tests/pool_test/traits.rs | 49 +++ .../{rwlock_test.rs => rwlock_test/main.rs} | 3 + tests-integration/tests/rwlock_test/traits.rs | 37 +++ .../unsafe_paths.rs} | 87 ----- .../main.rs} | 2 + .../tests/semaphore_test/traits.rs | 27 ++ .../main.rs} | 2 + .../tests/shutdown_test/traits.rs | 33 ++ .../main.rs} | 2 + .../tests/singleflight_test/traits.rs | 27 ++ tests-integration/tests/traits_test.rs | 275 ---------------- .../main.rs} | 2 + .../tests/waitgroup_test/traits.rs | 29 ++ .../{watch_test.rs => watch_test/main.rs} | 2 + tests-integration/tests/watch_test/traits.rs | 38 +++ xtask/src/main.rs | 10 +- 66 files changed, 1513 insertions(+), 1076 deletions(-) rename tests-integration/tests/{composition_test.rs => barrier_test/composition.rs} (72%) rename tests-integration/tests/{barrier_test.rs => barrier_test/main.rs} (99%) create mode 100644 tests-integration/tests/barrier_test/traits.rs create mode 100644 tests-integration/tests/blocking_test/composition.rs rename tests-integration/tests/{blocking_test.rs => blocking_test/main.rs} (99%) rename tests-integration/tests/{broadcast_mpmc_bounded_test.rs => broadcast_test/bounded.rs} (100%) create mode 100644 tests-integration/tests/broadcast_test/main.rs create mode 100644 tests-integration/tests/broadcast_test/traits.rs rename tests-integration/tests/{broadcast_mpmc_unbounded_test.rs => broadcast_test/unbounded.rs} (100%) rename tests-integration/tests/{completion_test.rs => completion_test/main.rs} (99%) create mode 100644 tests-integration/tests/completion_test/traits.rs rename tests-integration/tests/{condvar_test.rs => condvar_test/main.rs} (99%) create mode 100644 tests-integration/tests/condvar_test/traits.rs rename tests-integration/tests/{auto_reset_event_test.rs => event_test/auto_reset.rs} (100%) create mode 100644 tests-integration/tests/event_test/main.rs rename tests-integration/tests/{event_test.rs => event_test/manual_reset.rs} (100%) create mode 100644 tests-integration/tests/event_test/traits.rs rename tests-integration/tests/{latch_test.rs => latch_test/main.rs} (99%) create mode 100644 tests-integration/tests/latch_test/traits.rs rename tests-integration/tests/{lazy_cell_test.rs => lazy_cell_test/main.rs} (99%) create mode 100644 tests-integration/tests/lazy_cell_test/traits.rs create mode 100644 tests-integration/tests/lazy_cell_test/unsafe_paths.rs create mode 100644 tests-integration/tests/mpmc_test/traits.rs create mode 100644 tests-integration/tests/mpsc_test/traits.rs rename tests-integration/tests/{mutex_test.rs => mutex_test/main.rs} (99%) create mode 100644 tests-integration/tests/mutex_test/traits.rs create mode 100644 tests-integration/tests/mutex_test/unsafe_paths.rs rename tests-integration/tests/{once_cell_test.rs => once_cell_test/main.rs} (99%) create mode 100644 tests-integration/tests/once_cell_test/traits.rs rename tests-integration/tests/{once_map_test.rs => once_map_test/main.rs} (99%) create mode 100644 tests-integration/tests/once_map_test/traits.rs rename tests-integration/tests/{once_test.rs => once_test/main.rs} (99%) create mode 100644 tests-integration/tests/once_test/traits.rs create mode 100644 tests-integration/tests/oneshot_test/traits.rs rename tests-integration/tests/{phaser_test.rs => phaser_test/main.rs} (99%) create mode 100644 tests-integration/tests/phaser_test/traits.rs delete mode 100644 tests-integration/tests/pool_recycle_cancelled_test.rs delete mode 100644 tests-integration/tests/pool_replenish_test.rs rename tests-integration/tests/{pool_acquire_cancelled_test.rs => pool_test/acquire.rs} (66%) rename tests-integration/tests/{pool_behavior_test.rs => pool_test/behavior.rs} (71%) create mode 100644 tests-integration/tests/pool_test/main.rs create mode 100644 tests-integration/tests/pool_test/recycle.rs create mode 100644 tests-integration/tests/pool_test/replenish.rs create mode 100644 tests-integration/tests/pool_test/support.rs create mode 100644 tests-integration/tests/pool_test/traits.rs rename tests-integration/tests/{rwlock_test.rs => rwlock_test/main.rs} (99%) create mode 100644 tests-integration/tests/rwlock_test/traits.rs rename tests-integration/tests/{unsafe_paths_test.rs => rwlock_test/unsafe_paths.rs} (53%) rename tests-integration/tests/{semaphore_test.rs => semaphore_test/main.rs} (99%) create mode 100644 tests-integration/tests/semaphore_test/traits.rs rename tests-integration/tests/{shutdown_test.rs => shutdown_test/main.rs} (99%) create mode 100644 tests-integration/tests/shutdown_test/traits.rs rename tests-integration/tests/{singleflight_test.rs => singleflight_test/main.rs} (99%) create mode 100644 tests-integration/tests/singleflight_test/traits.rs delete mode 100644 tests-integration/tests/traits_test.rs rename tests-integration/tests/{waitgroup_test.rs => waitgroup_test/main.rs} (99%) create mode 100644 tests-integration/tests/waitgroup_test/traits.rs rename tests-integration/tests/{watch_test.rs => watch_test/main.rs} (99%) create mode 100644 tests-integration/tests/watch_test/traits.rs diff --git a/LICENSE b/LICENSE index f0925947..86747f2d 100644 --- a/LICENSE +++ b/LICENSE @@ -426,10 +426,6 @@ is followed by its upstream source path or paths: fastpool/src/unbounded.rs asyncband/src/pool/unbounded.rs fastpool/src/unbounded.rs - tests-integration/tests/pool_recycle_cancelled_test.rs - fastpool/tests/recycle_cancelled_tests.rs - tests-integration/tests/pool_replenish_test.rs - fastpool/tests/replenish_tests.rs The exact upstream revision is: diff --git a/asyncband/src/broadcast/mpmc/bounded/tests.rs b/asyncband/src/broadcast/mpmc/bounded/tests.rs index 594936ce..a6256e2d 100644 --- a/asyncband/src/broadcast/mpmc/bounded/tests.rs +++ b/asyncband/src/broadcast/mpmc/bounded/tests.rs @@ -16,7 +16,7 @@ // under the License. // These run under Miri via `cargo x miri`, so they stay single-threaded and small. Behavior -// reachable from the public API is covered in `tests-integration/broadcast_mpmc_bounded_test.rs`. +// reachable from the public API is covered in `tests-integration/tests/broadcast_test/bounded.rs`. use std::task::Waker; diff --git a/licenserc.toml b/licenserc.toml index 4ec6f841..7b6c05d9 100644 --- a/licenserc.toml +++ b/licenserc.toml @@ -37,8 +37,6 @@ excludes = [ "asyncband/src/rwlock/owned_write_guard.rs", "asyncband/src/rwlock/read_guard.rs", "asyncband/src/rwlock/write_guard.rs", - "tests-integration/tests/pool_recycle_cancelled_test.rs", - "tests-integration/tests/pool_replenish_test.rs", ] includes = [ "**/*.md", diff --git a/tests-integration/tests/composition_test.rs b/tests-integration/tests/barrier_test/composition.rs similarity index 72% rename from tests-integration/tests/composition_test.rs rename to tests-integration/tests/barrier_test/composition.rs index 64ac539b..e6187908 100644 --- a/tests-integration/tests/composition_test.rs +++ b/tests-integration/tests/barrier_test/composition.rs @@ -16,11 +16,8 @@ // under the License. use std::sync::Arc; -use std::thread; -use std::time::Duration; use asyncband::barrier::Barrier; -use asyncband::blocking::FutureExt as _; use asyncband::mutex::Mutex; use asyncband::oneshot; @@ -54,24 +51,3 @@ async fn public_primitives_compose_across_modules() { values.sort_unstable(); assert_eq!(*values, [1, 2]); } - -#[test] -fn blocking_bridge_composes_with_public_primitives() { - let mutex = Mutex::new(1); - *mutex.lock().block_on() += 1; - assert_eq!(*mutex.lock().block_on(), 2); - - let (sender, receiver) = oneshot::channel(); - let producer = thread::spawn(move || sender.send(7).unwrap()); - - assert_eq!(receiver.block_on(), Ok(7)); - producer.join().unwrap(); -} - -#[test] -fn timed_out_wait_cancels_an_asyncband_future() { - let (sender, receiver) = oneshot::channel(); - - assert_eq!(receiver.wait_timeout(Duration::ZERO), None); - assert_eq!(sender.send(7).unwrap_err().into_inner(), 7); -} diff --git a/tests-integration/tests/barrier_test.rs b/tests-integration/tests/barrier_test/main.rs similarity index 99% rename from tests-integration/tests/barrier_test.rs rename to tests-integration/tests/barrier_test/main.rs index 82d600a5..a6136f20 100644 --- a/tests-integration/tests/barrier_test.rs +++ b/tests-integration/tests/barrier_test/main.rs @@ -20,6 +20,9 @@ use tokio_test::assert_pending; use tokio_test::assert_ready; use tokio_test::task::spawn; +mod composition; +mod traits; + #[test] fn zero_does_not_block() { let b = Barrier::new(0); diff --git a/tests-integration/tests/barrier_test/traits.rs b/tests-integration/tests/barrier_test/traits.rs new file mode 100644 index 00000000..7cbd60d2 --- /dev/null +++ b/tests-integration/tests/barrier_test/traits.rs @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::barrier::Barrier; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::(); + assert_unpin::(); +} diff --git a/tests-integration/tests/blocking_test/composition.rs b/tests-integration/tests/blocking_test/composition.rs new file mode 100644 index 00000000..d4c6ec06 --- /dev/null +++ b/tests-integration/tests/blocking_test/composition.rs @@ -0,0 +1,44 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::thread; +use std::time::Duration; + +use asyncband::blocking::FutureExt as _; +use asyncband::mutex::Mutex; +use asyncband::oneshot; + +#[test] +fn blocking_bridge_composes_with_public_primitives() { + let mutex = Mutex::new(1); + *mutex.lock().block_on() += 1; + assert_eq!(*mutex.lock().block_on(), 2); + + let (sender, receiver) = oneshot::channel(); + let producer = thread::spawn(move || sender.send(7).unwrap()); + + assert_eq!(receiver.block_on(), Ok(7)); + producer.join().unwrap(); +} + +#[test] +fn timed_out_wait_cancels_an_asyncband_future() { + let (sender, receiver) = oneshot::channel(); + + assert_eq!(receiver.wait_timeout(Duration::ZERO), None); + assert_eq!(sender.send(7).unwrap_err().into_inner(), 7); +} diff --git a/tests-integration/tests/blocking_test.rs b/tests-integration/tests/blocking_test/main.rs similarity index 99% rename from tests-integration/tests/blocking_test.rs rename to tests-integration/tests/blocking_test/main.rs index 5f5e7511..f9bebbbb 100644 --- a/tests-integration/tests/blocking_test.rs +++ b/tests-integration/tests/blocking_test/main.rs @@ -28,6 +28,8 @@ use std::time::Duration; use asyncband::blocking::FutureExt as _; +mod composition; + // Long timeouts in this test target are watchdogs for detecting a stalled test process, not // assertions about elapsed-time precision. const TEST_WATCHDOG: Duration = Duration::from_secs(5); diff --git a/tests-integration/tests/broadcast_mpmc_bounded_test.rs b/tests-integration/tests/broadcast_test/bounded.rs similarity index 100% rename from tests-integration/tests/broadcast_mpmc_bounded_test.rs rename to tests-integration/tests/broadcast_test/bounded.rs diff --git a/tests-integration/tests/broadcast_test/main.rs b/tests-integration/tests/broadcast_test/main.rs new file mode 100644 index 00000000..7e6ae71a --- /dev/null +++ b/tests-integration/tests/broadcast_test/main.rs @@ -0,0 +1,20 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +mod bounded; +mod traits; +mod unbounded; diff --git a/tests-integration/tests/broadcast_test/traits.rs b/tests-integration/tests/broadcast_test/traits.rs new file mode 100644 index 00000000..35a626c4 --- /dev/null +++ b/tests-integration/tests/broadcast_test/traits.rs @@ -0,0 +1,39 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::broadcast; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::>(); +} diff --git a/tests-integration/tests/broadcast_mpmc_unbounded_test.rs b/tests-integration/tests/broadcast_test/unbounded.rs similarity index 100% rename from tests-integration/tests/broadcast_mpmc_unbounded_test.rs rename to tests-integration/tests/broadcast_test/unbounded.rs diff --git a/tests-integration/tests/completion_test.rs b/tests-integration/tests/completion_test/main.rs similarity index 99% rename from tests-integration/tests/completion_test.rs rename to tests-integration/tests/completion_test/main.rs index 8200e23b..fadb125e 100644 --- a/tests-integration/tests/completion_test.rs +++ b/tests-integration/tests/completion_test/main.rs @@ -31,6 +31,8 @@ use tests_integration::poll_with; use tests_integration::waker_on_drop; use tests_integration::waker_on_wake; +mod traits; + struct NotClone(String); #[test] diff --git a/tests-integration/tests/completion_test/traits.rs b/tests-integration/tests/completion_test/traits.rs new file mode 100644 index 00000000..3e009147 --- /dev/null +++ b/tests-integration/tests/completion_test/traits.rs @@ -0,0 +1,38 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::cell::Cell; + +use asyncband::completion; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + fn assert_send_value(_: T) {} + + assert_send_and_sync::>>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::(); + + let (_completer, completion) = completion::new::(); + assert_send_value(completion.wait()); +} diff --git a/tests-integration/tests/condvar_test.rs b/tests-integration/tests/condvar_test/main.rs similarity index 99% rename from tests-integration/tests/condvar_test.rs rename to tests-integration/tests/condvar_test/main.rs index fb7128fe..dd1e3e9e 100644 --- a/tests-integration/tests/condvar_test.rs +++ b/tests-integration/tests/condvar_test/main.rs @@ -28,6 +28,8 @@ use tests_integration::poll_with; use tests_integration::test_runtime; use tokio::task::JoinHandle; +mod traits; + struct NotifyOnDrop(Arc); impl Wake for NotifyOnDrop { diff --git a/tests-integration/tests/condvar_test/traits.rs b/tests-integration/tests/condvar_test/traits.rs new file mode 100644 index 00000000..761a66a8 --- /dev/null +++ b/tests-integration/tests/condvar_test/traits.rs @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::condvar::Condvar; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::(); + assert_unpin::(); +} diff --git a/tests-integration/tests/auto_reset_event_test.rs b/tests-integration/tests/event_test/auto_reset.rs similarity index 100% rename from tests-integration/tests/auto_reset_event_test.rs rename to tests-integration/tests/event_test/auto_reset.rs diff --git a/tests-integration/tests/event_test/main.rs b/tests-integration/tests/event_test/main.rs new file mode 100644 index 00000000..eb6ae1a7 --- /dev/null +++ b/tests-integration/tests/event_test/main.rs @@ -0,0 +1,20 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +mod auto_reset; +mod manual_reset; +mod traits; diff --git a/tests-integration/tests/event_test.rs b/tests-integration/tests/event_test/manual_reset.rs similarity index 100% rename from tests-integration/tests/event_test.rs rename to tests-integration/tests/event_test/manual_reset.rs diff --git a/tests-integration/tests/event_test/traits.rs b/tests-integration/tests/event_test/traits.rs new file mode 100644 index 00000000..6ef22daa --- /dev/null +++ b/tests-integration/tests/event_test/traits.rs @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::event::AutoResetEvent; +use asyncband::event::ManualResetEvent; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_unpin::(); + assert_unpin::(); +} diff --git a/tests-integration/tests/latch_test.rs b/tests-integration/tests/latch_test/main.rs similarity index 99% rename from tests-integration/tests/latch_test.rs rename to tests-integration/tests/latch_test/main.rs index 7a4e6c6c..280d6496 100644 --- a/tests-integration/tests/latch_test.rs +++ b/tests-integration/tests/latch_test/main.rs @@ -22,6 +22,8 @@ use std::task::Waker; use asyncband::latch::Latch; use tests_integration::WakeCounter; +mod traits; + #[test] fn countdown_operations_saturate_at_zero() { let latch = Latch::new(5); diff --git a/tests-integration/tests/latch_test/traits.rs b/tests-integration/tests/latch_test/traits.rs new file mode 100644 index 00000000..361c497e --- /dev/null +++ b/tests-integration/tests/latch_test/traits.rs @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::latch::Latch; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::(); + assert_unpin::(); +} diff --git a/tests-integration/tests/lazy_cell_test.rs b/tests-integration/tests/lazy_cell_test/main.rs similarity index 99% rename from tests-integration/tests/lazy_cell_test.rs rename to tests-integration/tests/lazy_cell_test/main.rs index 26046021..42b75874 100644 --- a/tests-integration/tests/lazy_cell_test.rs +++ b/tests-integration/tests/lazy_cell_test/main.rs @@ -25,6 +25,9 @@ use std::sync::atomic::Ordering; use asyncband::once::LazyCell; use tokio::sync::Notify; +mod traits; +mod unsafe_paths; + struct DropPanic; impl Drop for DropPanic { diff --git a/tests-integration/tests/lazy_cell_test/traits.rs b/tests-integration/tests/lazy_cell_test/traits.rs new file mode 100644 index 00000000..72e1ed5c --- /dev/null +++ b/tests-integration/tests/lazy_cell_test/traits.rs @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::once::LazyCell; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::>>(); + assert_unpin::>>(); +} diff --git a/tests-integration/tests/lazy_cell_test/unsafe_paths.rs b/tests-integration/tests/lazy_cell_test/unsafe_paths.rs new file mode 100644 index 00000000..1f42b591 --- /dev/null +++ b/tests-integration/tests/lazy_cell_test/unsafe_paths.rs @@ -0,0 +1,73 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::cell::Cell; +use std::future::Future; +use std::marker::PhantomPinned; +use std::pin::Pin; +use std::pin::pin; +use std::ptr; +use std::task::Context; +use std::task::Poll; + +use asyncband::once::LazyCell; +use tests_integration::poll_once; + +struct AddressSensitiveFuture { + address: Cell<*const Self>, + _pin: PhantomPinned, +} + +impl AddressSensitiveFuture { + fn new() -> Self { + Self { + address: Cell::new(ptr::null()), + _pin: PhantomPinned, + } + } +} + +impl Future for AddressSensitiveFuture { + type Output = i32; + + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + let this = self.as_ref().get_ref(); + let current = ptr::from_ref(this); + let first = this.address.get(); + if first.is_null() { + this.address.set(current); + Poll::Pending + } else { + assert!(ptr::eq(first, current)); + Poll::Ready(42) + } + } +} + +#[test] +fn lazy_cell_resumes_a_pinned_attempt_in_place() { + let lazy = LazyCell::from_future(AddressSensitiveFuture::new()); + let lazy = pin!(lazy); + + { + let mut force = pin!(LazyCell::force_pin(lazy.as_ref())); + assert!(poll_once(force.as_mut()).is_pending()); + } + + let mut force = pin!(LazyCell::force_pin(lazy.as_ref())); + assert_eq!(poll_once(force.as_mut()), Poll::Ready(&42)); +} diff --git a/tests-integration/tests/mpmc_test/main.rs b/tests-integration/tests/mpmc_test/main.rs index 8795d7ad..3f344fd1 100644 --- a/tests-integration/tests/mpmc_test/main.rs +++ b/tests-integration/tests/mpmc_test/main.rs @@ -29,6 +29,7 @@ use tests_integration::poll_once; mod callbacks; mod concurrency; mod notification; +mod traits; /// Either receiver flavor, so one case can cover both queues. trait Receiver: Clone { diff --git a/tests-integration/tests/mpmc_test/traits.rs b/tests-integration/tests/mpmc_test/traits.rs new file mode 100644 index 00000000..40af62ce --- /dev/null +++ b/tests-integration/tests/mpmc_test/traits.rs @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::cell::Cell; + +use asyncband::mpmc; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + fn assert_send_value(_: T) {} + + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>>(); + assert_send_and_sync::>>(); + assert_send_and_sync::>>(); + assert_send_and_sync::>>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + + let (unbounded_sender, unbounded_receiver) = mpmc::unbounded::>(); + assert_send_value(unbounded_receiver.recv()); + drop(unbounded_sender); + + let (bounded_sender, bounded_receiver) = mpmc::bounded::>(1); + assert_send_value(bounded_sender.send(Cell::new(0))); + assert_send_value(bounded_receiver.recv()); +} diff --git a/tests-integration/tests/mpsc_test/main.rs b/tests-integration/tests/mpsc_test/main.rs index 35b21b05..7e2a254d 100644 --- a/tests-integration/tests/mpsc_test/main.rs +++ b/tests-integration/tests/mpsc_test/main.rs @@ -31,6 +31,7 @@ mod backpressure; mod callbacks; mod concurrency; mod reservation; +mod traits; #[test] fn unbounded_try_recv_preserves_order_and_reports_state() { diff --git a/tests-integration/tests/mpsc_test/traits.rs b/tests-integration/tests/mpsc_test/traits.rs new file mode 100644 index 00000000..98856df9 --- /dev/null +++ b/tests-integration/tests/mpsc_test/traits.rs @@ -0,0 +1,74 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::cell::Cell; +use std::marker::PhantomPinned; +use std::panic::RefUnwindSafe; +use std::panic::UnwindSafe; + +use asyncband::mpsc; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); +} + +#[test] +fn mpsc_endpoints_keep_legacy_traits_regardless_of_payload() { + fn assert_send() {} + fn assert_sync() {} + fn assert_unpin() {} + fn assert_unwind_safe() {} + fn assert_ref_unwind_safe() {} + + macro_rules! assert_endpoint_traits { + ($endpoint:ident, $payload:ty) => { + assert_send::>(); + assert_sync::>(); + assert_unpin::>(); + assert_unwind_safe::>(); + assert_ref_unwind_safe::>(); + }; + } + + macro_rules! assert_payload_traits { + ($endpoint:ident) => { + assert_endpoint_traits!($endpoint, i32); + assert_endpoint_traits!($endpoint, Cell); + assert_endpoint_traits!($endpoint, &'static mut i32); + assert_endpoint_traits!($endpoint, PhantomPinned); + }; + } + + // Four endpoint types × four payloads × five traits = 80 compile-time assertions. + assert_payload_traits!(BoundedSender); + assert_payload_traits!(BoundedReceiver); + assert_payload_traits!(UnboundedSender); + assert_payload_traits!(UnboundedReceiver); +} diff --git a/tests-integration/tests/mutex_test.rs b/tests-integration/tests/mutex_test/main.rs similarity index 99% rename from tests-integration/tests/mutex_test.rs rename to tests-integration/tests/mutex_test/main.rs index 8dd11070..2a243235 100644 --- a/tests-integration/tests/mutex_test.rs +++ b/tests-integration/tests/mutex_test/main.rs @@ -20,6 +20,9 @@ use std::sync::Arc; use asyncband::mutex::*; use tests_integration::poll_once; +mod traits; +mod unsafe_paths; + #[test] fn test_try_lock_never_blocks() { // Test that try_lock and try_lock_owned never block, even under contention diff --git a/tests-integration/tests/mutex_test/traits.rs b/tests-integration/tests/mutex_test/traits.rs new file mode 100644 index 00000000..8c0f5258 --- /dev/null +++ b/tests-integration/tests/mutex_test/traits.rs @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::mutex::Mutex; +use asyncband::mutex::MutexGuard; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_unpin::>(); + assert_unpin::>(); +} diff --git a/tests-integration/tests/mutex_test/unsafe_paths.rs b/tests-integration/tests/mutex_test/unsafe_paths.rs new file mode 100644 index 00000000..5f795cbc --- /dev/null +++ b/tests-integration/tests/mutex_test/unsafe_paths.rs @@ -0,0 +1,51 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::sync::Arc; + +use asyncband::mutex::MappedMutexGuard; +use asyncband::mutex::Mutex; +use asyncband::mutex::MutexGuard; +use asyncband::mutex::OwnedMappedMutexGuard; +use asyncband::mutex::OwnedMutexGuard; + +#[test] +fn mapped_mutex_guards_preserve_lock_ownership() { + let mutex = Mutex::new((vec![1, 2], 3)); + let guard = mutex.try_lock().unwrap(); + let mapped = MutexGuard::map(guard, |value| &mut value.0); + let mut mapped = MappedMutexGuard::map(mapped, |values| &mut values[1]); + assert!(mutex.try_lock().is_none()); + *mapped = 4; + drop(mapped); + assert_eq!(mutex.into_inner(), (vec![1, 4], 3)); + + let mutex = Arc::new(Mutex::new(Some(vec![5, 6]))); + let weak = Arc::downgrade(&mutex); + let guard = mutex.clone().try_lock_owned().unwrap(); + let mapped = OwnedMutexGuard::filter_map(guard, Option::as_mut).unwrap(); + let mut mapped = OwnedMappedMutexGuard::map(mapped, |values| &mut values[0]); + assert!(mutex.try_lock().is_none()); + *mapped = 7; + drop(mapped); + let guard = mutex.try_lock().unwrap(); + assert_eq!(guard.as_deref(), Some([7, 6].as_slice())); + drop(guard); + + drop(mutex); + assert!(weak.upgrade().is_none()); +} diff --git a/tests-integration/tests/once_cell_test.rs b/tests-integration/tests/once_cell_test/main.rs similarity index 99% rename from tests-integration/tests/once_cell_test.rs rename to tests-integration/tests/once_cell_test/main.rs index f9303397..86a86beb 100644 --- a/tests-integration/tests/once_cell_test.rs +++ b/tests-integration/tests/once_cell_test/main.rs @@ -23,6 +23,8 @@ use std::sync::atomic::Ordering; use asyncband::once::OnceCell; use tests_integration::poll_once; +mod traits; + struct DropFlag(Arc); impl Drop for DropFlag { diff --git a/tests-integration/tests/once_cell_test/traits.rs b/tests-integration/tests/once_cell_test/traits.rs new file mode 100644 index 00000000..148e3d1d --- /dev/null +++ b/tests-integration/tests/once_cell_test/traits.rs @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::once::OnceCell; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::>(); + assert_unpin::>(); +} diff --git a/tests-integration/tests/once_map_test.rs b/tests-integration/tests/once_map_test/main.rs similarity index 99% rename from tests-integration/tests/once_map_test.rs rename to tests-integration/tests/once_map_test/main.rs index 6b2c61d7..35ec1883 100644 --- a/tests-integration/tests/once_map_test.rs +++ b/tests-integration/tests/once_map_test/main.rs @@ -27,6 +27,8 @@ use std::sync::atomic::Ordering; use asyncband::once::OnceMap; use tests_integration::poll_once; +mod traits; + #[test] fn constructors_and_default() { let _: OnceMap = OnceMap::default(); diff --git a/tests-integration/tests/once_map_test/traits.rs b/tests-integration/tests/once_map_test/traits.rs new file mode 100644 index 00000000..18d8512b --- /dev/null +++ b/tests-integration/tests/once_map_test/traits.rs @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::once::OnceMap; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::>(); + assert_unpin::>(); +} diff --git a/tests-integration/tests/once_test.rs b/tests-integration/tests/once_test/main.rs similarity index 99% rename from tests-integration/tests/once_test.rs rename to tests-integration/tests/once_test/main.rs index 622f746e..7d8e493b 100644 --- a/tests-integration/tests/once_test.rs +++ b/tests-integration/tests/once_test/main.rs @@ -22,6 +22,8 @@ use std::sync::atomic::Ordering; use asyncband::once::Once; use tests_integration::poll_once; +mod traits; + #[tokio::test] async fn call_once_runs_only_one_initializer() { let once = Once::new(); diff --git a/tests-integration/tests/once_test/traits.rs b/tests-integration/tests/once_test/traits.rs new file mode 100644 index 00000000..77daeb2b --- /dev/null +++ b/tests-integration/tests/once_test/traits.rs @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::once::Once; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::(); + assert_unpin::(); +} diff --git a/tests-integration/tests/oneshot_test/main.rs b/tests-integration/tests/oneshot_test/main.rs index bd3eba01..a015f522 100644 --- a/tests-integration/tests/oneshot_test/main.rs +++ b/tests-integration/tests/oneshot_test/main.rs @@ -40,6 +40,7 @@ use self::support::spawn_named; use self::support::spin_until; mod support; +mod traits; #[test] fn send_before_await() { diff --git a/tests-integration/tests/oneshot_test/traits.rs b/tests-integration/tests/oneshot_test/traits.rs new file mode 100644 index 00000000..07962dbe --- /dev/null +++ b/tests-integration/tests/oneshot_test/traits.rs @@ -0,0 +1,34 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::oneshot; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_send() {} + fn assert_unpin() {} + + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_send::>(); + assert_send::>(); +} diff --git a/tests-integration/tests/phaser_test.rs b/tests-integration/tests/phaser_test/main.rs similarity index 99% rename from tests-integration/tests/phaser_test.rs rename to tests-integration/tests/phaser_test/main.rs index 615672c3..6caeb9d8 100644 --- a/tests-integration/tests/phaser_test.rs +++ b/tests-integration/tests/phaser_test/main.rs @@ -28,6 +28,8 @@ use tests_integration::poll_once; use tests_integration::poll_with; use tests_integration::waker_on_drop; +mod traits; + #[test] fn batch_registration_joins_one_observed_phase() { let phaser = Phaser::new(); diff --git a/tests-integration/tests/phaser_test/traits.rs b/tests-integration/tests/phaser_test/traits.rs new file mode 100644 index 00000000..5b88e39c --- /dev/null +++ b/tests-integration/tests/phaser_test/traits.rs @@ -0,0 +1,36 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::phaser::Closed; +use asyncband::phaser::Phaser; +use asyncband::phaser::PhaserParticipant; +use asyncband::phaser::PhaserParticipants; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::(); +} diff --git a/tests-integration/tests/pool_recycle_cancelled_test.rs b/tests-integration/tests/pool_recycle_cancelled_test.rs deleted file mode 100644 index 144beaa5..00000000 --- a/tests-integration/tests/pool_recycle_cancelled_test.rs +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2025 FastLabs Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file contains code ported from Fastpool 1.1.1. -// The incorporated code has been modified for use in Apache Asyncband. -// Upstream source: -// https://github.com/fast/fastpool/blob/e4c65f1ed38395abc58d68eda8bd09925c13028e/fastpool/tests/recycle_cancelled_tests.rs - -use std::future::Future; -use std::future::poll_fn; -use std::pin::pin; -use std::sync::Arc; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; -use std::task::Poll; - -use asyncband::pool::ManageObject; -use asyncband::pool::ObjectStatus; -use asyncband::pool::RecycleCancelledStrategy; - -#[derive(Default)] -struct Controls { - created: AtomicUsize, - recycle_ready: AtomicBool, - reject_recycle: AtomicBool, -} - -struct ControlledRecycleManager { - controls: Arc, -} - -impl ManageObject for ControlledRecycleManager { - type Object = usize; - type Error = (); - - async fn create(&self) -> Result { - Ok(self.controls.created.fetch_add(1, Ordering::Relaxed)) - } - - async fn is_recyclable( - &self, - _object: &mut Self::Object, - _status: &ObjectStatus, - ) -> Result<(), Self::Error> { - poll_fn(|_| { - if !self.controls.recycle_ready.load(Ordering::Acquire) { - Poll::Pending - } else if self.controls.reject_recycle.load(Ordering::Relaxed) { - Poll::Ready(Err(())) - } else { - Poll::Ready(Ok(())) - } - }) - .await - } -} - -fn manager() -> (ControlledRecycleManager, Arc) { - let controls = Arc::new(Controls::default()); - ( - ControlledRecycleManager { - controls: controls.clone(), - }, - controls, - ) -} - -fn poll_and_cancel(future: impl Future) { - let mut future = pin!(future); - assert!(tests_integration::poll_once(future.as_mut()).is_pending()); -} - -mod bounded_tests { - use asyncband::pool::bounded::Pool; - use asyncband::pool::bounded::PoolConfig; - - use super::*; - - #[tokio::test] - async fn cancellation_detaches_by_default() { - let (manager, controls) = manager(); - let pool = Pool::new(PoolConfig::new(1), manager); - - let object = pool.get().await.unwrap(); - assert_eq!(*object, 0); - drop(object); - - poll_and_cancel(pool.get()); - assert_eq!(pool.status().current_size, 0); - assert_eq!(pool.status().idle_count, 0); - - let object = pool.get().await.unwrap(); - assert_eq!(*object, 1); - assert_eq!(controls.created.load(Ordering::Relaxed), 2); - } - - #[tokio::test] - async fn cancellation_can_restore_the_idle_object() { - let (manager, controls) = manager(); - let config = PoolConfig::new(1) - .with_recycle_cancelled_strategy(RecycleCancelledStrategy::ReturnToPool); - let pool = Pool::new(config, manager); - - let object = pool.get().await.unwrap(); - drop(object); - let mut last_used_before = None; - pool.retain(|_, status| { - last_used_before = Some(status.last_used()); - true - }); - - poll_and_cancel(pool.get()); - assert_eq!(pool.status().current_size, 1); - assert_eq!(pool.status().idle_count, 1); - - let mut last_used_after = None; - pool.retain(|_, status| { - last_used_after = Some(status.last_used()); - true - }); - assert_eq!(last_used_after, last_used_before); - - controls.recycle_ready.store(true, Ordering::Release); - let object = pool.get().await.unwrap(); - assert_eq!(*object, 0); - assert_eq!(controls.created.load(Ordering::Relaxed), 1); - } - - #[tokio::test] - async fn repeated_cancellation_does_not_shrink_a_restoring_pool() { - let (manager, _) = manager(); - let config = PoolConfig::new(3) - .with_recycle_cancelled_strategy(RecycleCancelledStrategy::ReturnToPool); - let pool = Pool::new(config, manager); - - let objects = [ - pool.get().await.unwrap(), - pool.get().await.unwrap(), - pool.get().await.unwrap(), - ]; - drop(objects); - - for _ in 0..5 { - poll_and_cancel(pool.get()); - } - assert_eq!(pool.status().current_size, 3); - assert_eq!(pool.status().idle_count, 3); - } - - #[tokio::test] - async fn rejected_recycle_detaches_even_when_cancellation_would_restore() { - let (manager, controls) = manager(); - let config = PoolConfig::new(1) - .with_recycle_cancelled_strategy(RecycleCancelledStrategy::ReturnToPool); - let pool = Pool::new(config, manager); - - let object = pool.get().await.unwrap(); - drop(object); - controls.reject_recycle.store(true, Ordering::Relaxed); - controls.recycle_ready.store(true, Ordering::Release); - - let object = pool.get().await.unwrap(); - assert_eq!(*object, 1); - assert_eq!(controls.created.load(Ordering::Relaxed), 2); - assert_eq!(pool.status().current_size, 1); - } -} - -mod unbounded_tests { - use asyncband::pool::unbounded::Pool; - use asyncband::pool::unbounded::PoolConfig; - - use super::*; - - #[tokio::test] - async fn cancellation_detaches_by_default() { - let (manager, controls) = manager(); - let pool = Pool::new(PoolConfig::default(), manager); - - let object = pool.get().await.unwrap(); - assert_eq!(*object, 0); - drop(object); - - poll_and_cancel(pool.get()); - assert_eq!(pool.status().current_size, 0); - assert_eq!(pool.status().idle_count, 0); - - let object = pool.get().await.unwrap(); - assert_eq!(*object, 1); - assert_eq!(controls.created.load(Ordering::Relaxed), 2); - } - - #[tokio::test] - async fn cancellation_can_restore_the_idle_object() { - let (manager, controls) = manager(); - let config = PoolConfig::new() - .with_recycle_cancelled_strategy(RecycleCancelledStrategy::ReturnToPool); - let pool = Pool::new(config, manager); - - let object = pool.get().await.unwrap(); - drop(object); - poll_and_cancel(pool.get()); - - assert_eq!(pool.status().current_size, 1); - assert_eq!(pool.status().idle_count, 1); - controls.recycle_ready.store(true, Ordering::Release); - - let object = pool.get().await.unwrap(); - assert_eq!(*object, 0); - assert_eq!(controls.created.load(Ordering::Relaxed), 1); - } - - #[tokio::test] - async fn repeated_cancellation_does_not_shrink_a_restoring_pool() { - let (manager, _) = manager(); - let config = PoolConfig::new() - .with_recycle_cancelled_strategy(RecycleCancelledStrategy::ReturnToPool); - let pool = Pool::new(config, manager); - - let objects = [ - pool.get().await.unwrap(), - pool.get().await.unwrap(), - pool.get().await.unwrap(), - ]; - drop(objects); - - for _ in 0..5 { - poll_and_cancel(pool.get()); - } - assert_eq!(pool.status().current_size, 3); - assert_eq!(pool.status().idle_count, 3); - } -} diff --git a/tests-integration/tests/pool_replenish_test.rs b/tests-integration/tests/pool_replenish_test.rs deleted file mode 100644 index 5dbca192..00000000 --- a/tests-integration/tests/pool_replenish_test.rs +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright 2025 FastLabs Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// This file contains code ported from Fastpool 1.1.1. -// The incorporated code has been modified for use in Apache Asyncband. -// Upstream source: -// https://github.com/fast/fastpool/blob/e4c65f1ed38395abc58d68eda8bd09925c13028e/fastpool/tests/replenish_tests.rs - -use std::convert::Infallible; -use std::future::poll_fn; -use std::sync::Arc; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; -use std::task::Poll; - -use asyncband::pool::ManageObject; -use asyncband::pool::ObjectStatus; -use asyncband::pool::bounded::Pool; -use asyncband::pool::bounded::PoolConfig; - -#[tokio::test] -async fn test_replenish_to() { - #[derive(Default)] - struct Manager; - - impl ManageObject for Manager { - type Object = (); - type Error = Infallible; - - async fn create(&self) -> Result { - Ok(()) - } - - async fn is_recyclable( - &self, - _o: &mut Self::Object, - _status: &ObjectStatus, - ) -> Result<(), Self::Error> { - Ok(()) - } - } - - const MAX_SIZE: usize = 2; - - fn make_default() -> Arc> { - Pool::new(PoolConfig::new(MAX_SIZE), Manager) - } - - for i in 0..5 { - let pool = make_default(); - let n = pool.replenish_to(i).await.unwrap(); - assert_eq!(n, i.min(MAX_SIZE)); - } - - // stage one idle object - { - let pool = make_default(); - pool.get().await.unwrap(); - let n = pool.replenish_to(2).await.unwrap(); - assert_eq!(n, 1); - } - - // stage two idle objects - { - let pool = make_default(); - let o1 = pool.get().await.unwrap(); - let o2 = pool.get().await.unwrap(); - drop((o1, o2)); - - let n = pool.replenish_to(2).await.unwrap(); - assert_eq!(n, 0); - } -} - -#[derive(Debug, PartialEq, Eq)] -struct CreateError; - -struct FailingManager { - calls: Arc, -} - -impl ManageObject for FailingManager { - type Object = usize; - type Error = CreateError; - - async fn create(&self) -> Result { - let call = self.calls.fetch_add(1, Ordering::Relaxed); - if call == 1 { - Err(CreateError) - } else { - Ok(call) - } - } - - async fn is_recyclable( - &self, - _object: &mut Self::Object, - _status: &ObjectStatus, - ) -> Result<(), Self::Error> { - Ok(()) - } -} - -#[tokio::test] -async fn replenish_to_reports_create_errors_and_keeps_prior_objects() { - let pool = Pool::new( - PoolConfig::new(2), - FailingManager { - calls: Arc::new(AtomicUsize::new(0)), - }, - ); - - assert_eq!(pool.replenish_to(2).await, Err(CreateError)); - assert_eq!(pool.status().current_size, 1); - assert_eq!(pool.status().idle_count, 1); - - assert_eq!(pool.replenish_to(2).await, Ok(1)); - assert_eq!(pool.status().current_size, 2); - assert_eq!(pool.status().idle_count, 2); -} - -struct ControlledManager { - calls: Arc, - allow_create: Arc, -} - -impl ManageObject for ControlledManager { - type Object = usize; - type Error = Infallible; - - async fn create(&self) -> Result { - let call = self.calls.fetch_add(1, Ordering::Relaxed); - if call != 0 { - poll_fn(|_| { - if self.allow_create.load(Ordering::Acquire) { - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; - } - Ok(call) - } - - async fn is_recyclable( - &self, - _object: &mut Self::Object, - _status: &ObjectStatus, - ) -> Result<(), Self::Error> { - Ok(()) - } -} - -#[tokio::test] -async fn concurrent_replenish_to_calls_respect_capacity() { - let calls = Arc::new(AtomicUsize::new(0)); - let allow_create = Arc::new(AtomicBool::new(false)); - let pool = Pool::new( - PoolConfig::new(2), - ControlledManager { - calls: calls.clone(), - allow_create: allow_create.clone(), - }, - ); - - assert_eq!(pool.replenish_to(1).await, Ok(1)); - - let mut first = Box::pin(pool.replenish_to(2)); - assert!(tests_integration::poll_once(first.as_mut()).is_pending()); - - let mut second = Box::pin(pool.replenish_to(2)); - assert_eq!( - tests_integration::poll_once(second.as_mut()), - Poll::Ready(Ok(0)) - ); - - allow_create.store(true, Ordering::Release); - assert_eq!( - tests_integration::poll_once(first.as_mut()), - Poll::Ready(Ok(1)) - ); - assert_eq!(calls.load(Ordering::Relaxed), 2); - assert_eq!(pool.status().current_size, 2); - assert_eq!(pool.status().idle_count, 2); -} - -#[tokio::test] -async fn concurrent_get_and_replenish_to_respect_capacity() { - let calls = Arc::new(AtomicUsize::new(0)); - let allow_create = Arc::new(AtomicBool::new(false)); - let pool = Pool::new( - PoolConfig::new(2), - ControlledManager { - calls: calls.clone(), - allow_create: allow_create.clone(), - }, - ); - - let first = pool.get().await.unwrap(); - - let mut replenish = Box::pin(pool.replenish_to(2)); - assert!(tests_integration::poll_once(replenish.as_mut()).is_pending()); - - let mut get = Box::pin(pool.get()); - assert!(tests_integration::poll_once(get.as_mut()).is_pending()); - assert_eq!(pool.status().current_size, 1); - - allow_create.store(true, Ordering::Release); - assert_eq!( - tests_integration::poll_once(replenish.as_mut()), - Poll::Ready(Ok(1)) - ); - - let second = match tests_integration::poll_once(get.as_mut()) { - Poll::Ready(Ok(object)) => object, - _ => panic!("get should consume the replenished object"), - }; - assert_eq!(calls.load(Ordering::Relaxed), 2); - assert_eq!(pool.status().current_size, 2); - assert_eq!(pool.status().idle_count, 0); - - drop((first, second)); - assert_eq!(pool.status().idle_count, 2); -} - -struct BlockingManager { - allow_create: Arc, -} - -impl ManageObject for BlockingManager { - type Object = (); - type Error = Infallible; - - async fn create(&self) -> Result { - poll_fn(|_| { - if self.allow_create.load(Ordering::Acquire) { - Poll::Ready(()) - } else { - Poll::Pending - } - }) - .await; - Ok(()) - } - - async fn is_recyclable( - &self, - _object: &mut Self::Object, - _status: &ObjectStatus, - ) -> Result<(), Self::Error> { - Ok(()) - } -} - -#[tokio::test] -async fn replenish_to_respects_max_size_with_active_and_idle_objects() { - let pool = Pool::new( - PoolConfig::new(2), - BlockingManager { - allow_create: Arc::new(AtomicBool::new(true)), - }, - ); - - assert_eq!(pool.replenish_to(2).await, Ok(2)); - let active = pool.get().await.unwrap(); - assert_eq!(pool.status().current_size, 2); - assert_eq!(pool.status().idle_count, 1); - - assert_eq!(pool.replenish_to(usize::MAX).await, Ok(0)); - assert_eq!(pool.status().current_size, 2); - assert_eq!(pool.status().idle_count, 1); - - drop(active); - assert_eq!(pool.status().idle_count, 2); -} - -#[tokio::test] -async fn cancelling_replenish_to_releases_reserved_capacity() { - let allow_create = Arc::new(AtomicBool::new(false)); - let pool = Pool::new( - PoolConfig::new(1), - BlockingManager { - allow_create: allow_create.clone(), - }, - ); - - let mut replenish = Box::pin(pool.replenish_to(1)); - assert!(tests_integration::poll_once(replenish.as_mut()).is_pending()); - drop(replenish); - - allow_create.store(true, Ordering::Release); - let mut get = Box::pin(pool.get()); - assert!(tests_integration::poll_once(get.as_mut()).is_ready()); - assert_eq!(pool.status().idle_count, 1); -} diff --git a/tests-integration/tests/pool_acquire_cancelled_test.rs b/tests-integration/tests/pool_test/acquire.rs similarity index 66% rename from tests-integration/tests/pool_acquire_cancelled_test.rs rename to tests-integration/tests/pool_test/acquire.rs index 2f34dda0..39276acc 100644 --- a/tests-integration/tests/pool_acquire_cancelled_test.rs +++ b/tests-integration/tests/pool_test/acquire.rs @@ -16,61 +16,30 @@ // under the License. use std::future::Future; -use std::future::poll_fn; use std::pin::pin; use std::sync::Arc; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; use std::task::Context; use std::task::Poll; use std::task::Wake; use std::task::Waker; -use asyncband::pool::ManageObject; -use asyncband::pool::ObjectStatus; use asyncband::pool::bounded::Pool; use asyncband::pool::bounded::PoolConfig; use tests_integration::WakeCounter; -struct Manager { - create_calls: Arc, - create_ready: Arc, -} - -impl ManageObject for Manager { - type Object = usize; - type Error = (); +use super::support::Manager; +use super::support::ManagerError; - async fn create(&self) -> Result { - let id = self.create_calls.fetch_add(1, Ordering::Relaxed); - // Tests explicitly poll again after changing this gate; no executor drives it. - poll_fn(|_| { - if self.create_ready.load(Ordering::Acquire) { - Poll::Ready(Ok(id)) - } else { - Poll::Pending - } - }) - .await - } - - async fn is_recyclable( - &self, - _object: &mut Self::Object, - _status: &ObjectStatus, - ) -> Result<(), Self::Error> { - Ok(()) - } -} - -fn ready(future: impl Future>) -> T { +fn ready(future: impl Future>) -> T { let wakes = Arc::new(WakeCounter::default()); wakes.wake_by_ref(); ready_after_wake(future, &wakes) } -fn ready_after_wake(future: impl Future>, wakes: &Arc) -> T { +fn ready_after_wake( + future: impl Future>, + wakes: &Arc, +) -> T { let mut future = pin!(future); let waker = Waker::from(wakes.clone()); // Allow cooperative yields, but never poll away a missing notification or spin forever. @@ -78,7 +47,7 @@ fn ready_after_wake(future: impl Future>, wakes: &Arc< assert!(wakes.take() > 0, "missing wake"); match future.as_mut().poll(&mut Context::from_waker(&waker)) { Poll::Ready(Ok(value)) => return value, - Poll::Ready(Err(())) => panic!("operation should succeed"), + Poll::Ready(Err(ManagerError)) => panic!("operation should succeed"), Poll::Pending => {} } } @@ -86,14 +55,8 @@ fn ready_after_wake(future: impl Future>, wakes: &Arc< } fn cancel_waiter(return_before_cancel: bool) { - let create_calls = Arc::new(AtomicUsize::new(0)); - let pool = Pool::new( - PoolConfig::new(1), - Manager { - create_calls: create_calls.clone(), - create_ready: Arc::new(AtomicBool::new(true)), - }, - ); + let manager = Manager::default(); + let pool = Pool::new(PoolConfig::new(1), manager.clone()); let held = ready(pool.get()); let mut first_wakes = Arc::new(WakeCounter::default()); let mut next_wakes = Arc::new(WakeCounter::default()); @@ -112,7 +75,7 @@ fn cancel_waiter(return_before_cancel: bool) { .poll(&mut Context::from_waker(&next_waker)) .is_pending() ); - assert_eq!(create_calls.load(Ordering::Relaxed), 1); + assert_eq!(manager.created(), 1); if return_before_cancel { drop(held); @@ -132,13 +95,13 @@ fn cancel_waiter(return_before_cancel: bool) { // A notification from returning the object is just as valid as one from cancellation. let object = ready_after_wake(next.as_mut(), &next_wakes); assert_eq!(*object, 0); - assert_eq!(create_calls.load(Ordering::Relaxed), 1); + assert_eq!(manager.created(), 1); assert_eq!(pool.status().current_size, 1); assert_eq!(pool.status().idle_count, 0); let mut extra = Box::pin(pool.get()); assert!(tests_integration::poll_once(extra.as_mut()).is_pending()); - assert_eq!(create_calls.load(Ordering::Relaxed), 1); + assert_eq!(manager.created(), 1); drop(extra); drop(object); assert_eq!(pool.status().idle_count, 1); @@ -157,18 +120,12 @@ fn cancelling_notified_get_preserves_follower_progress() { #[test] fn cancelling_create_restores_capacity_for_waiting_get() { - let create_calls = Arc::new(AtomicUsize::new(0)); - let create_ready = Arc::new(AtomicBool::new(false)); - let pool = Pool::new( - PoolConfig::new(1), - Manager { - create_calls: create_calls.clone(), - create_ready: create_ready.clone(), - }, - ); + let manager = Manager::default(); + let creation = manager.pause_create(); + let pool = Pool::new(PoolConfig::new(1), manager.clone()); let mut creating = Box::pin(pool.get()); assert!(tests_integration::poll_once(creating.as_mut()).is_pending()); - assert_eq!(create_calls.load(Ordering::Relaxed), 1); + assert_eq!(manager.created(), 1); assert_eq!(pool.status().current_size, 0); let wakes = Arc::new(WakeCounter::default()); @@ -179,24 +136,24 @@ fn cancelling_create_restores_capacity_for_waiting_get() { .poll(&mut Context::from_waker(&waker)) .is_pending() ); - assert_eq!(create_calls.load(Ordering::Relaxed), 1); + assert_eq!(manager.created(), 1); drop(creating); assert!(wakes.count() > 0); assert_eq!(pool.status().current_size, 0); assert_eq!(pool.status().idle_count, 0); - create_ready.store(true, Ordering::Release); + assert!(creation.is_closed()); let object = ready_after_wake(next.as_mut(), &wakes); assert_eq!(*object, 1); - assert_eq!(create_calls.load(Ordering::Relaxed), 2); + assert_eq!(manager.created(), 2); assert_eq!(pool.status().current_size, 1); assert_eq!(pool.status().idle_count, 0); let mut extra = Box::pin(pool.get()); assert!(tests_integration::poll_once(extra.as_mut()).is_pending()); - assert_eq!(create_calls.load(Ordering::Relaxed), 2); + assert_eq!(manager.created(), 2); drop(extra); drop(object); assert_eq!(pool.status().idle_count, 1); assert_eq!(*ready(pool.get()), 1); - assert_eq!(create_calls.load(Ordering::Relaxed), 2); + assert_eq!(manager.created(), 2); } diff --git a/tests-integration/tests/pool_behavior_test.rs b/tests-integration/tests/pool_test/behavior.rs similarity index 71% rename from tests-integration/tests/pool_behavior_test.rs rename to tests-integration/tests/pool_test/behavior.rs index ad2417ca..9d68269f 100644 --- a/tests-integration/tests/pool_behavior_test.rs +++ b/tests-integration/tests/pool_test/behavior.rs @@ -19,65 +19,23 @@ use std::cell::Cell; use std::convert::Infallible; use std::panic::AssertUnwindSafe; use std::panic::catch_unwind; -use std::sync::Arc; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; use std::time::Instant; -use asyncband::pool::ManageObject; -use asyncband::pool::ObjectStatus; use asyncband::pool::QueueStrategy; use asyncband::pool::bounded; use asyncband::pool::unbounded; -struct CountingManager { - next: Arc, - detached: Arc, -} - -impl ManageObject for CountingManager { - type Object = usize; - type Error = Infallible; - - async fn create(&self) -> Result { - Ok(self.next.fetch_add(1, Ordering::Relaxed)) - } - - async fn is_recyclable( - &self, - _object: &mut Self::Object, - _status: &ObjectStatus, - ) -> Result<(), Self::Error> { - Ok(()) - } - - fn on_detached(&self, object: &mut Self::Object) { - self.detached.fetch_add(1, Ordering::Relaxed); - *object += 1000; - } -} +use super::support::Manager; #[test] #[should_panic(expected = "bounded pool max_size must be greater than zero")] fn bounded_pool_rejects_zero_capacity() { - bounded::Pool::new( - bounded::PoolConfig::new(0), - CountingManager { - next: Arc::new(AtomicUsize::new(0)), - detached: Arc::new(AtomicUsize::new(0)), - }, - ); + bounded::Pool::new(bounded::PoolConfig::new(0), Manager::default()); } #[test] fn bounded_construction_allocates_idle_storage_lazily() { - let pool = bounded::Pool::new( - bounded::PoolConfig::new(usize::MAX), - CountingManager { - next: Arc::new(AtomicUsize::new(0)), - detached: Arc::new(AtomicUsize::new(0)), - }, - ); + let pool = bounded::Pool::new(bounded::PoolConfig::new(usize::MAX), Manager::default()); assert_eq!(pool.status().max_size, usize::MAX); assert_eq!(pool.status().current_size, 0); @@ -86,13 +44,7 @@ fn bounded_construction_allocates_idle_storage_lazily() { #[tokio::test] async fn bounded_last_used_tracks_the_end_of_a_checkout() { - let pool = bounded::Pool::new( - bounded::PoolConfig::new(1), - CountingManager { - next: Arc::new(AtomicUsize::new(0)), - detached: Arc::new(AtomicUsize::new(0)), - }, - ); + let pool = bounded::Pool::new(bounded::PoolConfig::new(1), Manager::default()); let object = pool.get().await.unwrap(); let before_return = Instant::now(); @@ -105,14 +57,8 @@ async fn bounded_last_used_tracks_the_end_of_a_checkout() { #[tokio::test] async fn retain_invokes_detachment_hook_once_per_removed_object() { - let detached = Arc::new(AtomicUsize::new(0)); - let pool = bounded::Pool::new( - bounded::PoolConfig::new(4), - CountingManager { - next: Arc::new(AtomicUsize::new(0)), - detached: detached.clone(), - }, - ); + let manager = Manager::default(); + let pool = bounded::Pool::new(bounded::PoolConfig::new(4), manager.clone()); let mut objects = vec![]; for _ in 0..4 { @@ -125,7 +71,7 @@ async fn retain_invokes_detachment_hook_once_per_removed_object() { assert_eq!(result.retained, 2); assert_eq!(result.removed, [1001, 1003]); - assert_eq!(detached.load(Ordering::Relaxed), 2); + assert_eq!(manager.detached(), [1, 3]); assert_eq!(pool.status().current_size, 2); assert_eq!(pool.status().idle_count, 2); } diff --git a/tests-integration/tests/pool_test/main.rs b/tests-integration/tests/pool_test/main.rs new file mode 100644 index 00000000..f03283ff --- /dev/null +++ b/tests-integration/tests/pool_test/main.rs @@ -0,0 +1,23 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +mod acquire; +mod behavior; +mod recycle; +mod replenish; +mod support; +mod traits; diff --git a/tests-integration/tests/pool_test/recycle.rs b/tests-integration/tests/pool_test/recycle.rs new file mode 100644 index 00000000..03ff53ef --- /dev/null +++ b/tests-integration/tests/pool_test/recycle.rs @@ -0,0 +1,193 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::pool::RecycleCancelledStrategy; +use tests_integration::WakeCounter; +use tests_integration::expect_ready; +use tests_integration::poll_once; +use tests_integration::poll_with; + +use super::support::Manager; +use super::support::ManagerError; +use super::support::ready; + +// Both pool variants promise the same object lifecycle during recycle cancellation. +macro_rules! recycle_contract { + () => { + #[test] + fn cancelled_validation_applies_the_configured_ownership_policy() { + for strategy in [None, Some(RecycleCancelledStrategy::ReturnToPool)] { + let manager = Manager::default(); + let pool = pool(1, manager.clone(), strategy); + let original = ready(pool.get()).unwrap(); + let id = *original; + drop(original); + + let mut returned_at = None; + pool.retain(|_, status| { + returned_at = Some(status.last_used()); + true + }); + + // Repeating the cancellation checks that restored objects stay reusable. + let attempts = if strategy.is_some() { 4 } else { 1 }; + for _ in 0..attempts { + let validation = manager.pause_recycle(); + let mut checkout = Box::pin(pool.get()); + assert!(poll_once(checkout.as_mut()).is_pending()); + assert_eq!(pool.status().idle_count, 0); + drop(checkout); + assert!(validation.is_closed()); + + let retained = usize::from(strategy.is_some()); + assert_eq!(pool.status().current_size, retained); + assert_eq!(pool.status().idle_count, retained); + assert_eq!(manager.created(), 1); + } + + if strategy.is_some() { + assert!(manager.detached().is_empty()); + pool.retain(|object, status| { + assert_eq!(*object, id); + assert_eq!(Some(status.last_used()), returned_at); + assert_eq!(status.recycle_count(), 0); + true + }); + } else { + assert_eq!(manager.detached(), [id]); + } + let replacement = ready(pool.get()).unwrap(); + if strategy.is_some() { + assert_eq!(*replacement, id); + assert_eq!(manager.created(), 1); + assert_eq!(replacement.status().recycle_count(), 1); + } else { + assert_ne!(*replacement, id); + assert_eq!(manager.created(), 2); + } + assert_eq!(pool.status().current_size, 1); + assert_eq!(pool.status().idle_count, 0); + } + } + + #[test] + fn recycle_completion_wakes_checkout_and_rejection_replaces_the_object() { + for reject in [false, true] { + let manager = Manager::default(); + let pool = pool( + 1, + manager.clone(), + Some(RecycleCancelledStrategy::ReturnToPool), + ); + drop(ready(pool.get()).unwrap()); + let validation = manager.pause_recycle(); + let (waker, wakes) = WakeCounter::new(); + let mut checkout = Box::pin(pool.get()); + assert!(poll_with(checkout.as_mut(), &waker).is_pending()); + validation + .send(if reject { Err(ManagerError) } else { Ok(()) }) + .unwrap(); + assert!(wakes.count() > 0); + + let object = expect_ready(poll_with(checkout.as_mut(), &waker)).unwrap(); + assert_eq!(*object, usize::from(reject)); + assert_eq!(manager.created(), 1 + usize::from(reject)); + assert_eq!(manager.detached(), if reject { vec![0] } else { vec![] }); + drop(object); + assert_eq!(pool.status().current_size, 1); + assert_eq!(pool.status().idle_count, 1); + } + } + + #[test] + fn cancelling_one_validation_leaves_other_idle_objects_available() { + let manager = Manager::default(); + let pool = pool( + 3, + manager.clone(), + Some(RecycleCancelledStrategy::ReturnToPool), + ); + let objects: Vec<_> = (0..3).map(|_| ready(pool.get()).unwrap()).collect(); + let mut ids: Vec<_> = objects.iter().map(|object| **object).collect(); + drop(objects); + + for _ in 0..6 { + let validation = manager.pause_recycle(); + let mut checkout = Box::pin(pool.get()); + assert!(poll_once(checkout.as_mut()).is_pending()); + assert_eq!(pool.status().idle_count, 2); + drop(checkout); + assert!(validation.is_closed()); + assert_eq!(pool.status().idle_count, 3); + } + + let objects: Vec<_> = (0..3).map(|_| ready(pool.get()).unwrap()).collect(); + let mut recycled: Vec<_> = objects.iter().map(|object| **object).collect(); + ids.sort_unstable(); + recycled.sort_unstable(); + assert_eq!(recycled, ids); + assert_eq!(manager.created(), 3); + assert!(manager.detached().is_empty()); + } + }; +} + +mod bounded { + use std::sync::Arc; + + use asyncband::pool::bounded::Pool; + use asyncband::pool::bounded::PoolConfig; + + use super::*; + + fn pool( + capacity: usize, + manager: Manager, + strategy: Option, + ) -> Arc> { + let mut config = PoolConfig::new(capacity); + if let Some(strategy) = strategy { + config = config.with_recycle_cancelled_strategy(strategy); + } + Pool::new(config, manager) + } + + recycle_contract!(); +} + +mod unbounded { + use std::sync::Arc; + + use asyncband::pool::unbounded::Pool; + use asyncband::pool::unbounded::PoolConfig; + + use super::*; + + fn pool( + _capacity: usize, + manager: Manager, + strategy: Option, + ) -> Arc> { + let mut config = PoolConfig::new(); + if let Some(strategy) = strategy { + config = config.with_recycle_cancelled_strategy(strategy); + } + Pool::new(config, manager) + } + + recycle_contract!(); +} diff --git a/tests-integration/tests/pool_test/replenish.rs b/tests-integration/tests/pool_test/replenish.rs new file mode 100644 index 00000000..b0a351dc --- /dev/null +++ b/tests-integration/tests/pool_test/replenish.rs @@ -0,0 +1,152 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::task::Poll; + +use asyncband::pool::bounded::Pool; +use asyncband::pool::bounded::PoolConfig; +use tests_integration::WakeCounter; +use tests_integration::expect_ready; +use tests_integration::poll_once; +use tests_integration::poll_with; + +use super::support::Manager; +use super::support::ManagerError; +use super::support::ready; + +#[test] +fn targets_account_for_idle_objects_and_checked_out_capacity() { + for capacity in [1, 4] { + for checked_out in 0..=capacity { + for idle in 0..=capacity - checked_out { + for target in [0, 1, capacity, usize::MAX] { + let manager = Manager::default(); + let pool = Pool::new(PoolConfig::new(capacity), manager.clone()); + let active: Vec<_> = (0..checked_out) + .map(|_| ready(pool.get()).unwrap()) + .collect(); + assert_eq!(ready(pool.replenish_to(idle)), Ok(idle)); + let expected_idle = target.min(capacity - checked_out).max(idle); + assert_eq!(ready(pool.replenish_to(target)), Ok(expected_idle - idle)); + assert_eq!(pool.status().idle_count, expected_idle); + assert_eq!(pool.status().current_size, checked_out + expected_idle); + assert_eq!(manager.created(), checked_out + expected_idle); + drop(active); + assert_eq!(pool.status().idle_count, manager.created()); + } + } + } + } +} + +#[test] +fn creation_failure_keeps_completed_work_and_allows_a_retry() { + let manager = Manager::default(); + manager.pause_create().send(Ok(())).unwrap(); + manager.pause_create().send(Err(ManagerError)).unwrap(); + let pool = Pool::new(PoolConfig::new(3), manager.clone()); + + assert_eq!(ready(pool.replenish_to(3)), Err(ManagerError)); + assert_eq!(pool.status().current_size, 1); + assert_eq!(pool.status().idle_count, 1); + assert_eq!(manager.created(), 2); + + assert_eq!(ready(pool.replenish_to(3)), Ok(2)); + let mut ids: Vec<_> = (0..3) + .map(|_| ready(pool.get()).unwrap().detach()) + .collect(); + ids.sort_unstable(); + assert_eq!(ids, [1000, 1002, 1003]); +} + +#[test] +fn in_flight_creation_reserves_capacity_against_other_replenishers() { + let manager = Manager::default(); + let pool = Pool::new(PoolConfig::new(3), manager.clone()); + assert_eq!(ready(pool.replenish_to(1)), Ok(1)); + + let creation = manager.pause_create(); + let mut first = Box::pin(pool.replenish_to(3)); + assert!(poll_once(first.as_mut()).is_pending()); + assert_eq!(manager.created(), 2); + assert_eq!(ready(pool.replenish_to(3)), Ok(0)); + assert_eq!(manager.created(), 2); + + creation.send(Ok(())).unwrap(); + assert_eq!(poll_once(first.as_mut()), Poll::Ready(Ok(2))); + assert_eq!(pool.status().current_size, 3); + assert_eq!(pool.status().idle_count, 3); +} + +#[test] +fn replenished_object_wakes_a_checkout_waiting_for_capacity() { + let manager = Manager::default(); + let pool = Pool::new(PoolConfig::new(2), manager.clone()); + let held = ready(pool.get()).unwrap(); + let creation = manager.pause_create(); + let mut replenish = Box::pin(pool.replenish_to(2)); + assert!(poll_once(replenish.as_mut()).is_pending()); + + let (waker, wakes) = WakeCounter::new(); + let mut checkout = Box::pin(pool.get()); + assert!(poll_with(checkout.as_mut(), &waker).is_pending()); + assert_eq!(manager.created(), 2); + creation.send(Ok(())).unwrap(); + assert_eq!(poll_once(replenish.as_mut()), Poll::Ready(Ok(1))); + assert!(wakes.count() > 0); + let acquired = expect_ready(poll_with(checkout.as_mut(), &waker)).unwrap(); + assert_ne!(*held, *acquired); + assert_eq!(manager.created(), 2); + assert_eq!(pool.status().idle_count, 0); + drop((held, acquired)); + assert_eq!(pool.status().idle_count, 2); +} + +#[test] +fn cancellation_keeps_finished_objects_and_releases_unfilled_reservations() { + for completed in [0, 1] { + let manager = Manager::default(); + for _ in 0..completed { + manager.pause_create().send(Ok(())).unwrap(); + } + let creation = manager.pause_create(); + let pool = Pool::new(PoolConfig::new(3), manager.clone()); + let mut replenish = Box::pin(pool.replenish_to(3)); + assert!(poll_once(replenish.as_mut()).is_pending()); + assert_eq!(pool.status().current_size, completed); + assert_eq!(pool.status().idle_count, completed); + + let mut active: Vec<_> = (0..completed).map(|_| ready(pool.get()).unwrap()).collect(); + let (waker, wakes) = WakeCounter::new(); + let mut checkout = Box::pin(pool.get()); + assert!(poll_with(checkout.as_mut(), &waker).is_pending()); + drop(replenish); + assert!(creation.is_closed()); + assert!(wakes.count() > 0); + let acquired = expect_ready(poll_with(checkout.as_mut(), &waker)).unwrap(); + active.push(acquired); + for _ in active.len()..3 { + active.push(ready(pool.get()).unwrap()); + } + assert_eq!(pool.status().current_size, 3); + assert_eq!(pool.status().idle_count, 0); + assert!(manager.detached().is_empty()); + assert!(poll_once(Box::pin(pool.get()).as_mut()).is_pending()); + drop(active); + assert_eq!(pool.status().idle_count, 3); + } +} diff --git a/tests-integration/tests/pool_test/support.rs b/tests-integration/tests/pool_test/support.rs new file mode 100644 index 00000000..f4a23596 --- /dev/null +++ b/tests-integration/tests/pool_test/support.rs @@ -0,0 +1,100 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::collections::VecDeque; +use std::future::Future; +use std::pin::pin; +use std::sync::Arc; +use std::sync::Mutex; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +use asyncband::pool::ManageObject; +use asyncband::pool::ObjectStatus; +use tests_integration::expect_ready; +use tests_integration::poll_once; +use tokio::sync::oneshot; + +#[derive(Debug, PartialEq, Eq)] +pub struct ManagerError; + +type Step = oneshot::Receiver>; + +#[derive(Default)] +struct State { + created: AtomicUsize, + creating: Mutex>, + recycling: Mutex>, + detached: Mutex>, +} + +#[derive(Clone, Default)] +pub struct Manager(Arc); + +impl Manager { + pub fn created(&self) -> usize { + self.0.created.load(Ordering::Relaxed) + } + + pub fn detached(&self) -> Vec { + self.0.detached.lock().unwrap().clone() + } + + pub fn pause_create(&self) -> oneshot::Sender> { + let (sender, receiver) = oneshot::channel(); + self.0.creating.lock().unwrap().push_back(receiver); + sender + } + + pub fn pause_recycle(&self) -> oneshot::Sender> { + let (sender, receiver) = oneshot::channel(); + self.0.recycling.lock().unwrap().push_back(receiver); + sender + } +} + +impl ManageObject for Manager { + type Object = usize; + type Error = ManagerError; + + async fn create(&self) -> Result { + let id = self.0.created.fetch_add(1, Ordering::Relaxed); + let step = self.0.creating.lock().unwrap().pop_front(); + if let Some(step) = step { + step.await.expect("creation controller dropped")?; + } + Ok(id) + } + + async fn is_recyclable(&self, _: &mut usize, _: &ObjectStatus) -> Result<(), ManagerError> { + let step = self.0.recycling.lock().unwrap().pop_front(); + if let Some(step) = step { + step.await.expect("recycle controller dropped")?; + } + Ok(()) + } + + fn on_detached(&self, object: &mut usize) { + self.0.detached.lock().unwrap().push(*object); + // Make hook execution visible in the values returned by retain/detach as well. + *object += 1000; + } +} + +pub fn ready(future: F) -> F::Output { + expect_ready(poll_once(pin!(future))) +} diff --git a/tests-integration/tests/pool_test/traits.rs b/tests-integration/tests/pool_test/traits.rs new file mode 100644 index 00000000..a71613e3 --- /dev/null +++ b/tests-integration/tests/pool_test/traits.rs @@ -0,0 +1,49 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::cell::Cell; + +use asyncband::pool; + +use super::support::Manager; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_send() {} + fn assert_unpin() {} + + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_send::>>(); +} + +#[test] +fn unbounded_manual_manager_traits_do_not_depend_on_the_object() { + fn assert_copy() {} + fn assert_debug() {} + + assert_copy::>(); + assert_debug::>(); +} diff --git a/tests-integration/tests/rwlock_test.rs b/tests-integration/tests/rwlock_test/main.rs similarity index 99% rename from tests-integration/tests/rwlock_test.rs rename to tests-integration/tests/rwlock_test/main.rs index 1f95bd6a..f022f11b 100644 --- a/tests-integration/tests/rwlock_test.rs +++ b/tests-integration/tests/rwlock_test/main.rs @@ -23,6 +23,9 @@ use tests_integration::poll_once; use tokio_test::assert_pending; use tokio_test::assert_ready; +mod traits; +mod unsafe_paths; + #[test] fn try_methods_respect_held_guards() { let rwlock = Arc::new(RwLock::new(42)); diff --git a/tests-integration/tests/rwlock_test/traits.rs b/tests-integration/tests/rwlock_test/traits.rs new file mode 100644 index 00000000..c2c8c760 --- /dev/null +++ b/tests-integration/tests/rwlock_test/traits.rs @@ -0,0 +1,37 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::rwlock::OwnedRwLockReadGuard; +use asyncband::rwlock::RwLock; +use asyncband::rwlock::RwLockReadGuard; +use asyncband::rwlock::RwLockWriteGuard; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_send() {} + fn assert_unpin() {} + + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_send::>>(); +} diff --git a/tests-integration/tests/unsafe_paths_test.rs b/tests-integration/tests/rwlock_test/unsafe_paths.rs similarity index 53% rename from tests-integration/tests/unsafe_paths_test.rs rename to tests-integration/tests/rwlock_test/unsafe_paths.rs index 3a7ace5e..b7a643eb 100644 --- a/tests-integration/tests/unsafe_paths_test.rs +++ b/tests-integration/tests/rwlock_test/unsafe_paths.rs @@ -15,22 +15,8 @@ // specific language governing permissions and limitations // under the License. -use std::cell::Cell; -use std::future::Future; -use std::marker::PhantomPinned; -use std::pin::Pin; -use std::pin::pin; -use std::ptr; use std::sync::Arc; -use std::task::Context; -use std::task::Poll; -use asyncband::mutex::MappedMutexGuard; -use asyncband::mutex::Mutex; -use asyncband::mutex::MutexGuard; -use asyncband::mutex::OwnedMappedMutexGuard; -use asyncband::mutex::OwnedMutexGuard; -use asyncband::once::LazyCell; use asyncband::rwlock::MappedRwLockReadGuard; use asyncband::rwlock::MappedRwLockWriteGuard; use asyncband::rwlock::OwnedMappedRwLockReadGuard; @@ -40,34 +26,6 @@ use asyncband::rwlock::OwnedRwLockWriteGuard; use asyncband::rwlock::RwLock; use asyncband::rwlock::RwLockReadGuard; use asyncband::rwlock::RwLockWriteGuard; -use tests_integration::poll_once; - -#[test] -fn mapped_mutex_guards_preserve_lock_ownership() { - let mutex = Mutex::new((vec![1, 2], 3)); - let guard = mutex.try_lock().unwrap(); - let mapped = MutexGuard::map(guard, |value| &mut value.0); - let mut mapped = MappedMutexGuard::map(mapped, |values| &mut values[1]); - assert!(mutex.try_lock().is_none()); - *mapped = 4; - drop(mapped); - assert_eq!(mutex.into_inner(), (vec![1, 4], 3)); - - let mutex = Arc::new(Mutex::new(Some(vec![5, 6]))); - let weak = Arc::downgrade(&mutex); - let guard = mutex.clone().try_lock_owned().unwrap(); - let mapped = OwnedMutexGuard::filter_map(guard, Option::as_mut).unwrap(); - let mut mapped = OwnedMappedMutexGuard::map(mapped, |values| &mut values[0]); - assert!(mutex.try_lock().is_none()); - *mapped = 7; - drop(mapped); - let guard = mutex.try_lock().unwrap(); - assert_eq!(guard.as_deref(), Some([7, 6].as_slice())); - drop(guard); - - drop(mutex); - assert!(weak.upgrade().is_none()); -} #[derive(Debug, Eq, PartialEq)] struct Data { @@ -121,48 +79,3 @@ fn mapped_rwlock_guards_preserve_lock_ownership() { drop(lock); assert!(weak.upgrade().is_none()); } - -struct AddressSensitiveFuture { - address: Cell<*const Self>, - _pin: PhantomPinned, -} - -impl AddressSensitiveFuture { - fn new() -> Self { - Self { - address: Cell::new(ptr::null()), - _pin: PhantomPinned, - } - } -} - -impl Future for AddressSensitiveFuture { - type Output = i32; - - fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { - let this = self.as_ref().get_ref(); - let current = ptr::from_ref(this); - let first = this.address.get(); - if first.is_null() { - this.address.set(current); - Poll::Pending - } else { - assert!(ptr::eq(first, current)); - Poll::Ready(42) - } - } -} - -#[test] -fn lazy_cell_resumes_a_pinned_attempt_in_place() { - let lazy = LazyCell::from_future(AddressSensitiveFuture::new()); - let lazy = pin!(lazy); - - { - let mut force = pin!(LazyCell::force_pin(lazy.as_ref())); - assert!(poll_once(force.as_mut()).is_pending()); - } - - let mut force = pin!(LazyCell::force_pin(lazy.as_ref())); - assert_eq!(poll_once(force.as_mut()), Poll::Ready(&42)); -} diff --git a/tests-integration/tests/semaphore_test.rs b/tests-integration/tests/semaphore_test/main.rs similarity index 99% rename from tests-integration/tests/semaphore_test.rs rename to tests-integration/tests/semaphore_test/main.rs index a3f4f675..512e0625 100644 --- a/tests-integration/tests/semaphore_test.rs +++ b/tests-integration/tests/semaphore_test/main.rs @@ -28,6 +28,8 @@ use tests_integration::WakeCounter; use tests_integration::expect_ready; use tests_integration::poll_with; +mod traits; + #[test] fn no_permits() { // this should not panic diff --git a/tests-integration/tests/semaphore_test/traits.rs b/tests-integration/tests/semaphore_test/traits.rs new file mode 100644 index 00000000..ac21c216 --- /dev/null +++ b/tests-integration/tests/semaphore_test/traits.rs @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::semaphore::Semaphore; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::(); + assert_unpin::(); +} diff --git a/tests-integration/tests/shutdown_test.rs b/tests-integration/tests/shutdown_test/main.rs similarity index 99% rename from tests-integration/tests/shutdown_test.rs rename to tests-integration/tests/shutdown_test/main.rs index db36080b..86b410bd 100644 --- a/tests-integration/tests/shutdown_test.rs +++ b/tests-integration/tests/shutdown_test/main.rs @@ -23,6 +23,8 @@ use asyncband::shutdown::*; use tests_integration::poll_once; use tests_integration::test_runtime; +mod traits; + #[test] fn test_single_pair() { let (shutdown, guard) = new(); diff --git a/tests-integration/tests/shutdown_test/traits.rs b/tests-integration/tests/shutdown_test/traits.rs new file mode 100644 index 00000000..b6e5bf34 --- /dev/null +++ b/tests-integration/tests/shutdown_test/traits.rs @@ -0,0 +1,33 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::shutdown::Shutdown; +use asyncband::shutdown::ShutdownGuard; +use asyncband::shutdown::ShutdownWatch; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::(); +} diff --git a/tests-integration/tests/singleflight_test.rs b/tests-integration/tests/singleflight_test/main.rs similarity index 99% rename from tests-integration/tests/singleflight_test.rs rename to tests-integration/tests/singleflight_test/main.rs index 87008f36..23ccf5e6 100644 --- a/tests-integration/tests/singleflight_test.rs +++ b/tests-integration/tests/singleflight_test/main.rs @@ -21,6 +21,8 @@ use std::sync::atomic::Ordering; use asyncband::singleflight::Group; use tests_integration::poll_once; +mod traits; + #[tokio::test] async fn supports_non_clone_key() { #[derive(Hash, PartialEq, Eq)] diff --git a/tests-integration/tests/singleflight_test/traits.rs b/tests-integration/tests/singleflight_test/traits.rs new file mode 100644 index 00000000..c5d38548 --- /dev/null +++ b/tests-integration/tests/singleflight_test/traits.rs @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::singleflight; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::>(); + assert_unpin::>(); +} diff --git a/tests-integration/tests/traits_test.rs b/tests-integration/tests/traits_test.rs deleted file mode 100644 index 26205e34..00000000 --- a/tests-integration/tests/traits_test.rs +++ /dev/null @@ -1,275 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use std::cell::Cell; -use std::marker::PhantomPinned; -use std::panic::RefUnwindSafe; -use std::panic::UnwindSafe; - -use asyncband::barrier::Barrier; -use asyncband::broadcast; -use asyncband::completion; -use asyncband::condvar::Condvar; -use asyncband::event::AutoResetEvent; -use asyncband::event::ManualResetEvent; -use asyncband::latch::Latch; -use asyncband::mpmc; -use asyncband::mpsc; -use asyncband::mutex::Mutex; -use asyncband::mutex::MutexGuard; -use asyncband::once::LazyCell; -use asyncband::once::Once; -use asyncband::once::OnceCell; -use asyncband::once::OnceMap; -use asyncband::oneshot; -use asyncband::phaser::Closed; -use asyncband::phaser::Phaser; -use asyncband::phaser::PhaserParticipant; -use asyncband::phaser::PhaserParticipants; -use asyncband::pool; -use asyncband::pool::ManageObject; -use asyncband::pool::ObjectStatus; -use asyncband::rwlock::OwnedRwLockReadGuard; -use asyncband::rwlock::RwLock; -use asyncband::rwlock::RwLockReadGuard; -use asyncband::rwlock::RwLockWriteGuard; -use asyncband::semaphore::Semaphore; -use asyncband::shutdown::Shutdown; -use asyncband::shutdown::ShutdownGuard; -use asyncband::shutdown::ShutdownWatch; -use asyncband::singleflight; -use asyncband::waitgroup::Wait; -use asyncband::waitgroup::WaitGroup; -use asyncband::watch; - -struct PoolManager; - -impl ManageObject for PoolManager { - type Object = i64; - type Error = std::convert::Infallible; - - async fn create(&self) -> Result { - Ok(0) - } - - async fn is_recyclable( - &self, - _object: &mut Self::Object, - _status: &ObjectStatus, - ) -> Result<(), Self::Error> { - Ok(()) - } -} - -#[test] -fn public_types_are_send_and_sync() { - fn assert_send_and_sync() {} - - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::>>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::(); - assert_send_and_sync::>>(); - assert_send_and_sync::(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>>(); - assert_send_and_sync::>>(); - assert_send_and_sync::>>(); - assert_send_and_sync::>>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::(); -} - -#[test] -fn movable_public_types_are_send() { - fn assert_send() {} - fn assert_send_value(_: T) {} - - assert_send::>>(); - assert_send::>(); - assert_send::>(); - assert_send::>>(); - - let (_tx, mut rx) = watch::channel(0); - assert_send_value(rx.changed()); - assert_send_value(rx.recv()); - - let (_completer, completion) = completion::new::(); - assert_send_value(completion.wait()); - - let (unbounded_sender, unbounded_receiver) = mpmc::unbounded::>(); - assert_send_value(unbounded_receiver.recv()); - drop(unbounded_sender); - - let (bounded_sender, bounded_receiver) = mpmc::bounded::>(1); - assert_send_value(bounded_sender.send(Cell::new(0))); - assert_send_value(bounded_receiver.recv()); -} - -#[test] -fn public_types_are_unpin() { - fn assert_unpin() {} - - assert_unpin::(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::>>(); - assert_unpin::(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::(); -} - -#[test] -fn mpsc_endpoints_keep_legacy_traits_regardless_of_payload() { - fn assert_send() {} - fn assert_sync() {} - fn assert_unpin() {} - fn assert_unwind_safe() {} - fn assert_ref_unwind_safe() {} - - macro_rules! assert_endpoint_traits { - ($endpoint:ident, $payload:ty) => { - assert_send::>(); - assert_sync::>(); - assert_unpin::>(); - assert_unwind_safe::>(); - assert_ref_unwind_safe::>(); - }; - } - - macro_rules! assert_payload_traits { - ($endpoint:ident) => { - assert_endpoint_traits!($endpoint, i32); - assert_endpoint_traits!($endpoint, Cell); - assert_endpoint_traits!($endpoint, &'static mut i32); - assert_endpoint_traits!($endpoint, PhantomPinned); - }; - } - - // Four endpoint types × four payloads × five traits = 80 compile-time assertions. - assert_payload_traits!(BoundedSender); - assert_payload_traits!(BoundedReceiver); - assert_payload_traits!(UnboundedSender); - assert_payload_traits!(UnboundedReceiver); -} - -#[test] -fn unbounded_manual_manager_traits_do_not_depend_on_the_object() { - fn assert_copy() {} - fn assert_debug() {} - - assert_copy::>(); - assert_debug::>(); -} diff --git a/tests-integration/tests/waitgroup_test.rs b/tests-integration/tests/waitgroup_test/main.rs similarity index 99% rename from tests-integration/tests/waitgroup_test.rs rename to tests-integration/tests/waitgroup_test/main.rs index c78c6b45..c67fb5f6 100644 --- a/tests-integration/tests/waitgroup_test.rs +++ b/tests-integration/tests/waitgroup_test/main.rs @@ -23,6 +23,8 @@ use asyncband::waitgroup::WaitGroup; use tests_integration::WakeCounter; use tests_integration::poll_once; +mod traits; + #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn waits_for_all_worker_handles() { let wg = WaitGroup::new(); diff --git a/tests-integration/tests/waitgroup_test/traits.rs b/tests-integration/tests/waitgroup_test/traits.rs new file mode 100644 index 00000000..b42a76ec --- /dev/null +++ b/tests-integration/tests/waitgroup_test/traits.rs @@ -0,0 +1,29 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::waitgroup::Wait; +use asyncband::waitgroup::WaitGroup; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + + assert_send_and_sync::(); + assert_unpin::(); + assert_unpin::(); +} diff --git a/tests-integration/tests/watch_test.rs b/tests-integration/tests/watch_test/main.rs similarity index 99% rename from tests-integration/tests/watch_test.rs rename to tests-integration/tests/watch_test/main.rs index 2636e77f..d8d66dd6 100644 --- a/tests-integration/tests/watch_test.rs +++ b/tests-integration/tests/watch_test/main.rs @@ -30,6 +30,8 @@ use tests_integration::poll_with; use tests_integration::waker_on_drop; use tests_integration::waker_on_wake; +mod traits; + #[derive(Clone)] struct ReentrantDrop(Option>); diff --git a/tests-integration/tests/watch_test/traits.rs b/tests-integration/tests/watch_test/traits.rs new file mode 100644 index 00000000..0f286a18 --- /dev/null +++ b/tests-integration/tests/watch_test/traits.rs @@ -0,0 +1,38 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use asyncband::watch; + +#[test] +fn public_types_keep_their_auto_traits() { + fn assert_send_and_sync() {} + fn assert_unpin() {} + fn assert_send_value(_: T) {} + + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::(); + + let (_tx, mut rx) = watch::channel(0); + assert_send_value(rx.changed()); + assert_send_value(rx.recv()); +} diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 6ae91be7..5a799464 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -116,10 +116,12 @@ impl CommandMiri { "tests-integration", &["--test", "oneshot_test"], )); - run_command(make_miri_cmd( - "tests-integration", - &["--test", "unsafe_paths_test"], - )); + for target in ["mutex_test", "rwlock_test", "lazy_cell_test"] { + run_command(make_miri_cmd( + "tests-integration", + &["--test", target, "unsafe_paths::"], + )); + } run_command(make_miri_cmd("tests-integration", &["--test", "mpsc_test"])); run_command(make_miri_cmd("tests-integration", &["--test", "mpmc_test"])); run_command(make_miri_cmd("tests-integration", &["--test", "spmc_test"])); From c0fd84c29b07eed50aa639e3c3a8d9e87b3ed7c3 Mon Sep 17 00:00:00 2001 From: tison Date: Mon, 21 Sep 2026 14:51:35 +0800 Subject: [PATCH 2/2] test: preserve cross-cutting integration suites --- .../{barrier_test/main.rs => barrier_test.rs} | 3 - .../tests/barrier_test/traits.rs | 27 -- .../main.rs => blocking_test.rs} | 2 - .../tests/blocking_test/composition.rs | 44 --- .../tests/broadcast_test/main.rs | 1 - .../tests/broadcast_test/traits.rs | 39 --- .../main.rs => completion_test.rs} | 2 - .../tests/completion_test/traits.rs | 38 --- .../composition.rs => composition_test.rs} | 24 ++ .../{condvar_test/main.rs => condvar_test.rs} | 2 - .../tests/condvar_test/traits.rs | 27 -- tests-integration/tests/event_test/main.rs | 1 - tests-integration/tests/event_test/traits.rs | 30 -- .../{latch_test/main.rs => latch_test.rs} | 2 - tests-integration/tests/latch_test/traits.rs | 27 -- .../main.rs => lazy_cell_test.rs} | 3 - .../tests/lazy_cell_test/traits.rs | 27 -- .../tests/lazy_cell_test/unsafe_paths.rs | 73 ----- tests-integration/tests/mpmc_test/main.rs | 1 - tests-integration/tests/mpmc_test/traits.rs | 50 ---- tests-integration/tests/mpsc_test/main.rs | 1 - tests-integration/tests/mpsc_test/traits.rs | 74 ----- .../{mutex_test/main.rs => mutex_test.rs} | 3 - tests-integration/tests/mutex_test/traits.rs | 30 -- .../tests/mutex_test/unsafe_paths.rs | 51 ---- .../main.rs => once_cell_test.rs} | 2 - .../tests/once_cell_test/traits.rs | 27 -- .../main.rs => once_map_test.rs} | 2 - .../tests/once_map_test/traits.rs | 27 -- .../tests/{once_test/main.rs => once_test.rs} | 2 - tests-integration/tests/once_test/traits.rs | 27 -- tests-integration/tests/oneshot_test/main.rs | 1 - .../tests/oneshot_test/traits.rs | 34 --- .../{phaser_test/main.rs => phaser_test.rs} | 2 - tests-integration/tests/phaser_test/traits.rs | 36 --- tests-integration/tests/pool_test/main.rs | 1 - tests-integration/tests/pool_test/traits.rs | 49 ---- .../{rwlock_test/main.rs => rwlock_test.rs} | 3 - tests-integration/tests/rwlock_test/traits.rs | 37 --- .../main.rs => semaphore_test.rs} | 2 - .../tests/semaphore_test/traits.rs | 27 -- .../main.rs => shutdown_test.rs} | 2 - .../tests/shutdown_test/traits.rs | 33 --- .../main.rs => singleflight_test.rs} | 2 - .../tests/singleflight_test/traits.rs | 27 -- tests-integration/tests/traits_test.rs | 275 ++++++++++++++++++ .../unsafe_paths.rs => unsafe_paths_test.rs} | 87 ++++++ .../main.rs => waitgroup_test.rs} | 2 - .../tests/waitgroup_test/traits.rs | 29 -- .../{watch_test/main.rs => watch_test.rs} | 2 - tests-integration/tests/watch_test/traits.rs | 38 --- xtask/src/main.rs | 10 +- 52 files changed, 390 insertions(+), 978 deletions(-) rename tests-integration/tests/{barrier_test/main.rs => barrier_test.rs} (99%) delete mode 100644 tests-integration/tests/barrier_test/traits.rs rename tests-integration/tests/{blocking_test/main.rs => blocking_test.rs} (99%) delete mode 100644 tests-integration/tests/blocking_test/composition.rs delete mode 100644 tests-integration/tests/broadcast_test/traits.rs rename tests-integration/tests/{completion_test/main.rs => completion_test.rs} (99%) delete mode 100644 tests-integration/tests/completion_test/traits.rs rename tests-integration/tests/{barrier_test/composition.rs => composition_test.rs} (72%) rename tests-integration/tests/{condvar_test/main.rs => condvar_test.rs} (99%) delete mode 100644 tests-integration/tests/condvar_test/traits.rs delete mode 100644 tests-integration/tests/event_test/traits.rs rename tests-integration/tests/{latch_test/main.rs => latch_test.rs} (99%) delete mode 100644 tests-integration/tests/latch_test/traits.rs rename tests-integration/tests/{lazy_cell_test/main.rs => lazy_cell_test.rs} (99%) delete mode 100644 tests-integration/tests/lazy_cell_test/traits.rs delete mode 100644 tests-integration/tests/lazy_cell_test/unsafe_paths.rs delete mode 100644 tests-integration/tests/mpmc_test/traits.rs delete mode 100644 tests-integration/tests/mpsc_test/traits.rs rename tests-integration/tests/{mutex_test/main.rs => mutex_test.rs} (99%) delete mode 100644 tests-integration/tests/mutex_test/traits.rs delete mode 100644 tests-integration/tests/mutex_test/unsafe_paths.rs rename tests-integration/tests/{once_cell_test/main.rs => once_cell_test.rs} (99%) delete mode 100644 tests-integration/tests/once_cell_test/traits.rs rename tests-integration/tests/{once_map_test/main.rs => once_map_test.rs} (99%) delete mode 100644 tests-integration/tests/once_map_test/traits.rs rename tests-integration/tests/{once_test/main.rs => once_test.rs} (99%) delete mode 100644 tests-integration/tests/once_test/traits.rs delete mode 100644 tests-integration/tests/oneshot_test/traits.rs rename tests-integration/tests/{phaser_test/main.rs => phaser_test.rs} (99%) delete mode 100644 tests-integration/tests/phaser_test/traits.rs delete mode 100644 tests-integration/tests/pool_test/traits.rs rename tests-integration/tests/{rwlock_test/main.rs => rwlock_test.rs} (99%) delete mode 100644 tests-integration/tests/rwlock_test/traits.rs rename tests-integration/tests/{semaphore_test/main.rs => semaphore_test.rs} (99%) delete mode 100644 tests-integration/tests/semaphore_test/traits.rs rename tests-integration/tests/{shutdown_test/main.rs => shutdown_test.rs} (99%) delete mode 100644 tests-integration/tests/shutdown_test/traits.rs rename tests-integration/tests/{singleflight_test/main.rs => singleflight_test.rs} (99%) delete mode 100644 tests-integration/tests/singleflight_test/traits.rs create mode 100644 tests-integration/tests/traits_test.rs rename tests-integration/tests/{rwlock_test/unsafe_paths.rs => unsafe_paths_test.rs} (53%) rename tests-integration/tests/{waitgroup_test/main.rs => waitgroup_test.rs} (99%) delete mode 100644 tests-integration/tests/waitgroup_test/traits.rs rename tests-integration/tests/{watch_test/main.rs => watch_test.rs} (99%) delete mode 100644 tests-integration/tests/watch_test/traits.rs diff --git a/tests-integration/tests/barrier_test/main.rs b/tests-integration/tests/barrier_test.rs similarity index 99% rename from tests-integration/tests/barrier_test/main.rs rename to tests-integration/tests/barrier_test.rs index a6136f20..82d600a5 100644 --- a/tests-integration/tests/barrier_test/main.rs +++ b/tests-integration/tests/barrier_test.rs @@ -20,9 +20,6 @@ use tokio_test::assert_pending; use tokio_test::assert_ready; use tokio_test::task::spawn; -mod composition; -mod traits; - #[test] fn zero_does_not_block() { let b = Barrier::new(0); diff --git a/tests-integration/tests/barrier_test/traits.rs b/tests-integration/tests/barrier_test/traits.rs deleted file mode 100644 index 7cbd60d2..00000000 --- a/tests-integration/tests/barrier_test/traits.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::barrier::Barrier; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::(); - assert_unpin::(); -} diff --git a/tests-integration/tests/blocking_test/main.rs b/tests-integration/tests/blocking_test.rs similarity index 99% rename from tests-integration/tests/blocking_test/main.rs rename to tests-integration/tests/blocking_test.rs index f9bebbbb..5f5e7511 100644 --- a/tests-integration/tests/blocking_test/main.rs +++ b/tests-integration/tests/blocking_test.rs @@ -28,8 +28,6 @@ use std::time::Duration; use asyncband::blocking::FutureExt as _; -mod composition; - // Long timeouts in this test target are watchdogs for detecting a stalled test process, not // assertions about elapsed-time precision. const TEST_WATCHDOG: Duration = Duration::from_secs(5); diff --git a/tests-integration/tests/blocking_test/composition.rs b/tests-integration/tests/blocking_test/composition.rs deleted file mode 100644 index d4c6ec06..00000000 --- a/tests-integration/tests/blocking_test/composition.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use std::thread; -use std::time::Duration; - -use asyncband::blocking::FutureExt as _; -use asyncband::mutex::Mutex; -use asyncband::oneshot; - -#[test] -fn blocking_bridge_composes_with_public_primitives() { - let mutex = Mutex::new(1); - *mutex.lock().block_on() += 1; - assert_eq!(*mutex.lock().block_on(), 2); - - let (sender, receiver) = oneshot::channel(); - let producer = thread::spawn(move || sender.send(7).unwrap()); - - assert_eq!(receiver.block_on(), Ok(7)); - producer.join().unwrap(); -} - -#[test] -fn timed_out_wait_cancels_an_asyncband_future() { - let (sender, receiver) = oneshot::channel(); - - assert_eq!(receiver.wait_timeout(Duration::ZERO), None); - assert_eq!(sender.send(7).unwrap_err().into_inner(), 7); -} diff --git a/tests-integration/tests/broadcast_test/main.rs b/tests-integration/tests/broadcast_test/main.rs index 7e6ae71a..e0ac8347 100644 --- a/tests-integration/tests/broadcast_test/main.rs +++ b/tests-integration/tests/broadcast_test/main.rs @@ -16,5 +16,4 @@ // under the License. mod bounded; -mod traits; mod unbounded; diff --git a/tests-integration/tests/broadcast_test/traits.rs b/tests-integration/tests/broadcast_test/traits.rs deleted file mode 100644 index 35a626c4..00000000 --- a/tests-integration/tests/broadcast_test/traits.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::broadcast; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::>(); -} diff --git a/tests-integration/tests/completion_test/main.rs b/tests-integration/tests/completion_test.rs similarity index 99% rename from tests-integration/tests/completion_test/main.rs rename to tests-integration/tests/completion_test.rs index fadb125e..8200e23b 100644 --- a/tests-integration/tests/completion_test/main.rs +++ b/tests-integration/tests/completion_test.rs @@ -31,8 +31,6 @@ use tests_integration::poll_with; use tests_integration::waker_on_drop; use tests_integration::waker_on_wake; -mod traits; - struct NotClone(String); #[test] diff --git a/tests-integration/tests/completion_test/traits.rs b/tests-integration/tests/completion_test/traits.rs deleted file mode 100644 index 3e009147..00000000 --- a/tests-integration/tests/completion_test/traits.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use std::cell::Cell; - -use asyncband::completion; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - fn assert_send_value(_: T) {} - - assert_send_and_sync::>>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::(); - - let (_completer, completion) = completion::new::(); - assert_send_value(completion.wait()); -} diff --git a/tests-integration/tests/barrier_test/composition.rs b/tests-integration/tests/composition_test.rs similarity index 72% rename from tests-integration/tests/barrier_test/composition.rs rename to tests-integration/tests/composition_test.rs index e6187908..64ac539b 100644 --- a/tests-integration/tests/barrier_test/composition.rs +++ b/tests-integration/tests/composition_test.rs @@ -16,8 +16,11 @@ // under the License. use std::sync::Arc; +use std::thread; +use std::time::Duration; use asyncband::barrier::Barrier; +use asyncband::blocking::FutureExt as _; use asyncband::mutex::Mutex; use asyncband::oneshot; @@ -51,3 +54,24 @@ async fn public_primitives_compose_across_modules() { values.sort_unstable(); assert_eq!(*values, [1, 2]); } + +#[test] +fn blocking_bridge_composes_with_public_primitives() { + let mutex = Mutex::new(1); + *mutex.lock().block_on() += 1; + assert_eq!(*mutex.lock().block_on(), 2); + + let (sender, receiver) = oneshot::channel(); + let producer = thread::spawn(move || sender.send(7).unwrap()); + + assert_eq!(receiver.block_on(), Ok(7)); + producer.join().unwrap(); +} + +#[test] +fn timed_out_wait_cancels_an_asyncband_future() { + let (sender, receiver) = oneshot::channel(); + + assert_eq!(receiver.wait_timeout(Duration::ZERO), None); + assert_eq!(sender.send(7).unwrap_err().into_inner(), 7); +} diff --git a/tests-integration/tests/condvar_test/main.rs b/tests-integration/tests/condvar_test.rs similarity index 99% rename from tests-integration/tests/condvar_test/main.rs rename to tests-integration/tests/condvar_test.rs index dd1e3e9e..fb7128fe 100644 --- a/tests-integration/tests/condvar_test/main.rs +++ b/tests-integration/tests/condvar_test.rs @@ -28,8 +28,6 @@ use tests_integration::poll_with; use tests_integration::test_runtime; use tokio::task::JoinHandle; -mod traits; - struct NotifyOnDrop(Arc); impl Wake for NotifyOnDrop { diff --git a/tests-integration/tests/condvar_test/traits.rs b/tests-integration/tests/condvar_test/traits.rs deleted file mode 100644 index 761a66a8..00000000 --- a/tests-integration/tests/condvar_test/traits.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::condvar::Condvar; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::(); - assert_unpin::(); -} diff --git a/tests-integration/tests/event_test/main.rs b/tests-integration/tests/event_test/main.rs index eb6ae1a7..60e0b8c7 100644 --- a/tests-integration/tests/event_test/main.rs +++ b/tests-integration/tests/event_test/main.rs @@ -17,4 +17,3 @@ mod auto_reset; mod manual_reset; -mod traits; diff --git a/tests-integration/tests/event_test/traits.rs b/tests-integration/tests/event_test/traits.rs deleted file mode 100644 index 6ef22daa..00000000 --- a/tests-integration/tests/event_test/traits.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::event::AutoResetEvent; -use asyncband::event::ManualResetEvent; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_unpin::(); - assert_unpin::(); -} diff --git a/tests-integration/tests/latch_test/main.rs b/tests-integration/tests/latch_test.rs similarity index 99% rename from tests-integration/tests/latch_test/main.rs rename to tests-integration/tests/latch_test.rs index 280d6496..7a4e6c6c 100644 --- a/tests-integration/tests/latch_test/main.rs +++ b/tests-integration/tests/latch_test.rs @@ -22,8 +22,6 @@ use std::task::Waker; use asyncband::latch::Latch; use tests_integration::WakeCounter; -mod traits; - #[test] fn countdown_operations_saturate_at_zero() { let latch = Latch::new(5); diff --git a/tests-integration/tests/latch_test/traits.rs b/tests-integration/tests/latch_test/traits.rs deleted file mode 100644 index 361c497e..00000000 --- a/tests-integration/tests/latch_test/traits.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::latch::Latch; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::(); - assert_unpin::(); -} diff --git a/tests-integration/tests/lazy_cell_test/main.rs b/tests-integration/tests/lazy_cell_test.rs similarity index 99% rename from tests-integration/tests/lazy_cell_test/main.rs rename to tests-integration/tests/lazy_cell_test.rs index 42b75874..26046021 100644 --- a/tests-integration/tests/lazy_cell_test/main.rs +++ b/tests-integration/tests/lazy_cell_test.rs @@ -25,9 +25,6 @@ use std::sync::atomic::Ordering; use asyncband::once::LazyCell; use tokio::sync::Notify; -mod traits; -mod unsafe_paths; - struct DropPanic; impl Drop for DropPanic { diff --git a/tests-integration/tests/lazy_cell_test/traits.rs b/tests-integration/tests/lazy_cell_test/traits.rs deleted file mode 100644 index 72e1ed5c..00000000 --- a/tests-integration/tests/lazy_cell_test/traits.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::once::LazyCell; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::>>(); - assert_unpin::>>(); -} diff --git a/tests-integration/tests/lazy_cell_test/unsafe_paths.rs b/tests-integration/tests/lazy_cell_test/unsafe_paths.rs deleted file mode 100644 index 1f42b591..00000000 --- a/tests-integration/tests/lazy_cell_test/unsafe_paths.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use std::cell::Cell; -use std::future::Future; -use std::marker::PhantomPinned; -use std::pin::Pin; -use std::pin::pin; -use std::ptr; -use std::task::Context; -use std::task::Poll; - -use asyncband::once::LazyCell; -use tests_integration::poll_once; - -struct AddressSensitiveFuture { - address: Cell<*const Self>, - _pin: PhantomPinned, -} - -impl AddressSensitiveFuture { - fn new() -> Self { - Self { - address: Cell::new(ptr::null()), - _pin: PhantomPinned, - } - } -} - -impl Future for AddressSensitiveFuture { - type Output = i32; - - fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { - let this = self.as_ref().get_ref(); - let current = ptr::from_ref(this); - let first = this.address.get(); - if first.is_null() { - this.address.set(current); - Poll::Pending - } else { - assert!(ptr::eq(first, current)); - Poll::Ready(42) - } - } -} - -#[test] -fn lazy_cell_resumes_a_pinned_attempt_in_place() { - let lazy = LazyCell::from_future(AddressSensitiveFuture::new()); - let lazy = pin!(lazy); - - { - let mut force = pin!(LazyCell::force_pin(lazy.as_ref())); - assert!(poll_once(force.as_mut()).is_pending()); - } - - let mut force = pin!(LazyCell::force_pin(lazy.as_ref())); - assert_eq!(poll_once(force.as_mut()), Poll::Ready(&42)); -} diff --git a/tests-integration/tests/mpmc_test/main.rs b/tests-integration/tests/mpmc_test/main.rs index 3f344fd1..8795d7ad 100644 --- a/tests-integration/tests/mpmc_test/main.rs +++ b/tests-integration/tests/mpmc_test/main.rs @@ -29,7 +29,6 @@ use tests_integration::poll_once; mod callbacks; mod concurrency; mod notification; -mod traits; /// Either receiver flavor, so one case can cover both queues. trait Receiver: Clone { diff --git a/tests-integration/tests/mpmc_test/traits.rs b/tests-integration/tests/mpmc_test/traits.rs deleted file mode 100644 index 40af62ce..00000000 --- a/tests-integration/tests/mpmc_test/traits.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use std::cell::Cell; - -use asyncband::mpmc; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - fn assert_send_value(_: T) {} - - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>>(); - assert_send_and_sync::>>(); - assert_send_and_sync::>>(); - assert_send_and_sync::>>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - - let (unbounded_sender, unbounded_receiver) = mpmc::unbounded::>(); - assert_send_value(unbounded_receiver.recv()); - drop(unbounded_sender); - - let (bounded_sender, bounded_receiver) = mpmc::bounded::>(1); - assert_send_value(bounded_sender.send(Cell::new(0))); - assert_send_value(bounded_receiver.recv()); -} diff --git a/tests-integration/tests/mpsc_test/main.rs b/tests-integration/tests/mpsc_test/main.rs index 7e2a254d..35b21b05 100644 --- a/tests-integration/tests/mpsc_test/main.rs +++ b/tests-integration/tests/mpsc_test/main.rs @@ -31,7 +31,6 @@ mod backpressure; mod callbacks; mod concurrency; mod reservation; -mod traits; #[test] fn unbounded_try_recv_preserves_order_and_reports_state() { diff --git a/tests-integration/tests/mpsc_test/traits.rs b/tests-integration/tests/mpsc_test/traits.rs deleted file mode 100644 index 98856df9..00000000 --- a/tests-integration/tests/mpsc_test/traits.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use std::cell::Cell; -use std::marker::PhantomPinned; -use std::panic::RefUnwindSafe; -use std::panic::UnwindSafe; - -use asyncband::mpsc; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); -} - -#[test] -fn mpsc_endpoints_keep_legacy_traits_regardless_of_payload() { - fn assert_send() {} - fn assert_sync() {} - fn assert_unpin() {} - fn assert_unwind_safe() {} - fn assert_ref_unwind_safe() {} - - macro_rules! assert_endpoint_traits { - ($endpoint:ident, $payload:ty) => { - assert_send::>(); - assert_sync::>(); - assert_unpin::>(); - assert_unwind_safe::>(); - assert_ref_unwind_safe::>(); - }; - } - - macro_rules! assert_payload_traits { - ($endpoint:ident) => { - assert_endpoint_traits!($endpoint, i32); - assert_endpoint_traits!($endpoint, Cell); - assert_endpoint_traits!($endpoint, &'static mut i32); - assert_endpoint_traits!($endpoint, PhantomPinned); - }; - } - - // Four endpoint types × four payloads × five traits = 80 compile-time assertions. - assert_payload_traits!(BoundedSender); - assert_payload_traits!(BoundedReceiver); - assert_payload_traits!(UnboundedSender); - assert_payload_traits!(UnboundedReceiver); -} diff --git a/tests-integration/tests/mutex_test/main.rs b/tests-integration/tests/mutex_test.rs similarity index 99% rename from tests-integration/tests/mutex_test/main.rs rename to tests-integration/tests/mutex_test.rs index 2a243235..8dd11070 100644 --- a/tests-integration/tests/mutex_test/main.rs +++ b/tests-integration/tests/mutex_test.rs @@ -20,9 +20,6 @@ use std::sync::Arc; use asyncband::mutex::*; use tests_integration::poll_once; -mod traits; -mod unsafe_paths; - #[test] fn test_try_lock_never_blocks() { // Test that try_lock and try_lock_owned never block, even under contention diff --git a/tests-integration/tests/mutex_test/traits.rs b/tests-integration/tests/mutex_test/traits.rs deleted file mode 100644 index 8c0f5258..00000000 --- a/tests-integration/tests/mutex_test/traits.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::mutex::Mutex; -use asyncband::mutex::MutexGuard; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_unpin::>(); - assert_unpin::>(); -} diff --git a/tests-integration/tests/mutex_test/unsafe_paths.rs b/tests-integration/tests/mutex_test/unsafe_paths.rs deleted file mode 100644 index 5f795cbc..00000000 --- a/tests-integration/tests/mutex_test/unsafe_paths.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use std::sync::Arc; - -use asyncband::mutex::MappedMutexGuard; -use asyncband::mutex::Mutex; -use asyncband::mutex::MutexGuard; -use asyncband::mutex::OwnedMappedMutexGuard; -use asyncband::mutex::OwnedMutexGuard; - -#[test] -fn mapped_mutex_guards_preserve_lock_ownership() { - let mutex = Mutex::new((vec![1, 2], 3)); - let guard = mutex.try_lock().unwrap(); - let mapped = MutexGuard::map(guard, |value| &mut value.0); - let mut mapped = MappedMutexGuard::map(mapped, |values| &mut values[1]); - assert!(mutex.try_lock().is_none()); - *mapped = 4; - drop(mapped); - assert_eq!(mutex.into_inner(), (vec![1, 4], 3)); - - let mutex = Arc::new(Mutex::new(Some(vec![5, 6]))); - let weak = Arc::downgrade(&mutex); - let guard = mutex.clone().try_lock_owned().unwrap(); - let mapped = OwnedMutexGuard::filter_map(guard, Option::as_mut).unwrap(); - let mut mapped = OwnedMappedMutexGuard::map(mapped, |values| &mut values[0]); - assert!(mutex.try_lock().is_none()); - *mapped = 7; - drop(mapped); - let guard = mutex.try_lock().unwrap(); - assert_eq!(guard.as_deref(), Some([7, 6].as_slice())); - drop(guard); - - drop(mutex); - assert!(weak.upgrade().is_none()); -} diff --git a/tests-integration/tests/once_cell_test/main.rs b/tests-integration/tests/once_cell_test.rs similarity index 99% rename from tests-integration/tests/once_cell_test/main.rs rename to tests-integration/tests/once_cell_test.rs index 86a86beb..f9303397 100644 --- a/tests-integration/tests/once_cell_test/main.rs +++ b/tests-integration/tests/once_cell_test.rs @@ -23,8 +23,6 @@ use std::sync::atomic::Ordering; use asyncband::once::OnceCell; use tests_integration::poll_once; -mod traits; - struct DropFlag(Arc); impl Drop for DropFlag { diff --git a/tests-integration/tests/once_cell_test/traits.rs b/tests-integration/tests/once_cell_test/traits.rs deleted file mode 100644 index 148e3d1d..00000000 --- a/tests-integration/tests/once_cell_test/traits.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::once::OnceCell; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::>(); - assert_unpin::>(); -} diff --git a/tests-integration/tests/once_map_test/main.rs b/tests-integration/tests/once_map_test.rs similarity index 99% rename from tests-integration/tests/once_map_test/main.rs rename to tests-integration/tests/once_map_test.rs index 35ec1883..6b2c61d7 100644 --- a/tests-integration/tests/once_map_test/main.rs +++ b/tests-integration/tests/once_map_test.rs @@ -27,8 +27,6 @@ use std::sync::atomic::Ordering; use asyncband::once::OnceMap; use tests_integration::poll_once; -mod traits; - #[test] fn constructors_and_default() { let _: OnceMap = OnceMap::default(); diff --git a/tests-integration/tests/once_map_test/traits.rs b/tests-integration/tests/once_map_test/traits.rs deleted file mode 100644 index 18d8512b..00000000 --- a/tests-integration/tests/once_map_test/traits.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::once::OnceMap; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::>(); - assert_unpin::>(); -} diff --git a/tests-integration/tests/once_test/main.rs b/tests-integration/tests/once_test.rs similarity index 99% rename from tests-integration/tests/once_test/main.rs rename to tests-integration/tests/once_test.rs index 7d8e493b..622f746e 100644 --- a/tests-integration/tests/once_test/main.rs +++ b/tests-integration/tests/once_test.rs @@ -22,8 +22,6 @@ use std::sync::atomic::Ordering; use asyncband::once::Once; use tests_integration::poll_once; -mod traits; - #[tokio::test] async fn call_once_runs_only_one_initializer() { let once = Once::new(); diff --git a/tests-integration/tests/once_test/traits.rs b/tests-integration/tests/once_test/traits.rs deleted file mode 100644 index 77daeb2b..00000000 --- a/tests-integration/tests/once_test/traits.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::once::Once; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::(); - assert_unpin::(); -} diff --git a/tests-integration/tests/oneshot_test/main.rs b/tests-integration/tests/oneshot_test/main.rs index a015f522..bd3eba01 100644 --- a/tests-integration/tests/oneshot_test/main.rs +++ b/tests-integration/tests/oneshot_test/main.rs @@ -40,7 +40,6 @@ use self::support::spawn_named; use self::support::spin_until; mod support; -mod traits; #[test] fn send_before_await() { diff --git a/tests-integration/tests/oneshot_test/traits.rs b/tests-integration/tests/oneshot_test/traits.rs deleted file mode 100644 index 07962dbe..00000000 --- a/tests-integration/tests/oneshot_test/traits.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::oneshot; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_send() {} - fn assert_unpin() {} - - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_send::>(); - assert_send::>(); -} diff --git a/tests-integration/tests/phaser_test/main.rs b/tests-integration/tests/phaser_test.rs similarity index 99% rename from tests-integration/tests/phaser_test/main.rs rename to tests-integration/tests/phaser_test.rs index 6caeb9d8..615672c3 100644 --- a/tests-integration/tests/phaser_test/main.rs +++ b/tests-integration/tests/phaser_test.rs @@ -28,8 +28,6 @@ use tests_integration::poll_once; use tests_integration::poll_with; use tests_integration::waker_on_drop; -mod traits; - #[test] fn batch_registration_joins_one_observed_phase() { let phaser = Phaser::new(); diff --git a/tests-integration/tests/phaser_test/traits.rs b/tests-integration/tests/phaser_test/traits.rs deleted file mode 100644 index 5b88e39c..00000000 --- a/tests-integration/tests/phaser_test/traits.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::phaser::Closed; -use asyncband::phaser::Phaser; -use asyncband::phaser::PhaserParticipant; -use asyncband::phaser::PhaserParticipants; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::(); -} diff --git a/tests-integration/tests/pool_test/main.rs b/tests-integration/tests/pool_test/main.rs index f03283ff..683f0f1a 100644 --- a/tests-integration/tests/pool_test/main.rs +++ b/tests-integration/tests/pool_test/main.rs @@ -20,4 +20,3 @@ mod behavior; mod recycle; mod replenish; mod support; -mod traits; diff --git a/tests-integration/tests/pool_test/traits.rs b/tests-integration/tests/pool_test/traits.rs deleted file mode 100644 index a71613e3..00000000 --- a/tests-integration/tests/pool_test/traits.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use std::cell::Cell; - -use asyncband::pool; - -use super::support::Manager; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_send() {} - fn assert_unpin() {} - - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_send::>>(); -} - -#[test] -fn unbounded_manual_manager_traits_do_not_depend_on_the_object() { - fn assert_copy() {} - fn assert_debug() {} - - assert_copy::>(); - assert_debug::>(); -} diff --git a/tests-integration/tests/rwlock_test/main.rs b/tests-integration/tests/rwlock_test.rs similarity index 99% rename from tests-integration/tests/rwlock_test/main.rs rename to tests-integration/tests/rwlock_test.rs index f022f11b..1f95bd6a 100644 --- a/tests-integration/tests/rwlock_test/main.rs +++ b/tests-integration/tests/rwlock_test.rs @@ -23,9 +23,6 @@ use tests_integration::poll_once; use tokio_test::assert_pending; use tokio_test::assert_ready; -mod traits; -mod unsafe_paths; - #[test] fn try_methods_respect_held_guards() { let rwlock = Arc::new(RwLock::new(42)); diff --git a/tests-integration/tests/rwlock_test/traits.rs b/tests-integration/tests/rwlock_test/traits.rs deleted file mode 100644 index c2c8c760..00000000 --- a/tests-integration/tests/rwlock_test/traits.rs +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::rwlock::OwnedRwLockReadGuard; -use asyncband::rwlock::RwLock; -use asyncband::rwlock::RwLockReadGuard; -use asyncband::rwlock::RwLockWriteGuard; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_send() {} - fn assert_unpin() {} - - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_send::>>(); -} diff --git a/tests-integration/tests/semaphore_test/main.rs b/tests-integration/tests/semaphore_test.rs similarity index 99% rename from tests-integration/tests/semaphore_test/main.rs rename to tests-integration/tests/semaphore_test.rs index 512e0625..a3f4f675 100644 --- a/tests-integration/tests/semaphore_test/main.rs +++ b/tests-integration/tests/semaphore_test.rs @@ -28,8 +28,6 @@ use tests_integration::WakeCounter; use tests_integration::expect_ready; use tests_integration::poll_with; -mod traits; - #[test] fn no_permits() { // this should not panic diff --git a/tests-integration/tests/semaphore_test/traits.rs b/tests-integration/tests/semaphore_test/traits.rs deleted file mode 100644 index ac21c216..00000000 --- a/tests-integration/tests/semaphore_test/traits.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::semaphore::Semaphore; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::(); - assert_unpin::(); -} diff --git a/tests-integration/tests/shutdown_test/main.rs b/tests-integration/tests/shutdown_test.rs similarity index 99% rename from tests-integration/tests/shutdown_test/main.rs rename to tests-integration/tests/shutdown_test.rs index 86b410bd..db36080b 100644 --- a/tests-integration/tests/shutdown_test/main.rs +++ b/tests-integration/tests/shutdown_test.rs @@ -23,8 +23,6 @@ use asyncband::shutdown::*; use tests_integration::poll_once; use tests_integration::test_runtime; -mod traits; - #[test] fn test_single_pair() { let (shutdown, guard) = new(); diff --git a/tests-integration/tests/shutdown_test/traits.rs b/tests-integration/tests/shutdown_test/traits.rs deleted file mode 100644 index b6e5bf34..00000000 --- a/tests-integration/tests/shutdown_test/traits.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::shutdown::Shutdown; -use asyncband::shutdown::ShutdownGuard; -use asyncband::shutdown::ShutdownWatch; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_send_and_sync::(); - assert_unpin::(); - assert_unpin::(); - assert_unpin::(); -} diff --git a/tests-integration/tests/singleflight_test/main.rs b/tests-integration/tests/singleflight_test.rs similarity index 99% rename from tests-integration/tests/singleflight_test/main.rs rename to tests-integration/tests/singleflight_test.rs index 23ccf5e6..87008f36 100644 --- a/tests-integration/tests/singleflight_test/main.rs +++ b/tests-integration/tests/singleflight_test.rs @@ -21,8 +21,6 @@ use std::sync::atomic::Ordering; use asyncband::singleflight::Group; use tests_integration::poll_once; -mod traits; - #[tokio::test] async fn supports_non_clone_key() { #[derive(Hash, PartialEq, Eq)] diff --git a/tests-integration/tests/singleflight_test/traits.rs b/tests-integration/tests/singleflight_test/traits.rs deleted file mode 100644 index c5d38548..00000000 --- a/tests-integration/tests/singleflight_test/traits.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::singleflight; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::>(); - assert_unpin::>(); -} diff --git a/tests-integration/tests/traits_test.rs b/tests-integration/tests/traits_test.rs new file mode 100644 index 00000000..26205e34 --- /dev/null +++ b/tests-integration/tests/traits_test.rs @@ -0,0 +1,275 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +use std::cell::Cell; +use std::marker::PhantomPinned; +use std::panic::RefUnwindSafe; +use std::panic::UnwindSafe; + +use asyncband::barrier::Barrier; +use asyncband::broadcast; +use asyncband::completion; +use asyncband::condvar::Condvar; +use asyncband::event::AutoResetEvent; +use asyncband::event::ManualResetEvent; +use asyncband::latch::Latch; +use asyncband::mpmc; +use asyncband::mpsc; +use asyncband::mutex::Mutex; +use asyncband::mutex::MutexGuard; +use asyncband::once::LazyCell; +use asyncband::once::Once; +use asyncband::once::OnceCell; +use asyncband::once::OnceMap; +use asyncband::oneshot; +use asyncband::phaser::Closed; +use asyncband::phaser::Phaser; +use asyncband::phaser::PhaserParticipant; +use asyncband::phaser::PhaserParticipants; +use asyncband::pool; +use asyncband::pool::ManageObject; +use asyncband::pool::ObjectStatus; +use asyncband::rwlock::OwnedRwLockReadGuard; +use asyncband::rwlock::RwLock; +use asyncband::rwlock::RwLockReadGuard; +use asyncband::rwlock::RwLockWriteGuard; +use asyncband::semaphore::Semaphore; +use asyncband::shutdown::Shutdown; +use asyncband::shutdown::ShutdownGuard; +use asyncband::shutdown::ShutdownWatch; +use asyncband::singleflight; +use asyncband::waitgroup::Wait; +use asyncband::waitgroup::WaitGroup; +use asyncband::watch; + +struct PoolManager; + +impl ManageObject for PoolManager { + type Object = i64; + type Error = std::convert::Infallible; + + async fn create(&self) -> Result { + Ok(0) + } + + async fn is_recyclable( + &self, + _object: &mut Self::Object, + _status: &ObjectStatus, + ) -> Result<(), Self::Error> { + Ok(()) + } +} + +#[test] +fn public_types_are_send_and_sync() { + fn assert_send_and_sync() {} + + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::>>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::(); + assert_send_and_sync::>>(); + assert_send_and_sync::(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>>(); + assert_send_and_sync::>>(); + assert_send_and_sync::>>(); + assert_send_and_sync::>>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::>(); + assert_send_and_sync::(); +} + +#[test] +fn movable_public_types_are_send() { + fn assert_send() {} + fn assert_send_value(_: T) {} + + assert_send::>>(); + assert_send::>(); + assert_send::>(); + assert_send::>>(); + + let (_tx, mut rx) = watch::channel(0); + assert_send_value(rx.changed()); + assert_send_value(rx.recv()); + + let (_completer, completion) = completion::new::(); + assert_send_value(completion.wait()); + + let (unbounded_sender, unbounded_receiver) = mpmc::unbounded::>(); + assert_send_value(unbounded_receiver.recv()); + drop(unbounded_sender); + + let (bounded_sender, bounded_receiver) = mpmc::bounded::>(1); + assert_send_value(bounded_sender.send(Cell::new(0))); + assert_send_value(bounded_receiver.recv()); +} + +#[test] +fn public_types_are_unpin() { + fn assert_unpin() {} + + assert_unpin::(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::>>(); + assert_unpin::(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::>(); + assert_unpin::(); +} + +#[test] +fn mpsc_endpoints_keep_legacy_traits_regardless_of_payload() { + fn assert_send() {} + fn assert_sync() {} + fn assert_unpin() {} + fn assert_unwind_safe() {} + fn assert_ref_unwind_safe() {} + + macro_rules! assert_endpoint_traits { + ($endpoint:ident, $payload:ty) => { + assert_send::>(); + assert_sync::>(); + assert_unpin::>(); + assert_unwind_safe::>(); + assert_ref_unwind_safe::>(); + }; + } + + macro_rules! assert_payload_traits { + ($endpoint:ident) => { + assert_endpoint_traits!($endpoint, i32); + assert_endpoint_traits!($endpoint, Cell); + assert_endpoint_traits!($endpoint, &'static mut i32); + assert_endpoint_traits!($endpoint, PhantomPinned); + }; + } + + // Four endpoint types × four payloads × five traits = 80 compile-time assertions. + assert_payload_traits!(BoundedSender); + assert_payload_traits!(BoundedReceiver); + assert_payload_traits!(UnboundedSender); + assert_payload_traits!(UnboundedReceiver); +} + +#[test] +fn unbounded_manual_manager_traits_do_not_depend_on_the_object() { + fn assert_copy() {} + fn assert_debug() {} + + assert_copy::>(); + assert_debug::>(); +} diff --git a/tests-integration/tests/rwlock_test/unsafe_paths.rs b/tests-integration/tests/unsafe_paths_test.rs similarity index 53% rename from tests-integration/tests/rwlock_test/unsafe_paths.rs rename to tests-integration/tests/unsafe_paths_test.rs index b7a643eb..3a7ace5e 100644 --- a/tests-integration/tests/rwlock_test/unsafe_paths.rs +++ b/tests-integration/tests/unsafe_paths_test.rs @@ -15,8 +15,22 @@ // specific language governing permissions and limitations // under the License. +use std::cell::Cell; +use std::future::Future; +use std::marker::PhantomPinned; +use std::pin::Pin; +use std::pin::pin; +use std::ptr; use std::sync::Arc; +use std::task::Context; +use std::task::Poll; +use asyncband::mutex::MappedMutexGuard; +use asyncband::mutex::Mutex; +use asyncband::mutex::MutexGuard; +use asyncband::mutex::OwnedMappedMutexGuard; +use asyncband::mutex::OwnedMutexGuard; +use asyncband::once::LazyCell; use asyncband::rwlock::MappedRwLockReadGuard; use asyncband::rwlock::MappedRwLockWriteGuard; use asyncband::rwlock::OwnedMappedRwLockReadGuard; @@ -26,6 +40,34 @@ use asyncband::rwlock::OwnedRwLockWriteGuard; use asyncband::rwlock::RwLock; use asyncband::rwlock::RwLockReadGuard; use asyncband::rwlock::RwLockWriteGuard; +use tests_integration::poll_once; + +#[test] +fn mapped_mutex_guards_preserve_lock_ownership() { + let mutex = Mutex::new((vec![1, 2], 3)); + let guard = mutex.try_lock().unwrap(); + let mapped = MutexGuard::map(guard, |value| &mut value.0); + let mut mapped = MappedMutexGuard::map(mapped, |values| &mut values[1]); + assert!(mutex.try_lock().is_none()); + *mapped = 4; + drop(mapped); + assert_eq!(mutex.into_inner(), (vec![1, 4], 3)); + + let mutex = Arc::new(Mutex::new(Some(vec![5, 6]))); + let weak = Arc::downgrade(&mutex); + let guard = mutex.clone().try_lock_owned().unwrap(); + let mapped = OwnedMutexGuard::filter_map(guard, Option::as_mut).unwrap(); + let mut mapped = OwnedMappedMutexGuard::map(mapped, |values| &mut values[0]); + assert!(mutex.try_lock().is_none()); + *mapped = 7; + drop(mapped); + let guard = mutex.try_lock().unwrap(); + assert_eq!(guard.as_deref(), Some([7, 6].as_slice())); + drop(guard); + + drop(mutex); + assert!(weak.upgrade().is_none()); +} #[derive(Debug, Eq, PartialEq)] struct Data { @@ -79,3 +121,48 @@ fn mapped_rwlock_guards_preserve_lock_ownership() { drop(lock); assert!(weak.upgrade().is_none()); } + +struct AddressSensitiveFuture { + address: Cell<*const Self>, + _pin: PhantomPinned, +} + +impl AddressSensitiveFuture { + fn new() -> Self { + Self { + address: Cell::new(ptr::null()), + _pin: PhantomPinned, + } + } +} + +impl Future for AddressSensitiveFuture { + type Output = i32; + + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + let this = self.as_ref().get_ref(); + let current = ptr::from_ref(this); + let first = this.address.get(); + if first.is_null() { + this.address.set(current); + Poll::Pending + } else { + assert!(ptr::eq(first, current)); + Poll::Ready(42) + } + } +} + +#[test] +fn lazy_cell_resumes_a_pinned_attempt_in_place() { + let lazy = LazyCell::from_future(AddressSensitiveFuture::new()); + let lazy = pin!(lazy); + + { + let mut force = pin!(LazyCell::force_pin(lazy.as_ref())); + assert!(poll_once(force.as_mut()).is_pending()); + } + + let mut force = pin!(LazyCell::force_pin(lazy.as_ref())); + assert_eq!(poll_once(force.as_mut()), Poll::Ready(&42)); +} diff --git a/tests-integration/tests/waitgroup_test/main.rs b/tests-integration/tests/waitgroup_test.rs similarity index 99% rename from tests-integration/tests/waitgroup_test/main.rs rename to tests-integration/tests/waitgroup_test.rs index c67fb5f6..c78c6b45 100644 --- a/tests-integration/tests/waitgroup_test/main.rs +++ b/tests-integration/tests/waitgroup_test.rs @@ -23,8 +23,6 @@ use asyncband::waitgroup::WaitGroup; use tests_integration::WakeCounter; use tests_integration::poll_once; -mod traits; - #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn waits_for_all_worker_handles() { let wg = WaitGroup::new(); diff --git a/tests-integration/tests/waitgroup_test/traits.rs b/tests-integration/tests/waitgroup_test/traits.rs deleted file mode 100644 index b42a76ec..00000000 --- a/tests-integration/tests/waitgroup_test/traits.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::waitgroup::Wait; -use asyncband::waitgroup::WaitGroup; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - - assert_send_and_sync::(); - assert_unpin::(); - assert_unpin::(); -} diff --git a/tests-integration/tests/watch_test/main.rs b/tests-integration/tests/watch_test.rs similarity index 99% rename from tests-integration/tests/watch_test/main.rs rename to tests-integration/tests/watch_test.rs index d8d66dd6..2636e77f 100644 --- a/tests-integration/tests/watch_test/main.rs +++ b/tests-integration/tests/watch_test.rs @@ -30,8 +30,6 @@ use tests_integration::poll_with; use tests_integration::waker_on_drop; use tests_integration::waker_on_wake; -mod traits; - #[derive(Clone)] struct ReentrantDrop(Option>); diff --git a/tests-integration/tests/watch_test/traits.rs b/tests-integration/tests/watch_test/traits.rs deleted file mode 100644 index 0f286a18..00000000 --- a/tests-integration/tests/watch_test/traits.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -use asyncband::watch; - -#[test] -fn public_types_keep_their_auto_traits() { - fn assert_send_and_sync() {} - fn assert_unpin() {} - fn assert_send_value(_: T) {} - - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::>(); - assert_send_and_sync::(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::>(); - assert_unpin::(); - - let (_tx, mut rx) = watch::channel(0); - assert_send_value(rx.changed()); - assert_send_value(rx.recv()); -} diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 5a799464..6ae91be7 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -116,12 +116,10 @@ impl CommandMiri { "tests-integration", &["--test", "oneshot_test"], )); - for target in ["mutex_test", "rwlock_test", "lazy_cell_test"] { - run_command(make_miri_cmd( - "tests-integration", - &["--test", target, "unsafe_paths::"], - )); - } + run_command(make_miri_cmd( + "tests-integration", + &["--test", "unsafe_paths_test"], + )); run_command(make_miri_cmd("tests-integration", &["--test", "mpsc_test"])); run_command(make_miri_cmd("tests-integration", &["--test", "mpmc_test"])); run_command(make_miri_cmd("tests-integration", &["--test", "spmc_test"]));