use crate::{Rc, RefCell, Vec, vec_ as vec};
#[cfg(test)]
mod tests;
#[doc = crate::_tags!(data_structure)]
#[doc = crate::_doc_location!("data/layout/array")]
#[doc = crate::_doc!(vendor: "tailcall-chunk")]
#[must_use]
#[derive(Clone)]
#[allow(missing_debug_implementations, reason = "unsatisfied trait bounds")]
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>>),
}
impl<A> Default for VecChunk<A> {
fn default() -> Self {
VecChunk::Empty
}
}
impl<A> VecChunk<A> {
pub fn new(a: A) -> Self {
VecChunk::Single(a)
}
pub fn is_null(&self) -> bool {
match self {
VecChunk::Empty => true,
VecChunk::Collect(vec) => vec.borrow().is_empty(),
_ => false,
}
}
pub fn append(self, a: A) -> Self {
self.concat(VecChunk::new(a))
}
pub fn prepend(self, a: A) -> Self {
if self.is_null() { VecChunk::new(a) } else { VecChunk::new(a).concat(self) }
}
pub fn concat(self, other: VecChunk<A>) -> VecChunk<A> {
match (self, other) {
(VecChunk::Empty, other) => other,
(this, VecChunk::Empty) => this,
(VecChunk::Single(a), VecChunk::Single(b)) => {
VecChunk::Collect(Rc::new(RefCell::new(vec![a, b])))
}
(VecChunk::Collect(vec), VecChunk::Single(a)) => {
if Rc::strong_count(&vec) == 1 {
vec.borrow_mut().push(a);
VecChunk::Collect(vec)
} else {
VecChunk::Concat(Rc::new(VecChunk::Collect(vec)), Rc::new(VecChunk::Single(a)))
}
}
(this, that) => VecChunk::Concat(Rc::new(this), Rc::new(that)),
}
}
pub fn transform(self, f: impl Fn(A) -> A + 'static) -> Self {
self.transform_flatten(move |a| VecChunk::new(f(a)))
}
pub fn materialize(self) -> VecChunk<A>
where
A: Clone,
{
VecChunk::Collect(Rc::new(RefCell::new(self.as_vec())))
}
pub fn transform_flatten(self, f: impl Fn(A) -> VecChunk<A> + 'static) -> Self {
VecChunk::TransformFlatten(Rc::new(self), Rc::new(f))
}
pub fn as_vec(&self) -> Vec<A>
where
A: Clone,
{
let mut vec = Vec::new();
self.as_vec_mut(&mut vec);
vec
}
pub fn as_vec_mut(&self, buf: &mut Vec<A>)
where
A: Clone,
{
match self {
VecChunk::Empty => {}
VecChunk::Single(a) => {
buf.push(a.clone());
}
VecChunk::Concat(a, b) => {
a.as_vec_mut(buf);
b.as_vec_mut(buf);
}
VecChunk::TransformFlatten(a, f) => {
let mut tmp = Vec::new();
a.as_vec_mut(&mut tmp);
for elem in tmp.into_iter() {
f(elem).as_vec_mut(buf);
}
}
VecChunk::Collect(vec) => {
buf.extend(vec.borrow().iter().cloned());
}
}
}
}
impl<A> FromIterator<A> for VecChunk<A> {
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
let vec: Vec<_> = iter.into_iter().collect();
VecChunk::Collect(Rc::new(RefCell::new(vec)))
}
}