1use std::cmp::Ordering;
7use std::collections::HashSet;
8use std::hash::{Hash, Hasher};
9use std::ops::Range;
10use std::sync::Arc;
11
12use oxidd_core::error::DuplicateVarName;
13use oxidd_core::util::{AllocResult, Borrowed, DropWith};
14use oxidd_core::{
15 DiagramRules, Edge, HasWorkers, InnerNode, LevelNo, LevelView, Manager, Node, NodeID,
16 ReducedOrNew, VarNo,
17};
18
19#[derive(Debug)]
24pub struct DummyEdge(Arc<()>);
25
26impl PartialEq for DummyEdge {
27 fn eq(&self, other: &Self) -> bool {
28 Arc::ptr_eq(&self.0, &other.0)
29 }
30}
31impl Eq for DummyEdge {}
32impl PartialOrd for DummyEdge {
33 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
34 Some(self.cmp(other))
35 }
36}
37impl Ord for DummyEdge {
38 fn cmp(&self, other: &Self) -> Ordering {
39 Arc::as_ptr(&self.0).cmp(&Arc::as_ptr(&other.0))
40 }
41}
42impl Hash for DummyEdge {
43 fn hash<H: Hasher>(&self, state: &mut H) {
44 Arc::as_ptr(&self.0).hash(state);
45 }
46}
47
48impl Drop for DummyEdge {
49 fn drop(&mut self) {
50 eprintln!(
51 "Edges must not be dropped. Use Manager::drop_edge(). Backtrace:\n{}",
52 std::backtrace::Backtrace::capture()
53 );
54 }
55}
56
57impl DummyEdge {
58 pub fn new() -> Self {
60 DummyEdge(Arc::new(()))
61 }
62
63 pub fn ref_count(&self) -> usize {
66 Arc::strong_count(&self.0)
67 }
68}
69impl Default for DummyEdge {
70 fn default() -> Self {
71 Self::new()
72 }
73}
74
75impl Edge for DummyEdge {
76 type Tag = ();
77
78 fn borrowed(&self) -> Borrowed<'_, Self> {
79 let ptr = Arc::as_ptr(&self.0);
80 Borrowed::new(DummyEdge(unsafe { Arc::from_raw(ptr) }))
81 }
82 fn with_tag(&self, _tag: ()) -> Borrowed<'_, Self> {
83 let ptr = Arc::as_ptr(&self.0);
84 Borrowed::new(DummyEdge(unsafe { Arc::from_raw(ptr) }))
85 }
86 fn with_tag_owned(self, _tag: ()) -> Self {
87 self
88 }
89 fn tag(&self) -> Self::Tag {}
90
91 fn node_id(&self) -> NodeID {
92 Arc::as_ptr(&self.0) as usize
93 }
94}
95
96pub struct DummyManager;
99
100pub struct DummyRules;
102impl DiagramRules<DummyEdge, DummyNode, ()> for DummyRules {
103 type Cofactors<'a> = std::iter::Empty<Borrowed<'a, DummyEdge>>;
104
105 fn reduce<M>(
106 _manager: &M,
107 _level: LevelNo,
108 _children: impl IntoIterator<Item = DummyEdge>,
109 ) -> ReducedOrNew<DummyEdge, DummyNode>
110 where
111 M: Manager<Edge = DummyEdge, InnerNode = DummyNode>,
112 {
113 ReducedOrNew::New(DummyNode, ())
114 }
115
116 fn cofactors(_tag: (), _node: &DummyNode) -> Self::Cofactors<'_> {
117 std::iter::empty()
118 }
119}
120
121unsafe impl Manager for DummyManager {
122 type Edge = DummyEdge;
123 type EdgeTag = ();
124 type InnerNode = DummyNode;
125 type Terminal = ();
126 type TerminalRef<'a> = &'a ();
127 type Rules = DummyRules;
128 type TerminalIterator<'a>
129 = std::iter::Empty<DummyEdge>
130 where
131 Self: 'a;
132 type NodeSet = HashSet<NodeID>;
133 type LevelView<'a>
134 = DummyLevelView
135 where
136 Self: 'a;
137 type LevelIterator<'a>
138 = std::iter::Empty<DummyLevelView>
139 where
140 Self: 'a;
141
142 fn get_node(&self, _edge: &Self::Edge) -> Node<'_, Self> {
143 Node::Inner(&DummyNode)
144 }
145
146 fn clone_edge(&self, edge: &Self::Edge) -> Self::Edge {
147 DummyEdge(edge.0.clone())
148 }
149
150 fn drop_edge(&self, edge: Self::Edge) {
151 let arc = unsafe { std::ptr::read(&edge.0) };
154 std::mem::forget(edge);
155 drop(arc);
156 }
157
158 fn try_remove_node(&self, edge: Self::Edge, _level: LevelNo) -> bool {
159 let arc = unsafe { std::ptr::read(&edge.0) };
162 std::mem::forget(edge);
163 Arc::into_inner(arc).is_some()
164 }
165
166 fn num_inner_nodes(&self) -> usize {
167 0
168 }
169
170 fn num_levels(&self) -> LevelNo {
171 0
172 }
173
174 fn num_named_vars(&self) -> VarNo {
175 0
176 }
177
178 fn add_vars(&mut self, _additional: VarNo) -> Range<VarNo> {
179 unimplemented!()
180 }
181
182 fn add_named_vars<S: Into<String>>(
183 &mut self,
184 _names: impl IntoIterator<Item = S>,
185 ) -> Result<Range<VarNo>, DuplicateVarName> {
186 unimplemented!()
187 }
188
189 fn var_name(&self, _var: VarNo) -> &str {
190 panic!("out of range")
191 }
192
193 fn set_var_name(
194 &mut self,
195 _var: VarNo,
196 _name: impl Into<String>,
197 ) -> Result<(), DuplicateVarName> {
198 panic!("out of range")
199 }
200
201 fn name_to_var(&self, _name: impl AsRef<str>) -> Option<VarNo> {
202 None
203 }
204
205 fn var_to_level(&self, _var: VarNo) -> LevelNo {
206 panic!("out of range")
207 }
208
209 fn level_to_var(&self, _level: LevelNo) -> VarNo {
210 panic!("out of range")
211 }
212
213 fn level(&self, _no: LevelNo) -> Self::LevelView<'_> {
214 panic!("out of range")
215 }
216
217 unsafe fn level_unchecked(&self, _no: LevelNo) -> Self::LevelView<'_> {
218 panic!("out of range")
219 }
220
221 fn levels(&self) -> Self::LevelIterator<'_> {
222 std::iter::empty()
223 }
224
225 fn get_terminal(&self, _terminal: Self::Terminal) -> AllocResult<Self::Edge> {
226 unimplemented!()
227 }
228
229 fn num_terminals(&self) -> usize {
230 0
231 }
232
233 fn terminals(&self) -> Self::TerminalIterator<'_> {
234 std::iter::empty()
235 }
236
237 fn gc(&self) -> usize {
238 0
239 }
240
241 fn reorder<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
242 f(self)
243 }
244
245 fn gc_count(&self) -> u64 {
246 0
247 }
248
249 fn reorder_count(&self) -> u64 {
250 0
251 }
252}
253
254impl HasWorkers for DummyManager {
255 type WorkerPool = crate::Workers;
256
257 fn workers(&self) -> &Self::WorkerPool {
258 &crate::Workers
259 }
260}
261
262pub struct DummyLevelView;
264
265unsafe impl LevelView<DummyEdge, DummyNode> for DummyLevelView {
266 type Iterator<'a>
267 = std::iter::Empty<&'a DummyEdge>
268 where
269 Self: 'a,
270 DummyEdge: 'a;
271
272 type Taken = Self;
273
274 fn len(&self) -> usize {
275 unreachable!()
276 }
277
278 fn level_no(&self) -> LevelNo {
279 unreachable!()
280 }
281
282 fn reserve(&mut self, _additional: usize) {
283 unreachable!()
284 }
285
286 fn get(&self, _node: &DummyNode) -> Option<&DummyEdge> {
287 unreachable!()
288 }
289
290 fn insert(&mut self, _edge: DummyEdge) -> bool {
291 unreachable!()
292 }
293
294 unsafe fn insert_unchecked(&mut self, _edge: DummyEdge) -> bool {
295 unreachable!()
296 }
297
298 fn get_or_insert(&mut self, _node: DummyNode) -> AllocResult<DummyEdge> {
299 unreachable!()
300 }
301
302 unsafe fn get_or_insert_unchecked(&mut self, _node: DummyNode) -> AllocResult<DummyEdge> {
303 unreachable!()
304 }
305
306 fn gc(&mut self) {
307 unreachable!()
308 }
309
310 fn remove(&mut self, _node: &DummyNode) -> bool {
311 unreachable!()
312 }
313
314 unsafe fn swap(&mut self, _other: &mut Self) {
315 unreachable!()
316 }
317
318 fn iter(&self) -> Self::Iterator<'_> {
319 unreachable!()
320 }
321
322 fn take(&mut self) -> Option<Self::Taken> {
323 unreachable!()
324 }
325}
326
327#[derive(PartialEq, Eq, Hash, Debug)]
329pub struct DummyNode;
330
331impl DropWith<DummyEdge> for DummyNode {
332 fn drop_with(self, _drop_edge: impl Fn(DummyEdge)) {
333 unimplemented!()
334 }
335}
336
337impl InnerNode<DummyEdge> for DummyNode {
338 const ARITY: usize = 0;
339
340 type ChildrenIter<'a>
341 = std::iter::Empty<Borrowed<'a, DummyEdge>>
342 where
343 Self: 'a;
344
345 fn new(_level: LevelNo, _children: impl IntoIterator<Item = DummyEdge>) -> Self {
346 unimplemented!()
347 }
348
349 fn check_level(&self, _check: impl FnOnce(LevelNo) -> bool) -> bool {
350 true
351 }
352 fn assert_level_matches(&self, _level: LevelNo) {}
353
354 fn children(&self) -> Self::ChildrenIter<'_> {
355 std::iter::empty()
356 }
357
358 fn child(&self, _n: usize) -> Borrowed<'_, DummyEdge> {
359 unimplemented!()
360 }
361
362 unsafe fn set_child(&self, _n: usize, _child: DummyEdge) -> DummyEdge {
363 unimplemented!()
364 }
365
366 fn ref_count(&self) -> usize {
367 unimplemented!()
368 }
369}
370
371#[macro_export]
388macro_rules! assert_ref_counts {
389 ($edge:ident = $count:literal) => {
390 assert_eq!($edge.ref_count(), $count);
391 };
392 ($edge:ident, $($edges:ident),+ = $count:literal) => {
393 assert_ref_counts!($edge = $count);
394 assert_ref_counts!($($edges),+ = $count);
395 };
396 ($($edges:ident),+ = $count:literal; $($($edgess:ident),+ = $counts:literal);+) => {
398 assert_ref_counts!($($edges),+ = $count);
399 assert_ref_counts!($($($edgess),+ = $counts);+);
400 };
401}