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