blob: 65765463200a1816886d6dfedee937f3f6a8f3fd [file] [log] [blame]
// Copyright 2018 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! This library provides type-safe and fully-featured `Mutex` and `RwLock`
//! types which wrap a simple raw mutex or rwlock type. This has several
//! benefits: not only does it eliminate a large portion of the work in
//! implementing custom lock types, it also allows users to write code which is
//! generic with regards to different lock implementations.
//!
//! Basic usage of this crate is very straightforward:
//!
//! 1. Create a raw lock type. This should only contain the lock state, not any
//! data protected by the lock.
//! 2. Implement the `RawMutex` trait for your custom lock type.
//! 3. Export your mutex as a type alias for `lock_api::Mutex`, and
//! your mutex guard as a type alias for `lock_api::MutexGuard`.
//! See the [example](#example) below for details.
//!
//! This process is similar for RwLocks, except that two guards need to be
//! exported instead of one. (Or 3 guards if your type supports upgradable read
//! locks, see [extension traits](#extension-traits) below for details)
//!
//! # Example
//!
//! ```
//! use lock_api::{RawMutex, Mutex, GuardSend};
//! use std::sync::atomic::{AtomicBool, Ordering};
//!
//! // 1. Define our raw lock type
//! pub struct RawSpinlock(AtomicBool);
//!
//! // 2. Implement RawMutex for this type
//! unsafe impl RawMutex for RawSpinlock {
//! const INIT: RawSpinlock = RawSpinlock(AtomicBool::new(false));
//!
//! // A spinlock guard can be sent to another thread and unlocked there
//! type GuardMarker = GuardSend;
//!
//! fn lock(&self) {
//! // Note: This isn't the best way of implementing a spinlock, but it
//! // suffices for the sake of this example.
//! while !self.try_lock() {}
//! }
//!
//! fn try_lock(&self) -> bool {
//! self.0
//! .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
//! .is_ok()
//! }
//!
//! fn unlock(&self) {
//! self.0.store(false, Ordering::Release);
//! }
//! }
//!
//! // 3. Export the wrappers. This are the types that your users will actually use.
//! pub type Spinlock<T> = lock_api::Mutex<RawSpinlock, T>;
//! pub type SpinlockGuard<'a, T> = lock_api::MutexGuard<'a, RawSpinlock, T>;
//! ```
//!
//! # Extension traits
//!
//! In addition to basic locking & unlocking functionality, you have the option
//! of exposing additional functionality in your lock types by implementing
//! additional traits for it. Examples of extension features include:
//!
//! - Fair unlocking (`RawMutexFair`, `RawRwLockFair`)
//! - Lock timeouts (`RawMutexTimed`, `RawRwLockTimed`)
//! - Downgradable write locks (`RawRwLockDowngradable`)
//! - Recursive read locks (`RawRwLockRecursive`)
//! - Upgradable read locks (`RawRwLockUpgrade`)
//!
//! The `Mutex` and `RwLock` wrappers will automatically expose this additional
//! functionality if the raw lock type implements these extension traits.
//!
//! # Cargo features
//!
//! This crate supports two cargo features:
//!
//! - `owning_ref`: Allows your lock types to be used with the `owning_ref` crate.
//! - `nightly`: Enables nightly-only features. At the moment the only such
//! feature is `const fn` constructors for lock types.
#![no_std]
#![warn(missing_docs)]
#![warn(rust_2018_idioms)]
#![cfg_attr(feature = "nightly", feature(const_fn))]
#[macro_use]
extern crate scopeguard;
/// Marker type which indicates that the Guard type for a lock is `Send`.
pub struct GuardSend(());
/// Marker type which indicates that the Guard type for a lock is not `Send`.
pub struct GuardNoSend(*mut ());
mod mutex;
pub use crate::mutex::*;
mod remutex;
pub use crate::remutex::*;
mod rwlock;
pub use crate::rwlock::*;