typesize/
lib.rs

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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! # Typesize
//!
//! A library to fetch an accurate estimate of the total memory usage of a value.
//!
//! The goal of this library is to produce the most accurate estimate possible, however without being deeply
//! integrated into the entire ecosystem this cannot be possible. This leads to the real goal being to get
//! "close enough" for getting a sense of memory usage in your program. If one of the [`TypeSize`]
//! implementations built-in could be improved, a PR would be greatly appreciated.
//!
//! An example usage of this library would be to wrap all the types you want to measure recursively in
//! the [`derive::TypeSize`] derive macro, and for any types which perform their own heap allocation
//! to manually implement [`TypeSize`] while overriding the [`TypeSize::extra_size`] method.
//!
//! ## MSRV
//! The Minimum Supported Rust Version is of this crate is 1.65, and it is considered breaking to raise this.
//!
//! This is without any library support features, as those libraries may require a higher MSRV.
//!
//! ## Features
//!
//! - `std`: Implements [`TypeSize`] for [`HashMap`] and [`HashSet`], default enabled.
//! - `details`: Adds [`TypeSize::get_size_details`] and [`TypeSize::get_collection_item_count`] to get field by field breakdowns of struct types.
//!
//! ### Library Support
//! - `dashmap`: Implements [`TypeSize`] for [`DashMap`] (**Only `5.x`, use the `typesize` feature of dashmap for `6.1`+**).
//! - `arrayvec`: Implements [`TypeSize`] for [`ArrayVec`] and [`ArrayString`] of any size.
//! - `simd_json`: Implements [`TypeSize`] for [`OwnedValue`] and [`StaticNode`], enables halfbrown.
//! - `halfbrown`: Implements [`TypeSize`] for [`SizedHashMap`], enables hashbrown.
//! - `extract_map_01`: Implements [`TypeSize`] for [`extract_map::ExtractMap`].
//! - `parking_lot`: Implements [`TypeSize`] for [`parking_lot::Mutex`] and [`parking_lot::RwLock`].
//! - `serde_json`: Implements [`TypeSize`] for [`serde_json::Value`] and [`serde_json::Map`].
//! - `mini_moka`: Implements [`TypeSize`] for [`mini_moka::unsync::Cache`], and [`mini_moka::sync::Cache`] if `dashmap` is enabled.
//! - `hashbrown`: Implements [`TypeSize`] for [`hashbrown::HashMap`].
//! - `secrecy`: Implements [`TypeSize`] for [`Secret`].
//! - `chrono`: Implements [`TypeSize`] for [`chrono::DateTime`] of any [`chrono::TimeZone`].
//! - `nonmax`: Implements [`TypeSize`] for all [`nonmax`] types.
//! - `time`: Implements [`TypeSize`] for [`time::OffsetDateTime`].
//! - `url`: Implements [`TypeSize`] for [`url::Url`].
//! - `bitvec`: Implements [`TypeSize`] for [`bitvec::array::BitArray`] and [`bitvec::vec::BitVec`].
//! - `web-time`: Implements [`TypeSize`] for [`web_time::Instant`] and [`web_time::SystemTime`] (on platforms where these aren't type aliases to [`std::time`] types).
//!
//! [`HashMap`]: std::collections::HashMap
//! [`HashSet`]: std::collections::HashSet
//! [`ArrayVec`]: arrayvec::ArrayVec
//! [`ArrayString`]: arrayvec::ArrayString
//! [`OwnedValue`]: simd_json::OwnedValue
//! [`StaticNode`]: simd_json::StaticNode
//! [`SizedHashMap`]: halfbrown::SizedHashMap
//! [`DashMap`]: dashmap::DashMap
//! [`Secret`]: secrecy::Secret
#![cfg_attr(not(feature = "std"), no_std)]

extern crate alloc;

mod r#box;
mod cell;
mod enums;
mod hash;
mod libs;
#[cfg(any(feature = "std", feature = "mini_moka", feature = "hashbrown"))]
mod map;
mod primitives;
pub mod ptr;
mod set;
#[cfg(feature = "std")]
mod sync;
mod time;
mod tuple;
mod vec;

#[deprecated = "Use ptr::{Ref, RefMut}"]
pub use ptr::{Ref, RefMut};

pub mod derive {
    pub use typesize_derive::TypeSize;
}

/// A trait to fetch an accurate estimate of the total memory usage of a value.
///
/// Unless you are writing a data structure, you should derive this trait using [`derive::TypeSize`].
///
/// Note: Implementations cannot be relied on for any form of `unsafe` bound,
/// as this is entirely safe to implement incorrectly.
pub trait TypeSize: Sized {
    /// The number of bytes more than the [`core::mem::size_of`] that this value is using.
    #[must_use]
    fn extra_size(&self) -> usize {
        0
    }

    /// The total number of bytes that this type is using, both direct
    /// ([`core::mem::size_of`]) and indirect (behind allocations)
    ///
    /// There's no reason to ever override this method.
    #[must_use]
    fn get_size(&self) -> usize {
        core::mem::size_of::<Self>() + self.extra_size()
    }

    /// Returns information about the number of items this type is holding, if it is a collection.
    #[must_use]
    #[cfg(feature = "details")]
    fn get_collection_item_count(&self) -> Option<usize> {
        None
    }

    /// Returns detailed information about the current value's field sizes.
    ///
    /// This should generally be implemented by [`derive::TypeSize`]
    #[must_use]
    #[cfg(feature = "details")]
    fn get_size_details(&self) -> alloc::vec::Vec<Field> {
        alloc::vec::Vec::new()
    }
}

/// A description of a struct or enum field.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[cfg(feature = "details")]
pub struct Field {
    /// The name of the field being described.
    pub name: &'static str,
    /// The total size of the field.
    pub size: usize,
    /// How many items this collection is holding, if it is one.
    pub collection_items: Option<usize>,
}

/// Implements [`TypeSize`] for multiple types based on the return value of [`core::mem::size_of`].
#[macro_export]
macro_rules! sizeof_impl {
    ($($ty:ty),*) => {
        $(impl TypeSize for $ty {})*
    };
}

/// Passes through the given tokens if the `details` feature of `typesize` is enabled.
///
/// This is mainly useful for libaries making their own [`TypeSize`] to be compatible with `details` on or off.
#[macro_export]
#[cfg(feature = "details")]
macro_rules! if_typesize_details {
    ($($tt:tt)*) => {
        $($tt)*
    }
}

/// Passes through the given tokens if the `details` feature of `typesize` is enabled.
///
/// This is mainly useful for libaries making their own [`TypeSize`] to be compatible with `details` on or off.
#[macro_export]
#[cfg(not(feature = "details"))]
macro_rules! if_typesize_details {
    ($($tt:tt)*) => {};
}