lessvec/lib.rs
1//! A minimal `Vec`-like collection implemented with manual allocation.
2//!
3//! This crate provides `LessVec<T>`, a small, educational reimplementation of
4//! `std::vec::Vec<T>` following patterns from the Rustonomicon. It's intended
5//! for learning and small use-cases, not as a drop-in replacement for `Vec`.
6//!
7//! # Examples
8//! ```
9//! use lessvec::LessVec;
10//!
11//! let mut v = LessVec::new();
12//! v.push(1);
13//! v.push(2);
14//! assert_eq!(&*v, &[1, 2]);
15//! assert_eq!(v.pop(), Some(2));
16//! ```
17//!
18//! See individual method docs for more examples.
19use std::{
20 alloc::{self, Layout},
21 marker::PhantomData,
22 mem,
23 ops::{Deref, DerefMut},
24 ptr::{self, NonNull},
25};
26
27mod macros;
28
29/// Re-exports a small "prelude" of the most commonly-used items.
30///
31/// The prelude provides:
32/// - `LessVec` — the vector type
33/// - `lessvec!` — the convenient macro (same syntax as `vec!`)
34///
35/// Bring them into scope with:
36///
37/// ```
38/// use lessvec::prelude::*;
39///
40/// let v = lessvec![1, 2, 3];
41/// assert_eq!(v.as_slice(), &[1, 2, 3]);
42/// ```
43pub mod prelude {
44 pub use crate::LessVec;
45 pub use crate::lessvec;
46}
47
48struct RawVec<T> {
49 ptr: NonNull<T>,
50 cap: usize,
51}
52
53unsafe impl<T: Send> Send for RawVec<T> {}
54unsafe impl<T: Sync> Sync for RawVec<T> {}
55
56impl<T> RawVec<T> {
57 fn new() -> Self {
58 let cap = if mem::size_of::<T>() == 0 {
59 usize::MAX
60 } else {
61 0
62 };
63
64 // `NonNull::dangling` doubles as "unallocated" and "zero-sized allocation"
65 RawVec {
66 ptr: NonNull::dangling(),
67 cap,
68 }
69 }
70
71 fn grow(&mut self) {
72 // since we set the capacity to usize::MAX when T has size 0, getting
73 // to here means Vec is overfull.
74 assert!(mem::size_of::<T>() != 0, "capacity overflow");
75
76 let (new_cap, new_layout) = if self.cap == 0 {
77 (1, Layout::array::<T>(1).unwrap())
78 } else {
79 // `new_cap` will not overflow because `self.cap <= isize::MAX`.
80 let new_cap = 2 * self.cap;
81
82 // `Layout::array` checks that the number of bytes is <= usize::MAX,
83 // but this is redundant since old_layout.size() <= isize::MAX,
84 // `unwrap` should never fail.
85 let new_layout = Layout::array::<T>(new_cap).unwrap();
86 (new_cap, new_layout)
87 };
88
89 // Ensure that the new allocation doesn't overflow; <= isize::MAX bytes.
90 assert!(
91 new_layout.size() <= isize::MAX as usize,
92 "Allocation too large"
93 );
94
95 let new_ptr = if self.cap == 0 {
96 unsafe { alloc::alloc(new_layout) }
97 } else {
98 let old_layout = Layout::array::<T>(self.cap).unwrap();
99 let old_ptr = self.ptr.as_ptr() as *mut u8;
100 unsafe { alloc::realloc(old_ptr, old_layout, new_layout.size()) }
101 };
102
103 // new_ptr becomes null if allocation fails, abort.
104 self.ptr = match NonNull::new(new_ptr as *mut T) {
105 Some(p) => p,
106 None => alloc::handle_alloc_error(new_layout),
107 };
108
109 self.cap = new_cap;
110 }
111
112 fn grow_to(&mut self, new_cap: usize) {
113 if mem::size_of::<T>() == 0 {
114 return;
115 }
116 if new_cap <= self.cap {
117 return;
118 }
119
120 let new_layout = Layout::array::<T>(new_cap).unwrap();
121 assert!(
122 new_layout.size() <= isize::MAX as usize,
123 "Allocation too large"
124 );
125
126 let new_ptr = if self.cap == 0 {
127 unsafe { alloc::alloc(new_layout) }
128 } else {
129 let old_layout = Layout::array::<T>(self.cap).unwrap();
130 let old_tr = self.ptr.as_ptr() as *mut u8;
131 unsafe { alloc::realloc(old_tr, old_layout, new_layout.size()) }
132 };
133
134 self.ptr = match NonNull::new(new_ptr as *mut T) {
135 Some(p) => p,
136 None => alloc::handle_alloc_error(new_layout),
137 };
138
139 self.cap = new_cap;
140 }
141}
142
143impl<T> Drop for RawVec<T> {
144 fn drop(&mut self) {
145 if self.cap != 0 && std::mem::size_of::<T>() > 0 {
146 let layout = std::alloc::Layout::array::<T>(self.cap).unwrap();
147 unsafe {
148 std::alloc::dealloc(self.ptr.as_ptr() as *mut _, layout);
149 }
150 }
151 }
152}
153
154/// A minimal growable contiguous vector.
155///
156/// `LessVec<T>` stores elements in a heap buffer and supports a small set of
157/// `Vec`-like operations. Use the methods below to manipulate the collection.
158///
159/// # Examples
160///
161/// ```
162/// use lessvec::LessVec;
163///
164/// let mut v = LessVec::new();
165/// v.push(10);
166/// v.push(20);
167/// assert_eq!(v.len(), 2);
168/// assert!(!v.is_empty());
169/// assert!(v.capacity() >= 2);
170/// ```
171pub struct LessVec<T> {
172 buf: RawVec<T>,
173 len: usize,
174}
175
176unsafe impl<T: Send> Send for LessVec<T> {}
177unsafe impl<T: Sync> Sync for LessVec<T> {}
178
179impl<T> Default for LessVec<T> {
180 fn default() -> Self {
181 Self::new()
182 }
183}
184
185impl<T> LessVec<T> {
186 fn ptr(&self) -> *mut T {
187 self.buf.ptr.as_ptr()
188 }
189
190 fn cap(&self) -> usize {
191 self.buf.cap
192 }
193
194 /// Creates a new, empty `LessVec`.
195 ///
196 /// # Examples
197 ///
198 /// ```
199 /// use lessvec::LessVec;
200 /// let v: LessVec<i32> = LessVec::new();
201 /// assert_eq!(v.len(), 0);
202 /// ```
203 pub fn new() -> Self {
204 LessVec {
205 buf: RawVec::new(),
206 len: 0,
207 }
208 }
209
210 /// Returns the number of elements in the vector.
211 ///
212 /// # Examples
213 ///
214 /// ```
215 /// use lessvec::LessVec;
216 /// let mut v = LessVec::new();
217 /// v.push(1);
218 /// assert_eq!(v.len(), 1);
219 /// ```
220 pub fn len(&self) -> usize {
221 self.len
222 }
223
224 /// Returns `true` if the vector contains no elements.
225 ///
226 /// # Examples
227 ///
228 /// ```
229 /// use lessvec::LessVec;
230 /// let mut v = LessVec::new();
231 /// assert!(v.is_empty());
232 /// v.push(1);
233 /// assert!(!v.is_empty());
234 /// ```
235 pub fn is_empty(&self) -> bool {
236 self.len == 0
237 }
238
239 /// Returns the number of elements the `LessVec` can hold without reallocating.
240 ///
241 /// Note: capacity may be larger than the number of elements. Calling
242 /// `reserve` or `reserve_exact` increases capacity.
243 ///
244 /// # Examples
245 ///
246 /// ```
247 /// use lessvec::LessVec;
248 /// let mut v: LessVec<i32> = LessVec::new();
249 /// v.reserve(5);
250 /// assert!(v.capacity() >= 5);
251 /// ```
252 pub fn capacity(&self) -> usize {
253 self.cap()
254 }
255
256 /// Clears the vector, removing all values.
257 ///
258 /// This drops each element in the vector.
259 ///
260 /// # Examples
261 ///
262 /// ```
263 /// use lessvec::LessVec;
264 /// let mut v = LessVec::new();
265 /// v.push(1);
266 /// v.clear();
267 /// assert!(v.is_empty());
268 /// ```
269 pub fn clear(&mut self) {
270 while self.pop().is_some() {}
271 }
272
273 /// Returns a slice containing all elements of the vector.
274 ///
275 /// # Examples
276 ///
277 /// ```
278 /// use lessvec::LessVec;
279 /// let mut v = LessVec::new();
280 /// v.push(1);
281 /// assert_eq!(v.as_slice(), &[1]);
282 /// ```
283 pub fn as_slice(&self) -> &[T] {
284 self
285 }
286
287 /// Returns a mutable slice containing all elements of the vector.
288 ///
289 /// # Examples
290 ///
291 /// ```
292 /// use lessvec::LessVec;
293 /// let mut v = LessVec::new();
294 /// v.push(1);
295 /// v.as_mut_slice()[0] = 2;
296 /// assert_eq!(v.as_slice(), &[2]);
297 /// ```
298 pub fn as_mut_slice(&mut self) -> &mut [T] {
299 &mut *self
300 }
301
302 /// Ensures the `LessVec` can hold at least `additional` more elements without reallocating.
303 ///
304 /// This grows capacity exponentially where necessary.
305 ///
306 /// # Examples
307 ///
308 /// ```
309 /// use lessvec::LessVec;
310 /// let mut v: LessVec<i32> = LessVec::new();
311 /// v.reserve(10);
312 /// assert!(v.capacity() >= 10);
313 /// ```
314 pub fn reserve(&mut self, additional: usize) {
315 let required = self.len.checked_add(additional).expect("capacity overflow");
316 if self.cap() >= required {
317 return;
318 }
319 while self.cap() < required {
320 self.buf.grow();
321 }
322 }
323
324 /// Ensures the `LessVec` has capacity for exactly `additional` more elements (no fewer).
325 ///
326 /// Unlike `reserve`, this attempts to allocate the exact requested capacity in one go.
327 ///
328 /// # Examples
329 ///
330 /// ```
331 /// use lessvec::LessVec;
332 /// let mut v: LessVec<i32> = LessVec::new();
333 /// v.reserve_exact(3);
334 /// assert!(v.capacity() >= 3);
335 /// ```
336 pub fn reserve_exact(&mut self, additional: usize) {
337 let required = self.len.checked_add(additional).expect("capacity overflow");
338 if self.cap() >= required {
339 return;
340 }
341 self.buf.grow_to(required);
342 }
343
344 /// Appends an element to the back of the collection.
345 ///
346 /// # Examples
347 ///
348 /// ```
349 /// use lessvec::LessVec;
350 /// let mut v = LessVec::new();
351 /// v.push(5);
352 /// assert_eq!(v.len(), 1);
353 /// assert_eq!(v.as_slice(), &[5]);
354 /// ```
355 pub fn push(&mut self, elem: T) {
356 if self.len == self.cap() {
357 self.buf.grow();
358 }
359
360 unsafe {
361 ptr::write(self.ptr().add(self.len), elem);
362 }
363
364 // This operation will not fail, we will get OOM first.
365 self.len += 1;
366 }
367
368 /// Removes the last element and returns it, or `None` if empty.
369 ///
370 /// # Examples
371 ///
372 /// ```
373 /// use lessvec::LessVec;
374 /// let mut v = LessVec::new();
375 /// v.push(10);
376 /// assert_eq!(v.pop(), Some(10));
377 /// assert_eq!(v.pop(), None);
378 /// ```
379 pub fn pop(&mut self) -> Option<T> {
380 if self.len == 0 {
381 None
382 } else {
383 self.len -= 1;
384 unsafe { Some(ptr::read(self.ptr().add(self.len))) }
385 }
386 }
387
388 /// Inserts an element at `index`, shifting elements to the right.
389 ///
390 /// # Panics
391 ///
392 /// Panics if `index > len`.
393 ///
394 /// # Examples
395 ///
396 /// ```
397 /// use lessvec::LessVec;
398 /// let mut v = LessVec::new();
399 /// v.push(1);
400 /// v.push(3);
401 /// v.insert(1, 2);
402 /// assert_eq!(v.as_slice(), &[1, 2, 3]);
403 /// ```
404 pub fn insert(&mut self, index: usize, elem: T) {
405 assert!(index <= self.len, "index out of bounds");
406 if self.len == self.cap() {
407 self.buf.grow();
408 }
409
410 unsafe {
411 ptr::copy(
412 self.ptr().add(index),
413 self.ptr().add(index + 1),
414 self.len - index,
415 );
416 ptr::write(self.ptr().add(index), elem);
417 }
418
419 self.len += 1;
420 }
421
422 /// Removes and returns the element at `index`, shifting elements left.
423 ///
424 /// # Panics
425 ///
426 /// Panics if `index >= len`.
427 ///
428 /// # Examples
429 ///
430 /// ```
431 /// use lessvec::LessVec;
432 /// let mut v = LessVec::new();
433 /// v.push(1);
434 /// v.push(2);
435 /// assert_eq!(v.remove(0), 1);
436 /// assert_eq!(v.as_slice(), &[2]);
437 /// ```
438 pub fn remove(&mut self, index: usize) -> T {
439 assert!(index < self.len, "index out of bounds");
440 unsafe {
441 self.len -= 1;
442 let result = ptr::read(self.ptr().add(index));
443 ptr::copy(
444 self.ptr().add(index + 1),
445 self.ptr().add(index),
446 self.len - index,
447 );
448 result
449 }
450 }
451
452 /// Removes all elements and returns an iterator that yields the removed elements.
453 ///
454 /// The vector's length is set to zero immediately; elements are yielded by the returned iterator.
455 ///
456 /// # Examples
457 ///
458 /// ```
459 /// use lessvec::LessVec;
460 /// let mut v = LessVec::new();
461 /// v.push(10);
462 /// v.push(20);
463 /// let drained: Vec<_> = v.drain().collect();
464 /// assert_eq!(drained, vec![10, 20]);
465 /// assert!(v.is_empty());
466 /// ```
467 pub fn drain(&'_ mut self) -> Drain<'_, T> {
468 let iter = unsafe { RawValIter::new(self) };
469
470 self.len = 0;
471
472 Drain {
473 iter,
474 vec: PhantomData,
475 }
476 }
477}
478
479impl<T> Drop for LessVec<T> {
480 fn drop(&mut self) {
481 if self.len != 0 {
482 // deallocation is handled by RawVec
483 while self.pop().is_some() {}
484 }
485 }
486}
487
488impl<T> Deref for LessVec<T> {
489 type Target = [T];
490 fn deref(&self) -> &[T] {
491 unsafe { std::slice::from_raw_parts(self.ptr(), self.len) }
492 }
493}
494
495impl<T> DerefMut for LessVec<T> {
496 fn deref_mut(&mut self) -> &mut [T] {
497 unsafe { std::slice::from_raw_parts_mut(self.ptr(), self.len) }
498 }
499}
500
501struct RawValIter<T> {
502 start: *const T,
503 end: *const T,
504}
505
506impl<T> RawValIter<T> {
507 // unsafe construct because it has no associated lifetimes. This is
508 // necessary to store RawValIter as in the same struct as its actual
509 // allocation. OK to use since it's a private implementation detail.
510 unsafe fn new(slice: &[T]) -> Self {
511 RawValIter {
512 start: slice.as_ptr(),
513 end: if mem::size_of::<T>() == 0 {
514 ((slice.as_ptr() as usize) + slice.len()) as *const _
515 } else if slice.is_empty() {
516 slice.as_ptr()
517 } else {
518 unsafe { slice.as_ptr().add(slice.len()) }
519 },
520 }
521 }
522}
523
524impl<T> Iterator for RawValIter<T> {
525 type Item = T;
526 fn next(&mut self) -> Option<T> {
527 if self.start == self.end {
528 None
529 } else {
530 unsafe {
531 if mem::size_of::<T>() == 0 {
532 self.start = (self.start as usize + 1) as *const _;
533 Some(ptr::read(NonNull::<T>::dangling().as_ptr()))
534 } else {
535 let old_ptr = self.start;
536 self.start = self.start.offset(1);
537 Some(ptr::read(old_ptr))
538 }
539 }
540 }
541 }
542
543 fn size_hint(&self) -> (usize, Option<usize>) {
544 let elem_size = mem::size_of::<T>();
545 let len =
546 (self.end as usize - self.start as usize) / if elem_size == 0 { 1 } else { elem_size };
547
548 (len, Some(len))
549 }
550}
551
552impl<T> DoubleEndedIterator for RawValIter<T> {
553 fn next_back(&mut self) -> Option<T> {
554 if self.start == self.end {
555 None
556 } else {
557 unsafe {
558 if mem::size_of::<T>() == 0 {
559 self.end = (self.end as usize - 1) as *const _;
560 Some(ptr::read(NonNull::<T>::dangling().as_ptr()))
561 } else {
562 self.end = self.end.offset(-1);
563 Some(ptr::read(self.end))
564 }
565 }
566 }
567 }
568}
569
570/// Iterator that yields values by value when consuming a `LessVec`.
571///
572/// # Examples
573///
574/// ```
575/// use lessvec::LessVec;
576/// let mut v = LessVec::new();
577/// v.push(1);
578/// v.push(2);
579/// let out: Vec<_> = v.into_iter().collect();
580/// assert_eq!(out, vec![1, 2]);
581/// ```
582pub struct IntoIter<T> {
583 _buf: RawVec<T>,
584 iter: RawValIter<T>,
585}
586
587impl<T> Iterator for IntoIter<T> {
588 type Item = T;
589 fn next(&mut self) -> Option<T> {
590 self.iter.next()
591 }
592
593 fn size_hint(&self) -> (usize, Option<usize>) {
594 self.iter.size_hint()
595 }
596}
597
598impl<T> DoubleEndedIterator for IntoIter<T> {
599 fn next_back(&mut self) -> Option<T> {
600 self.iter.next_back()
601 }
602}
603
604impl<T> Drop for IntoIter<T> {
605 fn drop(&mut self) {
606 for _ in &mut *self {}
607 }
608}
609
610impl<T> IntoIterator for LessVec<T> {
611 type Item = T;
612 type IntoIter = IntoIter<T>;
613 fn into_iter(self) -> IntoIter<T> {
614 unsafe {
615 let iter = RawValIter::new(&self);
616
617 let buf = ptr::read(&self.buf);
618 mem::forget(self);
619
620 IntoIter { _buf: buf, iter }
621 }
622 }
623}
624
625/// An iterator produced by `LessVec::drain`.
626///
627/// Iterates over and yields the drained elements by value.
628///
629/// # Examples
630///
631/// ```
632/// use lessvec::LessVec;
633/// let mut v = LessVec::new();
634/// v.push(1);
635/// v.push(2);
636/// let drained: Vec<_> = v.drain().collect();
637/// assert_eq!(drained, vec![1, 2]);
638/// ```
639pub struct Drain<'a, T: 'a> {
640 vec: PhantomData<&'a mut LessVec<T>>,
641 iter: RawValIter<T>,
642}
643
644impl<'a, T> Iterator for Drain<'a, T> {
645 type Item = T;
646 fn next(&mut self) -> Option<T> {
647 self.iter.next()
648 }
649
650 fn size_hint(&self) -> (usize, Option<usize>) {
651 self.iter.size_hint()
652 }
653}
654
655impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
656 fn next_back(&mut self) -> Option<Self::Item> {
657 self.iter.next_back()
658 }
659}
660
661impl<'a, T> Drop for Drain<'a, T> {
662 fn drop(&mut self) {
663 for _ in &mut *self {}
664 }
665}
666
667#[cfg(test)]
668mod tests {
669 use crate::prelude::*;
670
671 #[test]
672 fn push_pop_roundtrip() {
673 let mut v = LessVec::new();
674 v.push(1);
675 v.push(2);
676 v.push(3);
677
678 assert_eq!(v.pop(), Some(3));
679 assert_eq!(v.pop(), Some(2));
680 assert_eq!(v.pop(), Some(1));
681 assert_eq!(v.pop(), None);
682 }
683
684 #[test]
685 fn insert_remove() {
686 let mut v = LessVec::new();
687 v.push(1);
688 v.push(3);
689 v.insert(1, 2);
690
691 assert_eq!(&*v, &[1, 2, 3]);
692 assert_eq!(v.remove(1), 2);
693 assert_eq!(&*v, &[1, 3]);
694 }
695
696 #[test]
697 fn drain_consumes_elements() {
698 let mut v = LessVec::new();
699 v.push(10);
700 v.push(20);
701 v.push(30);
702
703 let drained: Vec<_> = v.drain().collect();
704 assert_eq!(drained, vec![10, 20, 30]);
705 assert_eq!(&*v, &[]);
706 }
707
708 #[test]
709 fn into_iter_works() {
710 let mut v = LessVec::new();
711 v.push(1);
712 v.push(2);
713 v.push(3);
714
715 let collected: Vec<_> = v.into_iter().collect();
716 assert_eq!(collected, vec![1, 2, 3]);
717 }
718
719 #[test]
720 fn reserve_and_capacity() {
721 let mut v: LessVec<i32> = LessVec::new();
722 v.reserve(5);
723 assert!(v.capacity() >= 5);
724 v.reserve_exact(10);
725 assert!(v.capacity() >= 10);
726 }
727
728 #[test]
729 fn clear_works() {
730 let mut v = LessVec::new();
731 v.push(1);
732 v.clear();
733 assert!(v.is_empty());
734 }
735
736 #[test]
737 fn as_slice_and_mut() {
738 let mut v = LessVec::new();
739 v.push(1);
740 assert_eq!(v.as_slice(), &[1]);
741 v.as_mut_slice()[0] = 2;
742 assert_eq!(v.as_slice(), &[2]);
743 }
744
745 #[test]
746 fn macro_basic() {
747 let v = lessvec![1, 2, 3];
748 assert_eq!(&*v, &[1, 2, 3]);
749 }
750
751 #[test]
752 fn macro_empty() {
753 let v: LessVec<i32> = lessvec![];
754 assert_eq!(v.len(), 0);
755 }
756
757 #[test]
758 fn macro_repeat() {
759 let v = lessvec![5; 3];
760 assert_eq!(&*v, &[5, 5, 5]);
761 }
762}