diff --git a/src/collections/scoped_buffer.rs b/src/collections/scoped_buffer.rs index 0d5865bd6d7014a443f35c90c53f082ddd838ef8..7f5194cf31bc6ef317490d82f6dc413fb07e2272 100644 --- a/src/collections/scoped_buffer.rs +++ b/src/collections/scoped_buffer.rs @@ -7,27 +7,28 @@ /// /// It is unsafe because we're using pointers to circumvent borrowing rules in /// the name of code cleanliness. The correctness of use is checked in debug -/// mode. +/// mode at runtime. use std::iter::FromIterator; -pub(crate) struct ScopedBuffer { - pub inner: Vec, +macro_rules! hide { + ($v:block) => { + #[cfg(debug_assertions)] $v + }; + ($v:expr) => { + #[cfg(debug_assertions)] $v + }; } -/// A section of the buffer. Keeps track of where we started the section. When -/// done with the section one must call `into_vec` or `forget` to remove the -/// section from the underlying buffer. This will also be done upon dropping the -/// ScopedSection in case errors are being handled. -pub(crate) struct ScopedSection { - inner: *mut Vec, - start_size: u32, - #[cfg(debug_assertions)] cur_size: u32, +pub(crate) struct ScopedBuffer { + pub inner: Vec, } impl ScopedBuffer { pub(crate) fn with_capacity(capacity: usize) -> Self { - Self { inner: Vec::with_capacity(capacity) } + Self { + inner: Vec::with_capacity(capacity), + } } pub(crate) fn start_section(&mut self) -> ScopedSection { @@ -35,7 +36,7 @@ impl ScopedBuffer { ScopedSection { inner: &mut self.inner, start_size, - #[cfg(debug_assertions)] cur_size: start_size + #[cfg(debug_assertions)] cur_size: start_size, } } } @@ -61,18 +62,35 @@ impl Drop for ScopedBuffer { } } +/// A section of the buffer. Keeps track of where we started the section. When +/// done with the section one must call `into_vec` or `forget` to remove the +/// section from the underlying buffer. This will also be done upon dropping the +/// ScopedSection in case errors are being handled. +pub(crate) struct ScopedSection { + inner: *mut Vec, + start_size: u32, + #[cfg(debug_assertions)] cur_size: u32, +} + impl ScopedSection { #[inline] pub(crate) fn push(&mut self, value: T) { let vec = unsafe{&mut *self.inner}; - #[cfg(debug_assertions)] debug_assert_eq!(vec.len(), self.cur_size as usize, "trying to push onto section, but size is larger than expected"); + hide!(debug_assert_eq!( + vec.len(), self.cur_size as usize, + "trying to push onto section, but size is larger than expected" + )); vec.push(value); - #[cfg(debug_assertions)] { self.cur_size += 1; } + hide!(self.cur_size += 1); } + #[inline] pub(crate) fn len(&self) -> usize { let vec = unsafe{&mut *self.inner}; - #[cfg(debug_assertions)] debug_assert_eq!(vec.len(), self.cur_size as usize, "trying to get section length, but size is larger than expected"); + hide!(debug_assert_eq!( + vec.len(), self.cur_size as usize, + "trying to get section length, but size is larger than expected" + )); return vec.len() - self.start_size as usize; } @@ -80,13 +98,13 @@ impl ScopedSection { #[allow(unused_mut)] // used in debug mode pub(crate) fn forget(mut self) { let vec = unsafe{&mut *self.inner}; - #[cfg(debug_assertions)] { + hide!({ debug_assert_eq!( vec.len(), self.cur_size as usize, "trying to forget section, but size is larger than expected" ); self.cur_size = self.start_size; - } + }); vec.truncate(self.start_size as usize); } @@ -94,13 +112,13 @@ impl ScopedSection { #[allow(unused_mut)] // used in debug mode pub(crate) fn into_vec(mut self) -> Vec { let vec = unsafe{&mut *self.inner}; - #[cfg(debug_assertions)] { + hide!({ debug_assert_eq!( vec.len(), self.cur_size as usize, "trying to turn section into vec, but size is larger than expected" ); self.cur_size = self.start_size; - } + }); let section = Vec::from_iter(vec.drain(self.start_size as usize..)); section } @@ -116,12 +134,19 @@ impl ScopedSection { } } -impl std::ops::Index for ScopedSection { +impl std::ops::Index for ScopedSection { type Output = T; - fn index(&self, idx: usize) -> &Self::Output { + fn index(&self, index: usize) -> &Self::Output { let vec = unsafe{&*self.inner}; - return &vec[self.start_size as usize + idx] + return &vec[self.start_size as usize + index] + } +} + +impl std::ops::IndexMut for ScopedSection { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + let vec = unsafe{&mut *self.inner}; + return &mut vec[self.start_size as usize + index] } } @@ -129,11 +154,14 @@ impl std::ops::Index for ScopedSection { impl Drop for ScopedSection { fn drop(&mut self) { let vec = unsafe{&mut *self.inner}; - #[cfg(debug_assertions)] debug_assert_eq!(vec.len(), self.cur_size as usize); + hide!(debug_assert_eq!(vec.len(), self.cur_size as usize)); vec.truncate(self.start_size as usize); } } +/// Small utility for iterating over a section of the buffer. Same conditions as +/// the buffer apply: each time we retrieve an element the buffer must have the +/// same size as the moment of creation. pub(crate) struct ScopedIter { inner: *mut Vec, cur_index: u32, @@ -144,6 +172,7 @@ impl Iterator for ScopedIter { type Item = T; fn next(&mut self) -> Option { + hide!(debug_assert_eq!(self.last_index as usize, unsafe { (*self.inner).len() })); if self.cur_index >= self.last_index { return None; }