loupe 0.2.0

Profiling tool for Rust
Documentation
#[cfg(test)]
use crate::{assert_size_of_val_eq, POINTER_BYTE_SIZE};
use crate::{MemoryUsage, MemoryUsageTracker};
use std::mem;
use std::sync::{
    atomic::{
        AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
        AtomicU64, AtomicU8, AtomicUsize,
    },
    Arc, Mutex, RwLock, Weak,
};

macro_rules! impl_memory_usage_for_numeric {
    ( $type:ty ) => {
        impl MemoryUsage for $type {
            fn size_of_val(&self, _: &mut dyn MemoryUsageTracker) -> usize {
                mem::size_of_val(self)
            }
        }
    };

    ( $( $type:ty ),+ $(,)* ) => {
        $( impl_memory_usage_for_numeric!( $type ); )+
    }
}

impl_memory_usage_for_numeric!(
    AtomicBool,
    AtomicI8,
    AtomicI16,
    AtomicI32,
    AtomicI64,
    AtomicIsize,
    AtomicU8,
    AtomicU16,
    AtomicU32,
    AtomicU64,
    AtomicUsize,
);

impl<T> MemoryUsage for Arc<T>
where
    T: MemoryUsage + ?Sized,
{
    fn size_of_val(&self, tracker: &mut dyn MemoryUsageTracker) -> usize {
        mem::size_of_val(self)
            + if tracker.track(Arc::as_ptr(self) as *const ()) {
                self.as_ref().size_of_val(tracker)
            } else {
                0
            }
    }
}

impl<T> MemoryUsage for Weak<T>
where
    T: MemoryUsage + ?Sized,
{
    fn size_of_val(&self, tracker: &mut dyn MemoryUsageTracker) -> usize {
        mem::size_of_val(self)
            + if tracker.track(Weak::as_ptr(self) as *const ()) {
                Weak::upgrade(self)
                    .map(|arc| arc.as_ref().size_of_val(tracker))
                    .unwrap_or(0)
            } else {
                0
            }
    }
}

impl<T> MemoryUsage for Mutex<T>
where
    T: MemoryUsage + ?Sized,
{
    fn size_of_val(&self, tracker: &mut dyn MemoryUsageTracker) -> usize {
        mem::size_of_val(self) + self.lock().unwrap().size_of_val(tracker)
    }
}

impl<T> MemoryUsage for RwLock<T>
where
    T: MemoryUsage + ?Sized,
{
    fn size_of_val(&self, tracker: &mut dyn MemoryUsageTracker) -> usize {
        mem::size_of_val(self) + self.read().unwrap().size_of_val(tracker)
    }
}

#[cfg(test)]
mod test_sync_types {
    use super::*;

    macro_rules! test_memory_usage_for_numeric {
        ($test_name:ident: ($value:expr) == $expected:expr) => {
            #[test]
            fn $test_name() {
                assert_size_of_val_eq!($value, $expected);
            }
        };

        ( $( $test_name:ident: ($value:expr) == $expected:expr );+ $(;)* ) => {
            $( test_memory_usage_for_numeric!( $test_name: ($value) == $expected); )+
        }
    }

    test_memory_usage_for_numeric!(
        test_atomic_bool: (AtomicBool::new(true)) == 1;
        test_atomic_i8: (AtomicI8::new(1i8)) == 1;
        test_atomic_i16: (AtomicI16::new(1i16)) == 2;
        test_atomic_i32: (AtomicI32::new(1i32)) == 4;
        test_atomic_i64: (AtomicI64::new(1i64)) == 8;
        test_atomic_isize: (AtomicIsize::new(1isize)) == POINTER_BYTE_SIZE;
        test_atomic_u8: (AtomicU8::new(1u8)) == 1;
        test_atomic_u16: (AtomicU16::new(1u16)) == 2;
        test_atomic_u32: (AtomicU32::new(1u32)) == 4;
        test_atomic_u64: (AtomicU64::new(1u64)) == 8;
        test_atomic_usize: (AtomicUsize::new(1usize)) == POINTER_BYTE_SIZE;
    );

    #[test]
    fn test_arc() {
        let empty_arc_size = mem::size_of_val(&Arc::new(()));

        let arc: Arc<i32> = Arc::new(1);
        assert_size_of_val_eq!(arc, empty_arc_size + 4);

        let arc: Arc<Option<i32>> = Arc::new(Some(1));
        assert_size_of_val_eq!(arc, empty_arc_size + POINTER_BYTE_SIZE + 4);
    }

    #[test]
    fn test_weak() {
        let empty_weak_size = mem::size_of_val(&Arc::downgrade(&Arc::new(())));

        let arc: Arc<i32> = Arc::new(1);
        let weak: Weak<i32> = Arc::downgrade(&arc);
        assert_size_of_val_eq!(weak, empty_weak_size + 4);

        let arc: Arc<Option<i32>> = Arc::new(Some(1));
        let weak: Weak<Option<i32>> = Arc::downgrade(&arc);
        assert_size_of_val_eq!(weak, empty_weak_size + POINTER_BYTE_SIZE + 4);

        let weak: Weak<i32> = {
            let arc: Arc<i32> = Arc::new(5);
            Arc::downgrade(&arc)
        };
        assert_size_of_val_eq!(weak, empty_weak_size);
    }

    #[test]
    fn test_mutex() {
        let empty_mutex_size = mem::size_of_val(&Mutex::new(()));

        let mutex: Mutex<i32> = Mutex::new(1);
        assert_size_of_val_eq!(mutex, empty_mutex_size + 4);

        let mutex: Mutex<Option<i32>> = Mutex::new(Some(1));
        assert_size_of_val_eq!(mutex, empty_mutex_size + 2 * POINTER_BYTE_SIZE + 4);
    }

    #[test]
    fn test_rwlock() {
        let empty_rwlock_size = mem::size_of_val(&RwLock::new(()));

        let rwlock: RwLock<i32> = RwLock::new(1);
        assert_size_of_val_eq!(rwlock, empty_rwlock_size + 4);

        let rwlock: RwLock<Option<i32>> = RwLock::new(Some(1));
        assert_size_of_val_eq!(rwlock, empty_rwlock_size + 2 * POINTER_BYTE_SIZE + 4);
    }
}