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
use crate::*;

#[cfg(target_arch="wasm32")]
pub mod internal {
    use wasm_bindgen::prelude::*;

    #[wasm_bindgen]
    extern {
        #[wasm_bindgen(js_namespace=console)]
        fn error(msg: String);

        type Error;

        #[wasm_bindgen(constructor)]
        fn new() -> Error;

        #[wasm_bindgen(structural,method,getter)]
        fn stack(error: &Error) -> String;
    }

    /// Print the current backtrace.
    pub fn backtrace() -> String {
        Error::new().stack()
    }
}

#[cfg(not(target_arch="wasm32"))]
mod internal {
    use crate::*;

    extern crate backtrace as bt;

    use bt::Backtrace;

    /// Print the current backtrace.
    pub fn backtrace() -> String {
        let bt = Backtrace::new();
        iformat!("{bt:?}")
    }
}

pub use internal::backtrace;



// ===================
// === TraceCopies ===
// ===================

/// An utility for tracing all copies of CloneRef-able entity.
///
/// This structure should be added as a field to structure implementing Clone or CloneRef. It will
/// mark each copy with unique id (the original copy has id of 0). Once enabled, it will print
/// backtrace of each clone, clone_ref or drop operation with assigned name (the same for all
/// copies) and copy id.
#[derive(Debug,Default)]
pub struct TraceCopies {
    clone_id : u64,
    handle   : Rc<RefCell<Option<ImString>>>,
}

thread_local! {
    static NEXT_CLONE_ID : Cell<u64> = Cell::new(1);
}

fn next_clone_id() -> u64 {
    NEXT_CLONE_ID.with(|id| {
        let next = id.get();
        id.set(next+1);
        next
    })
}

impl TraceCopies {
    /// Create enabled structure with appointed entity name (shared between all copies).
    pub fn enabled(name:impl Into<ImString>) -> Self {
        Self {
            clone_id : default(),
            handle   : Rc::new(RefCell::new(Some(name.into()))),
        }
    }

    /// Assign a name to the entity (shared between all copies) and start printing logs.
    pub fn enable(&self, name: impl Into<ImString>) {
        *self.handle.borrow_mut() = Some(name.into());
    }
}

impl Clone for TraceCopies {
    fn clone(&self) -> Self {
        let borrow   = self.handle.borrow();
        let clone_id = next_clone_id();
        let handle   = self.handle.clone();
        if let Some(name) = &*borrow {
            let bt = backtrace();
            iprintln!("[{name}] Cloning {self.clone_id} -> {clone_id} {bt}");
        }
        Self {clone_id,handle}
    }
}

impl CloneRef for TraceCopies {
    fn clone_ref(&self) -> Self {
        let borrow   = self.handle.borrow();
        let clone_id = next_clone_id();
        let handle   = self.handle.clone_ref();
        if let Some(name) = &*borrow {
            let bt = backtrace();
            iprintln!("[{name}] Cloning {self.clone_id} -> {clone_id} {bt}");
        }
        Self {clone_id,handle}
    }
}

impl Drop for TraceCopies {
    fn drop(&mut self) {
        let borrow = self.handle.borrow();
        if let Some(name) = &*borrow {
            let bt        = backtrace();
            let instances = Rc::strong_count(&self.handle) - 1;
            iprintln!("[{name}] Dropping {self.clone_id}; instances left: {instances} {bt}");
        }
    }
}