Skip to main content

wiwi_memory_usage/
lib.rs

1#![allow(
2	stable_features,
3	reason = "new_range_api, new_range_from_api, new_range_to_inclusive_api is not stable in msrv"
4)]
5#![cfg_attr(
6	feature = "nightly",
7	feature(
8		const_trait_impl,
9		f16,
10		f128,
11		integer_atomics,
12		new_range_api,
13		new_range_from_api,
14		new_range_to_inclusive_api,
15		phantom_variance_markers
16	)
17)]
18#![cfg_attr(
19	not(feature = "std"),
20	no_std
21)]
22#![deny(
23	unconditional_recursion,
24	clippy::unconditional_recursion
25)]
26
27mod macros;
28
29// the "const" syntax is nightly too, so we can't just
30// use a feature gate on normal code
31macro_rules! const_trait {
32	() => {
33		/// Types that know their own memory usage
34		#[diagnostic::on_unimplemented(
35			message = "Type doesn't know its memory usage"
36		)]
37		pub trait MemoryUsage: MemoryCompaction {
38			/// Get memory usage (including direct, indirect, and compactible memory)
39			fn memory_usage(&self) -> usize;
40		}
41
42		/// Types that always have the same memory usage, regardless of value
43		/// (notably different than [`Sized`])
44		#[diagnostic::on_unimplemented(
45			message = "Type doesn't know its static memory usage"
46		)]
47		pub trait MemoryUsageStatic: MemoryUsage {
48			const MEMORY_USAGE: usize;
49		}
50	};
51
52	(const) => {
53		/// Types that know their own memory usage
54		#[diagnostic::on_unimplemented(
55			message = "Type doesn't know its memory usage"
56		)]
57		pub const trait MemoryUsage: MemoryCompaction {
58			/// Get memory usage (including direct, indirect, and compactible memory)
59			fn memory_usage(&self) -> usize;
60		}
61
62		/// Types that always have the same memory usage, regardless of value
63		/// (notably different than [`Sized`])
64		#[diagnostic::on_unimplemented(
65			message = "Type doesn't know its static memory usage"
66		)]
67		pub const trait MemoryUsageStatic: [const] MemoryUsage {
68			const MEMORY_USAGE: usize;
69		}
70	};
71}
72
73#[cfg(not(feature = "nightly"))]
74const_trait!();
75
76#[cfg(feature = "nightly")]
77const_trait!(const);
78
79pub trait MemoryCompaction {
80	/// Get expected memory usage saved after compaction
81	///
82	/// Compaction means to remove unnecessary memory usage. This would include,
83	/// for example, removing the unused capacity of a [`Vec`], by calling
84	/// [`shrink_to_fit()`](Vec::shrink_to_fit).
85	///
86	/// Types like [`Vec`] that support memory compaction _should_ reimplement
87	/// this function.
88	#[inline]
89	fn memory_usage_compacted(&self) -> usize {
90		// default is delegate to ref version of this method, so if someone
91		// implements ref, they get this one for free if they want it
92		// otherwise, no-op
93		self.memory_usage_compacted_ref()
94	}
95
96	/// Perform memory compaction, saving as much memory as possible,
97	/// returning the amount of bytes saved
98	#[inline]
99	fn compact_memory(&mut self) -> usize {
100		// default is delegate to ref version of this method, so if someone
101		// implements ref, they get this one for free if they want it
102		// otherwise, no-op
103		self.compact_memory_ref()
104	}
105
106	/// Get expected memory usage saved after compaction behind a shared reference
107	///
108	/// This is useful for types with interior mutability. Types that have or
109	/// could have (ie. with generics) should implement this method and
110	/// [`compact_memory_ref()`](MemoryUsage::compact_memory_ref).
111	/// For types that don't, the default implementation is a no-op.
112	///
113	/// See [`MemoryUsage::memory_usage_compacted`] for more details.
114	#[inline]
115	fn memory_usage_compacted_ref(&self) -> usize {
116		// default is no-op, and no bytes saved
117		0
118	}
119
120	/// Perform memory compaction behind a shared reference, saving as much
121	/// memory as possible, returning the amount of bytes saved
122	///
123	/// This is useful for types with interior mutability. Types that have or
124	/// could have (ie. with generics) should implement this method and
125	/// [`memory_usage_compacted_ref()`](MemoryUsage::memory_usage_compacted_ref).
126	/// For types that don't, the default implementation is a no-op.
127	///
128	/// See [`MemoryUsage::compact_memory`] for more details.
129	#[inline]
130	fn compact_memory_ref(&self) -> usize {
131		// default is no-op, and no bytes saved
132		0
133	}
134}
135
136mod impls {
137	// todo primitive types, fn (pointer), closure, tuple (to 16)
138	// todo cells, path, osstr, cstr, rc, arc, types in our lib, other popular libs
139
140	mod array;
141	mod atomic;
142	mod bool;
143	mod char;
144	mod marker;
145	mod nonzero;
146	mod number;
147	mod option;
148	mod pointer;
149	mod range;
150	mod reference;
151	mod result;
152	mod saturating;
153	mod slice;
154	mod string;
155	mod unit;
156	mod vec;
157	mod wrapping;
158}
159
160#[doc(hidden)]
161pub mod __macro_support {
162	pub(crate) use crate::macros::{
163		impl_memory_usage,
164		impl_memory_usage_only_static,
165		impl_memory_usage_static
166	};
167	pub use wiwi_macro_proc::{
168		memory_usage_cfg_nightly as cfg_nightly,
169		memory_usage_cfg_not_nightly as cfg_not_nightly
170	};
171}