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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! Double Mapped Circular Buffer
//!
//! - Thread-safe.
//! - Supports multiple readers.
//! - Generic over the item type.
//! - Provides access to all items (not n-1).
//! - Supports Linux, macOS, Windows, and Android.
//! - [Sync](sync), [async](asynchronous), [non-blocking](nonblocking), and [lock-free](lockfree) implementations.
//! - [Generic](crate::generic) variant that allows specifying custom [Notifiers](crate::Notifier) to ease integration.
//! - Underlying data structure (i.e., [DoubleMappedBuffer](double_mapped_buffer::DoubleMappedBuffer)) is exported to allow custom implementations.
//!
//! # Quick Start
//!
//! ```
//! # #[cfg(feature = "sync")] {
//! # use vmcircbuffer::sync;
//! # use vmcircbuffer::generic::CircularError;
//! let mut w = sync::Circular::new::<u32>().unwrap();
//! let mut r = w.add_reader();
//!
//! // delay producing by 1 sec
//! let now = std::time::Instant::now();
//! let delay = std::time::Duration::from_millis(1000);
//!
//! // producer thread
//! std::thread::spawn(move || {
//! std::thread::sleep(delay);
//! let w_buff = w.slice();
//! for v in w_buff.iter_mut() {
//! *v = 23;
//! }
//! let l = w_buff.len();
//! w.produce(l);
//! });
//!
//! // blocks until data becomes available
//! let r_buff = r.slice().unwrap();
//! assert!(now.elapsed() > delay);
//! for v in r_buff {
//! assert_eq!(*v, 23);
//! }
//! let l = r_buff.len();
//! r.consume(l);
//! # }
//! ```
//!
//! Enable at least one implementation feature such as `sync`, `async`, `nonblocking`, or `lockfree`.
//! The crate does not enable any runtime implementation by default.
//!
//! # Commonalities
//!
//! There are some commonalities between the implementations:
//! - The `Circular` struct is a factory to create the `Writer`.
//! - If there are no `Reader`s, the `Writer` will not block but continuously overwrite the buffer.
//! - The `Writer` has an `add_reader()` method to add `Reader`s.
//! - When the `Writer` is dropped, the `Reader` can read the remaining items. Afterwards, the `slice()` will return `None`.
//!
//! # Details
//!
//! This circular buffer implementation maps the underlying buffer twice,
//! back-to-back into the virtual address space of the process. This arrangement
//! allows the circular buffer to present the available data sequentially,
//! (i.e., as a slice) without having to worry about wrapping.
//!
//! On Unix-based systems, the mapping is setup with a temporary file. This file
//! is created in the folder, determined through [std::env::temp_dir], which
//! considers environment variables. This can be used, if the standard paths are
//! not present of not writable on the platform.
//!
//! # Features
//!
//! The `async`, `nonblocking`, `sync`, and `lockfree` feature flags enable the
//! corresponding implementations. No runtime implementation is enabled by default.
//! In addition, the `generic` flag controls the generic implementation, while
//! [DoubleMappedBuffer](double_mapped_buffer::DoubleMappedBuffer) is always available.
/// A custom notifier can be used to trigger arbitrary mechanism to signal to a
/// reader or writer that data or buffer space is available. This could be a
/// write to an sync/async channel or a condition variable.
/// Custom metadata to annotate items.
/// Void implementation for the [Metadata] trait for buffers that don't use metadata.
;