1use std::cmp;
9use std::fmt;
10use std::sync::atomic::AtomicU32;
11use std::sync::atomic::AtomicU64;
12use std::sync::atomic::Ordering::Acquire;
13use std::sync::atomic::Ordering::Relaxed;
14use std::sync::atomic::Ordering::Release;
15use std::sync::Arc;
16
17use bitflags::bitflags;
18
19use crate::ops::DagAlgorithm;
20use crate::ops::IdConvert;
21use crate::Id;
22use crate::VerLink;
23
24bitflags! {
25 pub struct Flags: u32 {
26 const FULL = 0x1;
28
29 const EMPTY = 0x2;
31
32 const ID_DESC = 0x4;
34
35 const ID_ASC = 0x8;
37
38 const TOPO_DESC = 0x10;
40
41 const HAS_MIN_ID = 0x20;
43
44 const HAS_MAX_ID = 0x40;
46
47 const FILTER = 0x80;
49
50 const ANCESTORS = 0x100;
52 }
53}
54
55#[derive(Default)]
57pub struct Hints {
58 flags: AtomicU32,
60 min_id: AtomicU64,
61 max_id: AtomicU64,
62 id_map: IdMapSnapshot,
63 dag: DagSnapshot,
64}
65
66impl Hints {
67 pub fn new_with_idmap_dag(
68 id_map: impl Into<IdMapSnapshot>,
69 dag: impl Into<DagSnapshot>,
70 ) -> Self {
71 Self {
72 id_map: id_map.into(),
73 dag: dag.into(),
74 ..Default::default()
75 }
76 }
77
78 pub fn new_inherit_idmap_dag(hints: &Self) -> Self {
79 Self::new_with_idmap_dag(hints, hints)
80 }
81
82 pub fn union(hints_list: &[&Self]) -> Self {
86 let default = Self::default();
87 debug_assert!(default.id_map().is_none());
89 let id_map = hints_list
90 .iter()
91 .fold(Some(&default), |opt_a, b| {
92 opt_a.and_then(
93 |a| match a.id_map_version().partial_cmp(&b.id_map_version()) {
94 None => None, Some(cmp::Ordering::Equal) | Some(cmp::Ordering::Greater) => Some(a),
96 Some(cmp::Ordering::Less) => Some(b),
97 },
98 )
99 })
100 .and_then(|a| a.id_map());
101 debug_assert!(default.dag().is_none());
103 let dag = hints_list
104 .iter()
105 .fold(Some(&default), |opt_a, b| {
106 opt_a.and_then(|a| match a.dag_version().partial_cmp(&b.dag_version()) {
107 None => None,
108 Some(cmp::Ordering::Equal) | Some(cmp::Ordering::Greater) => Some(a),
109 Some(cmp::Ordering::Less) => Some(b),
110 })
111 })
112 .and_then(|a| a.dag());
113 Self {
114 id_map: IdMapSnapshot(id_map),
115 dag: DagSnapshot(dag),
116 ..Self::default()
117 }
118 }
119
120 pub fn flags(&self) -> Flags {
121 let flags = self.flags.load(Relaxed);
122 Flags::from_bits_truncate(flags)
123 }
124
125 pub fn contains(&self, flags: Flags) -> bool {
126 self.flags().contains(flags)
127 }
128
129 pub fn min_id(&self) -> Option<Id> {
130 if self.contains(Flags::HAS_MIN_ID) {
131 Some(Id(self.min_id.load(Acquire)))
132 } else {
133 None
134 }
135 }
136
137 pub fn max_id(&self) -> Option<Id> {
138 if self.contains(Flags::HAS_MAX_ID) {
139 Some(Id(self.max_id.load(Acquire)))
140 } else {
141 None
142 }
143 }
144
145 pub fn update_flags_with(&self, func: impl Fn(Flags) -> Flags) -> &Self {
146 let mut flags = func(self.flags());
147 if flags.contains(Flags::EMPTY) {
149 flags.insert(Flags::ID_ASC | Flags::ID_DESC | Flags::TOPO_DESC | Flags::ANCESTORS);
150 }
151 if flags.contains(Flags::FULL) {
152 flags.insert(Flags::ANCESTORS);
153 }
154 self.flags.store(flags.bits(), Relaxed);
155 self
156 }
157
158 pub fn add_flags(&self, flags: Flags) -> &Self {
159 self.update_flags_with(|f| f | flags);
160 self
161 }
162
163 pub fn remove_flags(&self, flags: Flags) -> &Self {
164 self.update_flags_with(|f| f - flags);
165 self
166 }
167
168 pub fn set_min_id(&self, min_id: Id) -> &Self {
169 self.min_id.store(min_id.0, Release);
170 self.add_flags(Flags::HAS_MIN_ID);
171 self
172 }
173
174 pub fn set_max_id(&self, max_id: Id) -> &Self {
175 self.max_id.store(max_id.0, Release);
176 self.add_flags(Flags::HAS_MAX_ID);
177 self
178 }
179
180 pub fn inherit_flags_min_max_id(&self, other: &Hints) -> &Self {
181 self.update_flags_with(|_| other.flags());
182 if let Some(id) = other.min_id() {
183 self.set_min_id(id);
184 }
185 if let Some(id) = other.max_id() {
186 self.set_max_id(id);
187 }
188 self
189 }
190
191 pub fn dag(&self) -> Option<Arc<dyn DagAlgorithm + Send + Sync>> {
192 self.dag.0.clone()
193 }
194
195 pub fn id_map(&self) -> Option<Arc<dyn IdConvert + Send + Sync>> {
196 self.id_map.0.clone()
197 }
198
199 pub fn dag_version(&self) -> Option<&VerLink> {
201 self.dag.0.as_ref().map(|d| d.dag_version())
202 }
203
204 pub fn id_map_version(&self) -> Option<&VerLink> {
206 self.id_map.0.as_ref().map(|d| d.map_version())
207 }
208}
209
210#[derive(Clone, Default)]
211pub struct DagSnapshot(Option<Arc<dyn DagAlgorithm + Send + Sync>>);
212
213impl From<&Hints> for DagSnapshot {
214 fn from(hints: &Hints) -> Self {
215 hints.dag.clone()
216 }
217}
218
219impl From<Arc<dyn DagAlgorithm + Send + Sync>> for DagSnapshot {
220 fn from(dag: Arc<dyn DagAlgorithm + Send + Sync>) -> Self {
221 DagSnapshot(Some(dag))
222 }
223}
224
225#[derive(Clone, Default)]
226pub struct IdMapSnapshot(Option<Arc<dyn IdConvert + Send + Sync>>);
227
228impl From<&Hints> for IdMapSnapshot {
229 fn from(hints: &Hints) -> Self {
230 hints.id_map.clone()
231 }
232}
233
234impl From<Arc<dyn IdConvert + Send + Sync>> for IdMapSnapshot {
235 fn from(dag: Arc<dyn IdConvert + Send + Sync>) -> Self {
236 IdMapSnapshot(Some(dag))
237 }
238}
239
240#[derive(Clone, Default)]
241pub struct DagVersion<'a>(Option<&'a VerLink>);
242
243impl<'a> From<&'a Hints> for DagVersion<'a> {
244 fn from(hints: &'a Hints) -> Self {
245 Self(match &hints.dag.0 {
246 Some(d) => Some(d.dag_version()),
247 None => None,
248 })
249 }
250}
251
252impl<'a> From<&'a VerLink> for DagVersion<'a> {
253 fn from(version: &'a VerLink) -> Self {
254 Self(Some(version))
255 }
256}
257
258#[derive(Clone, Default)]
259pub struct IdMapVersion<'a>(Option<&'a VerLink>);
260
261impl<'a> From<&'a Hints> for IdMapVersion<'a> {
262 fn from(hints: &'a Hints) -> Self {
263 Self(match &hints.id_map.0 {
264 Some(m) => Some(m.map_version()),
265 None => None,
266 })
267 }
268}
269
270impl<'a> From<&'a VerLink> for IdMapVersion<'a> {
271 fn from(version: &'a VerLink) -> Self {
272 Self(Some(version))
273 }
274}
275
276impl Clone for Hints {
277 fn clone(&self) -> Self {
278 Self {
279 flags: AtomicU32::new(self.flags.load(Acquire)),
280 min_id: AtomicU64::new(self.min_id.load(Acquire)),
281 max_id: AtomicU64::new(self.max_id.load(Acquire)),
282 id_map: self.id_map.clone(),
283 dag: self.dag.clone(),
284 }
285 }
286}
287
288impl fmt::Debug for Hints {
289 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
290 write!(
291 f,
292 "Hints({:?}",
293 self.flags() - (Flags::HAS_MIN_ID | Flags::HAS_MAX_ID)
294 )?;
295 match (self.min_id(), self.max_id()) {
296 (Some(min), Some(max)) => write!(f, ", {}..={}", min.0, max.0)?,
297 (Some(min), None) => write!(f, ", {}..", min.0)?,
298 (None, Some(max)) => write!(f, ", ..={}", max.0)?,
299 (None, None) => {}
300 }
301 write!(f, ")")?;
302 Ok(())
303 }
304}
305
306#[cfg(test)]
307#[test]
308fn test_incompatilbe_union() {
309 use crate::tests::dummy_dag::DummyDag;
310 let dag1 = DummyDag::new();
311 let dag2 = DummyDag::new();
312
313 let mut hints1 = Hints::default();
314 hints1.dag = DagSnapshot(Some(dag1.dag_snapshot().unwrap()));
315
316 let mut hints2 = Hints::default();
317 hints2.dag = DagSnapshot(Some(dag2.dag_snapshot().unwrap()));
318
319 assert_eq!(
320 Hints::union(&[&hints1, &hints1]).dag_version(),
321 hints1.dag_version()
322 );
323
324 assert_eq!(Hints::union(&[&hints1, &hints2]).dag_version(), None);
325 assert_eq!(Hints::union(&[&hints2, &hints1]).dag_version(), None);
326 assert_eq!(
327 Hints::union(&[&hints2, &hints1, &hints2]).dag_version(),
328 None
329 );
330}