pub enum VecChunk<A> {
Empty,
Single(A),
Concat(Rc<VecChunk<A>>, Rc<VecChunk<A>>),
Collect(Rc<RefCell<Vec<A>>>),
TransformFlatten(Rc<VecChunk<A>>, Rc<dyn Fn(A) -> VecChunk<A>>),
}
alloc
only.Expand description
A persistent data structure that provides efficient append and concatenation operations.
§Overview
VecChunk<A>
is an immutable data structure that allows O(1) complexity for append and
concatenation operations through structural sharing. It uses Rc
(Reference Counting)
for efficient memory management.
§Performance
- Append operation: O(1)
- Concatenation operation: O(1)
- Converting to Vec: O(n)
§Implementation Details
The data structure is implemented as an enum with three variants:
Empty
: Represents an empty chunkAppend
: Represents a single element appended to another chunkConcat
: Represents the concatenation of two chunks
§Example
let mut chunk = VecChunk::default();
chunk = chunk.append(1);
chunk = chunk.append(2);
let other_chunk = VecChunk::default().append(3).append(4);
let combined = chunk.concat(other_chunk);
assert_eq!(combined.as_vec(), vec![1, 2, 3, 4]);
§References
§Derived Work
This is derived work from the
tailcall-chunk
crate,
including the following modifications:
- add
must_use
attribute. - make it
no_std
compatible. - rename the structure to
VecChunk
. - misc. refactoring.
Variants§
Empty
Represents an empty chunk with no elements
Single(A)
Represents a chunk containing exactly one element
Concat(Rc<VecChunk<A>>, Rc<VecChunk<A>>)
Represents the concatenation of two chunks, enabling O(1) concatenation
Collect(Rc<RefCell<Vec<A>>>)
Represents a collection of elements
TransformFlatten(Rc<VecChunk<A>>, Rc<dyn Fn(A) -> VecChunk<A>>)
Represents a lazy transformation that flattens elements
Implementations§
Source§impl<A> VecChunk<A>
impl<A> VecChunk<A>
Sourcepub fn is_null(&self) -> bool
pub fn is_null(&self) -> bool
Returns true
if the chunk is empty.
§Example
let chunk: VecChunk<i32> = VecChunk::default();
assert!(chunk.is_null());
let non_empty = chunk.append(42);
assert!(!non_empty.is_null());
Sourcepub fn concat(self, other: VecChunk<A>) -> VecChunk<A>
pub fn concat(self, other: VecChunk<A>) -> VecChunk<A>
Concatenates this chunk with another chunk.
This operation has O(1) complexity as it creates a new Concat
variant
that references both chunks through Rc
s.
§Performance Optimization
If either chunk is empty, returns the other chunk instead of creating
a new Concat
variant.
§Example
let chunk1 = VecChunk::default().append(1).append(2);
let chunk2 = VecChunk::default().append(3).append(4);
let combined = chunk1.concat(chunk2);
assert_eq!(combined.as_vec(), vec![1, 2, 3, 4]);
Sourcepub fn transform(self, f: impl Fn(A) -> A + 'static) -> Self
pub fn transform(self, f: impl Fn(A) -> A + 'static) -> Self
Transforms each element in the chunk using the provided function.
This method creates a lazy representation of the transformation without actually
performing it. The transformation is only executed when as_vec
or as_vec_mut
is called.
§Performance
- Creating the transformation: O(1)
- Executing the transformation (during
as_vec
): O(n)
§Arguments
f
- A function that takes a reference to an element of typeA
and returns a new element of typeA
§Example
let chunk = VecChunk::default().append(1).append(2).append(3);
// This operation is O(1) and doesn't actually transform the elements
let doubled = chunk.transform(|x| x * 2);
// The transformation happens here, when we call as_vec()
assert_eq!(doubled.as_vec(), vec![2, 4, 6]);
Sourcepub fn materialize(self) -> VecChunk<A>where
A: Clone,
pub fn materialize(self) -> VecChunk<A>where
A: Clone,
Materializes a chunk by converting it into a collected form.
This method evaluates any lazy transformations and creates a new chunk containing
all elements in a Collect
variant. This can be useful for performance when you
plan to reuse the chunk multiple times, as it prevents re-evaluation of transformations.
§Performance
- Time complexity: O(n) where n is the number of elements
- Space complexity: O(n) as it creates a new vector containing all elements
§Example
let chunk = VecChunk::default()
.append(1)
.append(2)
.transform(|x| x * 2); // Lazy transformation
// Materialize the chunk to evaluate the transformation once
let materialized = chunk.materialize();
assert_eq!(materialized.as_vec(), vec![2, 4]);
Sourcepub fn transform_flatten(self, f: impl Fn(A) -> VecChunk<A> + 'static) -> Self
pub fn transform_flatten(self, f: impl Fn(A) -> VecChunk<A> + 'static) -> Self
Transforms each element in the chunk into a new chunk and flattens the result.
This method creates a lazy representation of the transformation without actually
performing it. The transformation is only executed when as_vec
or as_vec_mut
is called.
§Performance
- Creating the transformation: O(1)
- Executing the transformation (during
as_vec
): O(n)
§Arguments
f
- A function that takes an element of typeA
and returns a newVecChunk<A>
§Example
let chunk = VecChunk::default().append(1).append(2);
// Transform each number x into a chunk containing [x, x+1]
let expanded = chunk.transform_flatten(|x| {
VecChunk::default().append(x).append(x + 1)
});
assert_eq!(expanded.as_vec(), vec![1, 2, 2, 3]);
Sourcepub fn as_vec(&self) -> Vec<A> ⓘwhere
A: Clone,
pub fn as_vec(&self) -> Vec<A> ⓘwhere
A: Clone,
Converts the chunk into a vector of references to its elements.
This operation has O(n) complexity where n is the number of elements in the chunk.
§Example
let chunk = VecChunk::default().append(1).append(2).append(3);
assert_eq!(chunk.as_vec(), vec![1, 2, 3]);
Sourcepub fn as_vec_mut(&self, buf: &mut Vec<A>)where
A: Clone,
pub fn as_vec_mut(&self, buf: &mut Vec<A>)where
A: Clone,
Trait Implementations§
Source§impl<A> Default for VecChunk<A>
impl<A> Default for VecChunk<A>
Source§fn default() -> Self
fn default() -> Self
Creates a new empty chunk.
This is equivalent to using VecChunk::Empty
.
Source§impl<A> FromIterator<A> for VecChunk<A>
impl<A> FromIterator<A> for VecChunk<A>
Source§fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self
Creates a chunk from an iterator.
§Example
let vec = vec![1, 2, 3];
let chunk: VecChunk<_> = vec.into_iter().collect();
assert_eq!(chunk.as_vec(), vec![1, 2, 3]);
Auto Trait Implementations§
impl<A> Freeze for VecChunk<A>where
A: Freeze,
impl<A> !RefUnwindSafe for VecChunk<A>
impl<A> !Send for VecChunk<A>
impl<A> !Sync for VecChunk<A>
impl<A> Unpin for VecChunk<A>where
A: Unpin,
impl<A> !UnwindSafe for VecChunk<A>
Blanket Implementations§
§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
§type ArchivedMetadata = ()
type ArchivedMetadata = ()
§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> ByteSized for T
impl<T> ByteSized for T
Source§const BYTE_ALIGN: usize = _
const BYTE_ALIGN: usize = _
Source§fn byte_align(&self) -> usize ⓘ
fn byte_align(&self) -> usize ⓘ
Source§fn ptr_size_ratio(&self) -> [usize; 2]
fn ptr_size_ratio(&self) -> [usize; 2]
Source§impl<T, R> Chain<R> for Twhere
T: ?Sized,
impl<T, R> Chain<R> for Twhere
T: ?Sized,
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> ExtAny for T
impl<T> ExtAny for T
Source§fn as_any_mut(&mut self) -> &mut dyn Anywhere
Self: Sized,
fn as_any_mut(&mut self) -> &mut dyn Anywhere
Self: Sized,
Source§impl<T> ExtMem for Twhere
T: ?Sized,
impl<T> ExtMem for Twhere
T: ?Sized,
Source§const NEEDS_DROP: bool = _
const NEEDS_DROP: bool = _
Source§fn mem_align_of_val(&self) -> usize ⓘ
fn mem_align_of_val(&self) -> usize ⓘ
Source§fn mem_size_of_val(&self) -> usize ⓘ
fn mem_size_of_val(&self) -> usize ⓘ
Source§fn mem_needs_drop(&self) -> bool
fn mem_needs_drop(&self) -> bool
true
if dropping values of this type matters. Read moreSource§fn mem_forget(self)where
Self: Sized,
fn mem_forget(self)where
Self: Sized,
self
without running its destructor. Read moreSource§fn mem_replace(&mut self, other: Self) -> Selfwhere
Self: Sized,
fn mem_replace(&mut self, other: Self) -> Selfwhere
Self: Sized,
Source§unsafe fn mem_zeroed<T>() -> T
unsafe fn mem_zeroed<T>() -> T
unsafe_layout
only.T
represented by the all-zero byte-pattern. Read moreSource§unsafe fn mem_transmute_copy<Src, Dst>(src: &Src) -> Dst
unsafe fn mem_transmute_copy<Src, Dst>(src: &Src) -> Dst
unsafe_layout
only.T
represented by the all-zero byte-pattern. Read moreSource§fn mem_as_bytes(&self) -> &[u8] ⓘ
fn mem_as_bytes(&self) -> &[u8] ⓘ
unsafe_slice
only.§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> Hook for T
impl<T> Hook for T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError> ⓘ
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError> ⓘ
§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out
indicating that a T
is niched.