1use std::mem;
4
5pub trait SpaceUsage: Sized {
31 #[inline]
39 fn total_bytes(&self) -> usize {
40 Self::stack_bytes() + self.heap_bytes()
41 }
42
43 fn is_stack_only() -> bool;
48
49 #[inline]
58 fn stack_bytes() -> usize {
59 mem::size_of::<Self>()
60 }
61
62 #[inline]
69 fn heap_bytes(&self) -> usize;
70}
71
72impl_stack_only_space_usage!(());
73impl_stack_only_space_usage!(u8);
74impl_stack_only_space_usage!(u16);
75impl_stack_only_space_usage!(u32);
76impl_stack_only_space_usage!(u64);
77impl_stack_only_space_usage!(usize);
78impl_stack_only_space_usage!(i8);
79impl_stack_only_space_usage!(i16);
80impl_stack_only_space_usage!(i32);
81impl_stack_only_space_usage!(i64);
82impl_stack_only_space_usage!(isize);
83impl_stack_only_space_usage!(f32);
84impl_stack_only_space_usage!(f64);
85
86impl<'a, T> SpaceUsage for &'a T {
87 fn is_stack_only() -> bool { true }
88 fn heap_bytes(&self) -> usize { 0 }
89}
90
91impl<'a, T> SpaceUsage for &'a [T] {
92 fn is_stack_only() -> bool { true }
93 fn heap_bytes(&self) -> usize { 0 }
94}
95
96macro_rules! impl_tuple_space_usage {
97 ( $( $tv:ident ),+ ) =>
98 {
99 impl<$( $tv: SpaceUsage ),+> SpaceUsage for ($( $tv, )+) {
100 #[allow(non_snake_case)]
101 fn heap_bytes(&self) -> usize {
102 let &($( ref $tv, )+) = self;
103 0 $( + $tv.heap_bytes() )+
104 }
105
106 #[inline]
107 fn is_stack_only() -> bool {
108 $( $tv::is_stack_only() )&*
109 }
110 }
111 }
112}
113
114impl_tuple_space_usage!(A);
115impl_tuple_space_usage!(A, B);
116impl_tuple_space_usage!(A, B, C);
117impl_tuple_space_usage!(A, B, C, D);
118impl_tuple_space_usage!(A, B, C, D, E);
119impl_tuple_space_usage!(A, B, C, D, E, F);
120impl_tuple_space_usage!(A, B, C, D, E, F, G);
121impl_tuple_space_usage!(A, B, C, D, E, F, G, H);
122impl_tuple_space_usage!(A, B, C, D, E, F, G, H, I);
123impl_tuple_space_usage!(A, B, C, D, E, F, G, H, I, J);
124impl_tuple_space_usage!(A, B, C, D, E, F, G, H, I, J, K);
125impl_tuple_space_usage!(A, B, C, D, E, F, G, H, I, J, K, L);
126
127impl<A: SpaceUsage + ::std::fmt::Debug> SpaceUsage for Vec<A> {
128 #[inline]
129 fn is_stack_only() -> bool { false }
130
131 fn heap_bytes(&self) -> usize {
132 let mut result = self.capacity() * A::stack_bytes();
133
134 if ! A::is_stack_only() {
135 for each in self {
136 result += each.heap_bytes();
137 }
138 }
139
140 result
141 }
142}
143
144impl<A: SpaceUsage> SpaceUsage for Box<A> {
145 #[inline]
146 fn is_stack_only() -> bool { false }
147
148 fn stack_bytes() -> usize {
149 mem::size_of::<Self>()
150 }
151
152 fn heap_bytes(&self) -> usize {
153 use std::ops::Deref;
154 self.deref().total_bytes()
155 }
156}
157
158#[cfg(test)]
159mod test {
160 use super::*;
161 use std::mem::size_of;
162
163 #[test]
164 fn is_stack_only() {
165 assert!( u32::is_stack_only());
166 assert!( isize::is_stack_only());
167 assert!(! Vec::<u64>::is_stack_only());
168 assert!(! Vec::<Vec<u64>>::is_stack_only());
169 assert!( <(u32, u32, u32)>::is_stack_only());
170 assert!(! <(u32, Vec<u32>, u32)>::is_stack_only());
171 }
172
173 #[test]
174 fn int_size() {
175 assert_eq!(2, 0u16.total_bytes());
176 assert_eq!(4, 0u32.total_bytes());
177 assert_eq!(8, 0i64.total_bytes());
178 }
179
180 #[test]
181 fn tuple_size() {
182 assert_eq!(8, (0u32, 0u32).total_bytes());
183 assert_eq!(12, (0u32, 0u8, 0u32).total_bytes());
185 }
186
187 #[test]
188 fn vec_size() {
189 let v = Vec::<u64>::with_capacity(8);
190 assert_eq!(8, v.capacity());
191 assert_eq!(64, v.heap_bytes());
192 assert_eq!(64 + size_of::<Vec<u64>>(),
193 v.total_bytes());
194 }
195
196 #[test]
197 fn vec_vec_size() {
198 let v1 = Vec::<u64>::with_capacity(8);
199 let v2 = Vec::<u64>::with_capacity(8);
200 let w = vec![v1, v2];
201 assert_eq!(2, w.capacity());
202 assert_eq!(128 + 2 * size_of::<Vec<u64>>() +
203 size_of::<Vec<Vec<u64>>>(),
204 w.total_bytes());
205 }
206}