npnc/
lib.rs

1// Copyright 2017 Kyle Mayes
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Lock-free queues.
16//!
17//! # Examples
18//!
19//! ## Bounded SPSC
20//!
21//! ```
22//! extern crate npnc;
23//!
24//! use std::thread;
25//!
26//! use npnc::bounded::spsc;
27//!
28//! fn main() {
29//!     let (producer, consumer) = spsc::channel(64);
30//!
31//!     // Producer
32//!     let b = thread::spawn(move || {
33//!         for index in 0..32 {
34//!             producer.produce(index).unwrap();
35//!         }
36//!     });
37//!
38//!     // Consumer
39//!     let a = thread::spawn(move || {
40//!         loop {
41//!             if let Ok(item) = consumer.consume() {
42//!                 println!("{}", item);
43//!                 if item == 31 {
44//!                     break;
45//!                 }
46//!             }
47//!         }
48//!     });
49//!
50//!     a.join().unwrap();
51//!     b.join().unwrap();
52//! }
53//! ```
54
55#![cfg_attr(feature="valgrind", feature(alloc_system))]
56
57#![warn(missing_copy_implementations, missing_debug_implementations, missing_docs)]
58
59#[cfg(feature="valgrind")]
60extern crate alloc_system;
61
62extern crate hazard;
63
64use std::error;
65use std::fmt;
66
67#[macro_use]
68mod utility;
69mod buffer;
70pub mod bounded;
71pub mod unbounded;
72
73/// The number of pointers that fit in a 128 byte cacheline.
74#[cfg(target_pointer_width="32")]
75const POINTERS: usize = 32;
76#[cfg(target_pointer_width="64")]
77const POINTERS: usize = 16;
78
79//================================================
80// Enums
81//================================================
82
83// ConsumeError __________________________________
84
85/// Indicates the reason a `consume` operation could not return an item.
86#[derive(Copy, Clone, Debug, PartialEq, Eq)]
87pub enum ConsumeError {
88    /// The queue was empty and had no remaining producers.
89    Disconnected,
90    /// The queue was empty.
91    Empty,
92}
93
94impl error::Error for ConsumeError {
95    fn description(&self) -> &str {
96        match *self {
97            ConsumeError::Disconnected => "the queue was empty and had no remaining producers",
98            ConsumeError::Empty => "the queue was empty",
99        }
100    }
101}
102
103impl fmt::Display for ConsumeError {
104    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
105        write!(formatter, "{}", error::Error::description(self))
106    }
107}
108
109// ProduceError __________________________________
110
111/// Indicates the reason a `produce` operation rejected an item.
112#[derive(Copy, Clone, PartialEq, Eq)]
113pub enum ProduceError<T> {
114    /// The queue had no remaining consumers.
115    Disconnected(T),
116    /// The queue was full.
117    Full(T),
118}
119
120impl<T> ProduceError<T> {
121    //- Consumers --------------------------------
122
123    /// Returns the rejected item.
124    pub fn item(self) -> T {
125        match self { ProduceError::Disconnected(item) | ProduceError::Full(item) => item }
126    }
127}
128
129impl<T> error::Error for ProduceError<T> {
130    fn description(&self) -> &str {
131        match *self {
132            ProduceError::Disconnected(_) => "the queue had no remaining consumers",
133            ProduceError::Full(_) => "the queue was full",
134        }
135    }
136}
137
138impl<T> fmt::Debug for ProduceError<T> {
139    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
140        match *self {
141            ProduceError::Disconnected(_) => write!(formatter, "ProduceError::Disconnected(..)"),
142            ProduceError::Full(_) => write!(formatter, "ProduceError::Full(..)"),
143        }
144    }
145}
146
147impl<T> fmt::Display for ProduceError<T> {
148    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
149        write!(formatter, "{}", error::Error::description(self))
150    }
151}