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