• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // We avoid relying on anything else in the crate, apart from the `Debug` trait.
2 use crate::fmt::Debug;
3 use std::cmp::Ordering;
4 use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
5 
6 /// A blueprint for crash test dummy instances that monitor particular events.
7 /// Some instances may be configured to panic at some point.
8 /// Events are `clone`, `drop` or some anonymous `query`.
9 ///
10 /// Crash test dummies are identified and ordered by an id, so they can be used
11 /// as keys in a BTreeMap.
12 #[derive(Debug)]
13 pub struct CrashTestDummy {
14     pub id: usize,
15     cloned: AtomicUsize,
16     dropped: AtomicUsize,
17     queried: AtomicUsize,
18 }
19 
20 impl CrashTestDummy {
21     /// Creates a crash test dummy design. The `id` determines order and equality of instances.
new(id: usize) -> CrashTestDummy22     pub fn new(id: usize) -> CrashTestDummy {
23         CrashTestDummy {
24             id,
25             cloned: AtomicUsize::new(0),
26             dropped: AtomicUsize::new(0),
27             queried: AtomicUsize::new(0),
28         }
29     }
30 
31     /// Creates an instance of a crash test dummy that records what events it experiences
32     /// and optionally panics.
spawn(&self, panic: Panic) -> Instance<'_>33     pub fn spawn(&self, panic: Panic) -> Instance<'_> {
34         Instance { origin: self, panic }
35     }
36 
37     /// Returns how many times instances of the dummy have been cloned.
cloned(&self) -> usize38     pub fn cloned(&self) -> usize {
39         self.cloned.load(SeqCst)
40     }
41 
42     /// Returns how many times instances of the dummy have been dropped.
dropped(&self) -> usize43     pub fn dropped(&self) -> usize {
44         self.dropped.load(SeqCst)
45     }
46 
47     /// Returns how many times instances of the dummy have had their `query` member invoked.
queried(&self) -> usize48     pub fn queried(&self) -> usize {
49         self.queried.load(SeqCst)
50     }
51 }
52 
53 #[derive(Debug)]
54 pub struct Instance<'a> {
55     origin: &'a CrashTestDummy,
56     panic: Panic,
57 }
58 
59 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
60 pub enum Panic {
61     Never,
62     InClone,
63     InDrop,
64     InQuery,
65 }
66 
67 impl Instance<'_> {
id(&self) -> usize68     pub fn id(&self) -> usize {
69         self.origin.id
70     }
71 
72     /// Some anonymous query, the result of which is already given.
query<R>(&self, result: R) -> R73     pub fn query<R>(&self, result: R) -> R {
74         self.origin.queried.fetch_add(1, SeqCst);
75         if self.panic == Panic::InQuery {
76             panic!("panic in `query`");
77         }
78         result
79     }
80 }
81 
82 impl Clone for Instance<'_> {
clone(&self) -> Self83     fn clone(&self) -> Self {
84         self.origin.cloned.fetch_add(1, SeqCst);
85         if self.panic == Panic::InClone {
86             panic!("panic in `clone`");
87         }
88         Self { origin: self.origin, panic: Panic::Never }
89     }
90 }
91 
92 impl Drop for Instance<'_> {
drop(&mut self)93     fn drop(&mut self) {
94         self.origin.dropped.fetch_add(1, SeqCst);
95         if self.panic == Panic::InDrop {
96             panic!("panic in `drop`");
97         }
98     }
99 }
100 
101 impl PartialOrd for Instance<'_> {
partial_cmp(&self, other: &Self) -> Option<Ordering>102     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
103         self.id().partial_cmp(&other.id())
104     }
105 }
106 
107 impl Ord for Instance<'_> {
cmp(&self, other: &Self) -> Ordering108     fn cmp(&self, other: &Self) -> Ordering {
109         self.id().cmp(&other.id())
110     }
111 }
112 
113 impl PartialEq for Instance<'_> {
eq(&self, other: &Self) -> bool114     fn eq(&self, other: &Self) -> bool {
115         self.id().eq(&other.id())
116     }
117 }
118 
119 impl Eq for Instance<'_> {}
120