1pub mod params;
4
5use std::alloc;
6use std::alloc::Layout;
7use std::hash::{Hash, Hasher};
8use std::ptr;
9use std::ptr::NonNull;
10use std::mem;
11use std::slice;
12use std::ops;
13pub use self::params::{DefaultParams, Params};
14
15#[derive(Clone, Debug)]
19pub struct ZeroBufInner<T> {
20 ptr: NonNull<T>,
21 capacity: usize,
22}
23
24impl<T> ZeroBufInner<T> {
25 pub fn capacity(&self) -> usize {
26 self.capacity
27 }
28
29 pub fn as_slice(&self) -> &[T] {
30 unsafe {
34 slice::from_raw_parts(self.ptr.as_ptr(), self.capacity())
35 }
36 }
37
38 pub fn as_slice_mut(&mut self) -> &mut [T] {
39 unsafe {
41 slice::from_raw_parts_mut(self.ptr.as_ptr(), self.capacity())
42 }
43 }
44}
45
46impl<T> ops::Deref for ZeroBufInner<T> {
47 type Target = [T];
48
49 fn deref(&self) -> &[T] {
50 self.as_slice()
51 }
52}
53
54impl<T> ops::DerefMut for ZeroBufInner<T> {
55 fn deref_mut(&mut self) -> &mut [T] {
56 self.as_slice_mut()
57 }
58}
59
60impl<T: Hash> Hash for ZeroBufInner<T> {
61 fn hash<H: Hasher>(&self, state: &mut H) {
62 Hash::hash(&**self, state)
63 }
64}
65
66#[derive(Clone, Debug, Hash)]
71pub struct ZeroBuf<T, P: Params<T> = DefaultParams> {
72 inner: ZeroBufInner<T>,
73 params: P,
74}
75
76impl<T> ZeroBuf<T> {
77 pub fn new() -> Self {
79 Self::with_capacity(0)
80 }
81
82 pub fn with_capacity(capacity: usize) -> Self {
91 Self::with_capacity_and_params(capacity, DefaultParams)
92 }
93}
94
95impl<T, P: Params<T>> ZeroBuf<T, P> {
96 pub fn new_with_params(p: P) -> Self {
99 Self::with_capacity_and_params(0, p)
100 }
101
102 pub fn with_capacity_and_params(capacity: usize, params: P) -> Self {
112 match (capacity, mem::size_of::<T>()) {
113 (0, _) | (_, 0) => {
114 Self {
115 inner: ZeroBufInner {
116 ptr: NonNull::dangling(),
117 capacity,
118 },
119 params,
120 }
121 }
122 (capacity, _) => {
123 Self {
124 inner: ZeroBufInner {
125 ptr: Self::alloc_zeroed(capacity),
126 capacity,
127 },
128 params,
129 }
130 }
131 }
132 }
133
134 pub fn capacity(&self) -> usize {
136 self.inner.capacity()
137 }
138
139 pub fn as_slice(&self) -> &[T] {
152 unsafe {
156 slice::from_raw_parts(self.inner.ptr.as_ptr(), self.capacity())
157 }
158 }
159
160 pub fn as_slice_mut(&mut self) -> &mut [T] {
173 unsafe {
175 slice::from_raw_parts_mut(self.inner.ptr.as_ptr(), self.capacity())
176 }
177 }
178
179 pub fn resize(&mut self, new_capacity: usize) {
187 match new_capacity {
188 x if x == self.capacity() => (),
189 0 => {
190 self.params.drop(&mut self.inner);
193 self.free();
195 }
196 new_capacity => self.realloc_zeroed(new_capacity),
197 }
198 }
199
200 pub fn grow(&mut self) {
213 let new_capacity = self.params.next_capacity(&mut self.inner);
214 self.resize(new_capacity);
215 }
216
217 fn alloc_zeroed(size: usize) -> NonNull<T> {
218 let layout = Self::make_layout(size);
219 let ptr = unsafe {
220 alloc::alloc_zeroed(layout)
221 };
222
223 NonNull::new(ptr).expect("allocation failed").cast()
224 }
225
226 fn realloc_zeroed(&mut self, size: usize) {
227 let old_layout = Self::make_layout(size);
229 let old_size = self.capacity();
230 let layout = Self::make_layout(size);
231
232 if mem::size_of::<T>() == 0 {
233 if size < old_size {
234 self.params.drop(&mut self.inner[size..old_size]);
235 }
236 self.inner.capacity = size;
237 return;
238 }
239
240 let ptr = unsafe {
241 match old_size {
242 0 => Self::alloc_zeroed(size).cast().as_ptr(),
243 _ => alloc::realloc(self.inner.ptr.cast().as_ptr(), old_layout, layout.size()),
244 }
245 };
246 let ptr = NonNull::new(ptr).expect("allocation failed").cast();
247
248 if size > old_size {
249 unsafe {
251 let index_zero: *mut T = ptr.as_ptr();
256 let start = index_zero.add(old_size);
257 let count = size - old_size;
258 ptr::write_bytes(start as *mut T, 0, count);
260 }
261 } else if size < old_size {
262 self.params.drop(&mut self.inner[size..old_size]);
264 }
265
266 self.inner.ptr = ptr;
267 self.inner.capacity = size;
268 }
269
270 fn free(&mut self) {
271 if mem::size_of::<T>() > 0 && self.capacity() > 0 {
275 let layout = Self::make_layout(self.capacity());
276 unsafe {
277 alloc::dealloc(self.inner.ptr.cast().as_ptr(), layout);
278 }
279 self.inner.ptr = NonNull::dangling();
280 }
281 self.inner.capacity = 0;
282 }
283
284 fn make_layout(size: usize) -> Layout {
285 let total_size = mem::size_of::<T>().checked_mul(size).expect("capacity overflow");
286 Layout::from_size_align(total_size, mem::align_of::<T>()).expect("layout error")
287 }
288
289 pub unsafe fn default_value() -> T {
300 mem::zeroed()
301 }
302}
303
304impl<T, P: Params<T>> Drop for ZeroBuf<T, P> {
305 fn drop(&mut self) {
306 self.resize(0)
307 }
308}
309
310impl<T> Default for ZeroBuf<T> {
311 fn default() -> Self {
312 Self::new()
313 }
314}
315
316impl<T, P: Params<T> + Default> Default for ZeroBuf<T, P> {
317 fn default() -> Self {
318 Self::new_with_params(P::default())
319 }
320}
321
322impl<T, P: Params<T>> ops::Deref for ZeroBuf<T, P> {
323 type Target = [T];
324
325 fn deref(&self) -> &[T] {
326 self.as_slice()
327 }
328}
329
330impl<T, P: Params<T>> ops::DerefMut for ZeroBuf<T, P> {
331 fn deref_mut(&mut self) -> &mut [T] {
332 self.as_slice_mut()
333 }
334}
335
336impl<T, I> ops::Index<I> for ZeroBuf<T>
337where
338 I: slice::SliceIndex<[T]>,
339{
340 type Output = I::Output;
341
342 #[inline]
343 fn index(&self, index: I) -> &Self::Output {
344 ops::Index::index(&**self, index)
345 }
346}
347
348impl<T, I> ops::IndexMut<I> for ZeroBuf<T>
349where
350 I: slice::SliceIndex<[T]>,
351{
352 #[inline]
353 fn index_mut(&mut self, index: I) -> &mut Self::Output {
354 ops::IndexMut::index_mut(&mut **self, index)
355 }
356}
357
358#[cfg(test)]
359mod tests {
360 use super::*;
361 use std::fmt::Debug;
362
363 fn check_what_is_zero<T: Clone + Debug + PartialEq>() -> T {
364 let b = ZeroBuf::<T>::with_capacity(1);
365 let z = b[0].clone();
366 assert_eq!(z, unsafe { mem::zeroed() });
367 z
368 }
369
370 #[test]
371 fn zero_value_primitives() {
372 assert_eq!(check_what_is_zero::<u8>(), 0);
373 assert_eq!(check_what_is_zero::<u16>(), 0);
374 assert_eq!(check_what_is_zero::<u32>(), 0);
375 assert_eq!(check_what_is_zero::<u64>(), 0);
376 assert_eq!(check_what_is_zero::<u128>(), 0);
377 assert_eq!(check_what_is_zero::<i8>(), 0);
378 assert_eq!(check_what_is_zero::<i16>(), 0);
379 assert_eq!(check_what_is_zero::<i32>(), 0);
380 assert_eq!(check_what_is_zero::<i64>(), 0);
381 assert_eq!(check_what_is_zero::<i128>(), 0);
382 assert_eq!(check_what_is_zero::<bool>(), false);
383 assert_eq!(check_what_is_zero::<char>(), '\x00');
384 }
385
386 #[test]
387 fn zero_value_pointers() {
388 use std::rc::Rc;
389 assert_eq!(check_what_is_zero::<Option<Rc<String>>>(), None);
390 assert_eq!(check_what_is_zero::<Option<String>>(), None);
391 assert_eq!(check_what_is_zero::<Option<Vec<u8>>>(), None);
392 }
393
394 #[test]
395 fn resize_to_zero() {
396 let mut b: ZeroBuf<u8> = ZeroBuf::with_capacity(1);
398 b.resize(0);
399 assert_eq!(b.capacity(), 0);
400
401 let mut b: ZeroBuf<u8> = ZeroBuf::new();
403 b.resize(0);
404 assert_eq!(b.capacity(), 0);
405 }
406
407 #[test]
408 fn simulate_push() {
409 let mut b: ZeroBuf<u8> = ZeroBuf::with_capacity(0);
411 let mut v = vec![];
412
413 let push = |b: &mut ZeroBuf<u8>, value| {
414 let cap = b.capacity();
415 b.resize(cap + 1);
416 b[cap] = value;
417 };
418
419 assert_eq!(b[..], v[..]);
420 push(&mut b, 1);
421 v.push(1);
422 assert_eq!(b[..], v[..]);
423 push(&mut b, 3);
424 v.push(3);
425 assert_eq!(b[..], v[..]);
426 for i in 0..100 {
427 push(&mut b, i);
428 v.push(i);
429 assert_eq!(b[..], v[..]);
430 }
431 }
432
433 #[test]
434 fn growth() {
435 let mut b: ZeroBuf<u32> = ZeroBuf::with_capacity(0);
436 let incr = |b: &mut ZeroBuf<u32>| {
437 for x in b.iter_mut() {
438 *x += 1;
439 }
440 };
441 let n = 10;
442 for _ in 0..n {
443 b.grow();
444 incr(&mut b);
445 }
446 assert!(b.capacity() > 0);
447 assert_eq!(b.iter().fold(0, |acc, x| acc + x), (1 << n) - 1);
449 }
450
451 #[test]
452 fn destructor() {
453 use std::rc::Rc;
454 let c = 16;
455 let mut b: ZeroBuf<Option<Rc<String>>> = ZeroBuf::with_capacity(c);
456 let hi = Rc::new(String::from("Hi"));
457 assert_eq!(Rc::strong_count(&hi), 1);
458
459 for x in b.iter_mut() {
460 *x = Some(Rc::clone(&hi));
461 }
462
463 assert_eq!(Rc::strong_count(&hi), c + 1);
464
465 b.resize(c - 1);
467 assert_eq!(Rc::strong_count(&hi), c + 1 - 1);
468
469 mem::drop(b);
471 assert_eq!(Rc::strong_count(&hi), 1);
472 }
473
474 #[test]
475 fn zero_sized() {
476 struct Foo;
477
478 impl Drop for Foo {
479 fn drop(&mut self) {
480 println!("Dropping!");
481 }
482 }
483
484 let mut b: ZeroBuf<Foo> = ZeroBuf::with_capacity(10);
485 assert_eq!(b.capacity(), 10);
486
487 b.resize(15);
488 assert_eq!(b.capacity(), 15);
489
490 b.resize(0);
491 assert_eq!(b.capacity(), 0);
492 }
493
494 #[test]
495 fn hash_equal() {
496 use std::hash::{Hash, Hasher};
497 use std::collections::hash_map::DefaultHasher;
498
499 fn hash_u64<T: Hash>(x: &T) -> u64 {
500 let mut h = DefaultHasher::new();
501 x.hash(&mut h);
502 h.finish()
503 }
504
505 let a: ZeroBuf<u8> = ZeroBuf::new();
506 let b: ZeroBuf<u8> = ZeroBuf::new();
507 assert_eq!(hash_u64(&a), hash_u64(&b));
508
509 let a: ZeroBuf<u8> = ZeroBuf::with_capacity(10);
510 let mut b: ZeroBuf<u8> = ZeroBuf::with_capacity(10);
511 assert_eq!(hash_u64(&a), hash_u64(&b));
512
513 b[2] = 99;
516 assert!(hash_u64(&a) != hash_u64(&b));
517 }
518}