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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//! A task queue where the processing of tasks can generate additional subtasks.
//!
//! This module implements a stream where the consumer of the stream can request
//! additional items to be added to the stream. An example where this is useful
//! is fetching a package including all the transitive dependencies: we start
//! with a stream that just yields the package we want to fetch. The consumer can
//! then fetch a package and add all dependencies of that package to the stream,
//! adding them to the set of packages that need to be fetched.
//!
//! The data structure is called a work set because it allows assigning a key to
//! each item to avoid duplicates. A new item will only be added if no prior item
//! had the same key.
//!
//! # Example
//!
//! ```rust
//! extern crate futures;
//! extern crate nix_index;
//!
//! use futures::{Stream, stream::StreamExt};
//! use nix_index::workset::{WorkSet};
//! use std::iter::{self, FromIterator};
//!
//! #[derive(Clone)]
//! struct Package {
//! name: String,
//! dependencies: Vec<Package>,
//! }
//!
//! fn main() {
//! // set up some data
//! let pkgA = Package { name: "a".to_string(), dependencies: vec![] };
//! let pkgB = Package { name: "b".to_string(), dependencies: vec![] };
//! let pkgC = Package { name: "c".to_string(), dependencies: vec![pkgA.clone(), pkgB] };
//! let pkgD = Package { name: "d".to_string(), dependencies: vec![pkgA, pkgC] };
//!
//! // construct a workset that has `pkgD` as initial item.
//! let workset = WorkSet::from_iter(iter::once((pkgD.name.clone(), pkgD)));
//!
//! // fetch the names of all transitive dependencies of `pkgD`. In real cases,
//! // this would probably perform some network requests or other IO with futures.
//! let all_packages = workset.map(|(mut handle, pkg)| {
//! let Package { name, dependencies } = pkg;
//! // add all dependencies to the workset
//! for pkg in dependencies {
//! handle.add_work(pkg.name.clone(), pkg);
//! }
//! name
//! });
//!
//! // all_packages is now a stream of all the names of the transitive dependencies of pkgD
//! // and pkgD itself
//! }
//! ```
use RefCell;
use HashSet;
use Hash;
use FromIterator;
use Pin;
use ;
use ;
use Stream;
use IndexMap;
/// This structure holds the internal state of our queue.
/// A queue where the consumer can request new items to be added to the queue.
///
/// To construct a new instance of this type, use `WorkSet::from_iter`.
///
/// The queue terminates if there is no work left that need processing and all
/// `WorkSetHandle`s have been dropped (if there are `WorkSetHandle`s alive
/// then it is still possible to call `add_work`, so the stream cannot end even
/// if there is no work item available at the current time).
/// A work set handle allows you to add new items to the queue.
///
/// As long as there are still `WorkSetHandle`s alive, the queue
/// will not terminate.
/// An observer for `WorkSet` that provides status information
/// about the queue.
///
/// Note that this trait is not dependent on the type of items or keys
/// in the work set, as it only provides meta information about the queue.
/// A work set watch is any implementation of a `WorkSetObserver`.
///
/// The watch not prevent the queue from terminating. If the queue has already
/// terminated, the number of remaining items will be zero.
pub type WorkSetWatch = ;
/// This is a concrete implementation of a `WorkSetObserver`.
///
/// The indirection through the `WorkSetObserver` trait and `WorkSetWatch` type is
/// necessary to allow hiding the concrete types `K` and `V` of the queue.
/// Hiding the concrete types makes the interface much nicer.
/// A work set implements the `Stream` trait. The stream will produce the work
/// that still needs processing. Along with every work item it also provides
/// a handle to the queue that allows the consumer to add more items to the queue.
///
/// The stream ends if the queue terminates, see the documentation of `WorkSet`
/// for when exactly that happens.