1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
//! [![crates.io version](https://img.shields.io/crates/v/safina-sync.svg)](https://crates.io/crates/safina-sync)
//! [![license: Apache 2.0](https://gitlab.com/leonhard-llc/safina-rs/-/raw/main/license-apache-2.0.svg)](http://www.apache.org/licenses/LICENSE-2.0)
//! [![unsafe forbidden](https://gitlab.com/leonhard-llc/safina-rs/-/raw/main/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/)
//! [![pipeline status](https://gitlab.com/leonhard-llc/safina-rs/badges/main/pipeline.svg)](https://gitlab.com/leonhard-llc/safina-rs/-/pipelines)
//!
//! This is a safe Rust library for sharing or sending data between async tasks.
//!
//! It is part of [`safina`](https://crates.io/crates/safina), a safe async runtime.
//!
//! # Features
//! - `forbid(unsafe_code)`
//! - Depends only on `std`
//! - Good test coverage (100%)
//! - Works with [`safina-executor`](https://crates.io/crates/safina-executor) or any async executor
//!
//! # Limitations
//! - Allocates
//!
//! # Documentation
//! <https://docs.rs/safina-sync>
//!
//! # Examples
//! ```rust
//! use std::sync::Arc;
//! use safina_async_test::async_test;
//! use safina_sync::Mutex;
//! # async fn some_async_fn() {}
//! # fn get_shared_data() -> Arc<Mutex<u32>> {
//! #     Arc::new(Mutex::new(0))
//! # }
//! # #[async_test]
//! # async fn test1() {
//! #     let addr = String::new();
//! let shared_counter: Arc<Mutex<u32>> = get_shared_data();
//! {
//!     let mut counter_guard = shared_counter.lock().await;
//!     *counter_guard += 1;
//!     // some_async_fn().await; // Cannot await while holding a MutexGuard.
//! }
//! some_async_fn().await; // Await is ok after releasing MutexGuard.
//! # }
//! ```
//!
//! # Alternatives
//! - [async-lock](https://crates.io/crates/async-lock)
//!   - Contains a little `unsafe` code
//! - [futures-locks](https://crates.io/crates/futures-locks)
//!   - Contains a little `unsafe` code
//! - [futures-util](https://crates.io/crates/futures-util)
//!   - Very popular
//!   - Full of `unsafe`
//! - [tokio-sync](https://crates.io/crates/tokio-sync)
//!   - Very popular
//!   - Fast
//!   - Internally incredibly complicated
//!   - Full of `unsafe`
//!
//! # Changelog
//! - v0.1.3 - Fix Promise type parameter
//! - v0.1.2 - Add Promise
//! - v0.1.1 - Improve Mutex performance when there are many waiters
//! - v0.1.0 - First published version
//!
//! # TO DO
//! - DONE - Implement `Mutex` with tests & docs
//! - DONE - Publish on crates.io
//! - DONE - Add `Promise`
//! - Add `Barrier`
//! - Add `RwLock`
//! - Add `WaitableBool`
//! - Add `Channel` (single receiver)
//! - Add `UnboundedChannel`
//! - Add `WaitableQueue` (multiple receivers)
//! - Add `UnboundedWaitableQueue`
//! - Add `Topic` (copies message to every receiver)
//!
//! # Release Process
//! 1. Edit `Cargo.toml` and bump version number.
//! 1. Run `./release.sh`
#![forbid(unsafe_code)]

mod mutex;
pub use mutex::*;

mod promise;
pub use promise::*;

#[cfg(test)]
mod tests {
    use core::ops::Range;
    use core::time::Duration;
    use std::time::Instant;

    pub fn expect_elapsed(before: Instant, range_ms: Range<u64>) {
        if range_ms.is_empty() {
            panic!("invalid range {:?}", range_ms)
        }
        let elapsed = before.elapsed();
        let duration_range =
            Duration::from_millis(range_ms.start)..Duration::from_millis(range_ms.end);
        if !duration_range.contains(&elapsed) {
            panic!("{:?} elapsed, out of range {:?}", elapsed, duration_range);
        }
    }
}