#![doc = include_str!("../README.md")]
#![deny(missing_docs)]
use std::borrow::Borrow;
use std::fmt::{Debug, Formatter};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
pub mod impls;
pub use impls::columns::ColumnsRegion;
pub use impls::mirror::MirrorRegion;
pub use impls::option::OptionRegion;
pub use impls::result::ResultRegion;
pub use impls::slice::SliceRegion;
pub use impls::slice_copy::OwnedRegion;
pub use impls::string::StringRegion;
#[cfg(feature = "serde")]
pub trait Index: Copy + Serialize + for<'a> Deserialize<'a> {}
#[cfg(feature = "serde")]
impl<T: Copy + Serialize + for<'a> Deserialize<'a>> Index for T {}
#[cfg(not(feature = "serde"))]
pub trait Index: Copy {}
#[cfg(not(feature = "serde"))]
impl<T: Copy> Index for T {}
pub trait Region: Default {
type Owned;
type ReadItem<'a>: IntoOwned<'a, Owned = Self::Owned>
where
Self: 'a;
type Index: Index;
fn merge_regions<'a>(regions: impl Iterator<Item = &'a Self> + Clone) -> Self
where
Self: 'a;
#[must_use]
fn index(&self, index: Self::Index) -> Self::ReadItem<'_>;
fn reserve_regions<'a, I>(&mut self, regions: I)
where
Self: 'a,
I: Iterator<Item = &'a Self> + Clone;
fn clear(&mut self);
fn heap_size<F: FnMut(usize, usize)>(&self, callback: F);
#[must_use]
fn reborrow<'b, 'a: 'b>(item: Self::ReadItem<'a>) -> Self::ReadItem<'b>
where
Self: 'a;
}
pub trait RegionPreference {
type Owned;
type Region: Region<Owned = Self::Owned>;
}
impl<T: RegionPreference + ?Sized> RegionPreference for &T {
type Owned = T::Owned;
type Region = T::Region;
}
pub trait Push<T>: Region {
#[must_use]
fn push(&mut self, item: T) -> Self::Index;
}
pub trait ReserveItems<T>: Region {
fn reserve_items<I>(&mut self, items: I)
where
I: Iterator<Item = T> + Clone;
}
pub trait IntoOwned<'a> {
type Owned;
#[must_use]
fn into_owned(self) -> Self::Owned;
fn clone_onto(self, other: &mut Self::Owned);
#[must_use]
fn borrow_as(owned: &'a Self::Owned) -> Self;
}
impl<'a, T: ToOwned + ?Sized> IntoOwned<'a> for &'a T {
type Owned = T::Owned;
#[inline]
fn into_owned(self) -> Self::Owned {
self.to_owned()
}
#[inline]
fn clone_onto(self, other: &mut Self::Owned) {
<T as ToOwned>::clone_into(self, other)
}
#[inline]
fn borrow_as(owned: &'a Self::Owned) -> Self {
owned.borrow()
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(
feature = "serde",
serde(
bound = "R: Serialize + for<'a> Deserialize<'a>, R::Index: Serialize + for<'a> Deserialize<'a>"
)
)]
pub struct FlatStack<R: Region> {
indices: Vec<R::Index>,
region: R,
}
impl<R: Region> Default for FlatStack<R> {
#[inline]
fn default() -> Self {
Self {
indices: Vec::default(),
region: R::default(),
}
}
}
impl<R: Region> Debug for FlatStack<R>
where
for<'a> R::ReadItem<'a>: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<R: Region> FlatStack<R> {
#[inline]
#[must_use]
pub fn default_impl<T: RegionPreference<Region = R>>() -> Self {
Self::default()
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
indices: Vec::with_capacity(capacity),
region: R::default(),
}
}
#[must_use]
pub fn merge_capacity<'a, I: Iterator<Item = &'a Self> + Clone + 'a>(stacks: I) -> Self
where
R: 'a,
{
Self {
indices: Vec::with_capacity(stacks.clone().map(|s| s.indices.len()).sum()),
region: R::merge_regions(stacks.map(|r| &r.region)),
}
}
#[inline]
pub fn copy<T>(&mut self, item: T)
where
R: Push<T>,
{
let index = self.region.push(item);
self.indices.push(index);
}
#[inline]
#[must_use]
pub fn get(&self, offset: usize) -> R::ReadItem<'_> {
self.region.index(self.indices[offset])
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.indices.len()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.indices.is_empty()
}
#[must_use]
pub fn capacity(&self) -> usize {
self.indices.capacity()
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.indices.reserve(additional);
}
#[inline]
pub fn clear(&mut self) {
self.indices.clear();
self.region.clear();
}
#[inline]
pub fn reserve_items<T>(&mut self, items: impl Iterator<Item = T> + Clone)
where
R: ReserveItems<T>,
{
ReserveItems::reserve_items(&mut self.region, items);
}
#[inline]
pub fn reserve_regions<'a>(&mut self, regions: impl Iterator<Item = &'a R> + Clone)
where
R: 'a,
{
self.region.reserve_regions(regions);
}
#[inline]
pub fn iter(&self) -> Iter<'_, R> {
self.into_iter()
}
#[inline]
pub fn heap_size<F: FnMut(usize, usize)>(&self, mut callback: F) {
use crate::impls::offsets::OffsetContainer;
self.region.heap_size(&mut callback);
OffsetContainer::heap_size(&self.indices, callback);
}
}
impl<T, R: Region + Push<T>> Extend<T> for FlatStack<R> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
let iter = iter.into_iter();
self.reserve(iter.size_hint().0);
for item in iter {
self.indices.push(self.region.push(item));
}
}
}
impl<'a, R: Region> IntoIterator for &'a FlatStack<R> {
type Item = R::ReadItem<'a>;
type IntoIter = Iter<'a, R>;
fn into_iter(self) -> Self::IntoIter {
Iter {
inner: self.indices.iter(),
region: &self.region,
}
}
}
pub struct Iter<'a, R: Region> {
inner: std::slice::Iter<'a, R::Index>,
region: &'a R,
}
impl<'a, R: Region> Iterator for Iter<'a, R> {
type Item = R::ReadItem<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next().map(|idx| self.region.index(*idx))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<R: Region> ExactSizeIterator for Iter<'_, R> {}
impl<R: Region> Clone for Iter<'_, R> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
region: self.region,
}
}
}
impl<R: Region + Push<T>, T> FromIterator<T> for FlatStack<R> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let iter = iter.into_iter();
let mut c = Self::with_capacity(iter.size_hint().0);
c.extend(iter);
c
}
}
impl<R: Region + Clone> Clone for FlatStack<R> {
fn clone(&self) -> Self {
Self {
region: self.region.clone(),
indices: self.indices.clone(),
}
}
fn clone_from(&mut self, source: &Self) {
self.region.clone_from(&source.region);
self.indices.clone_from(&source.indices);
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub struct CopyIter<I>(pub I);
#[cfg(test)]
mod tests {
use crate::impls::deduplicate::{CollapseSequence, ConsecutiveOffsetPairs};
use crate::impls::tuple::TupleARegion;
use super::*;
fn copy<R: Region + Push<T>, T>(r: &mut R, item: T) -> R::Index {
r.push(item)
}
#[test]
fn test_readme() {
let r: Result<_, u16> = Ok("abc");
let mut c = FlatStack::default_impl::<Result<&str, u16>>();
c.copy(r);
assert_eq!(r, c.get(0));
}
#[test]
fn test_slice_string_onto() {
let mut c = <StringRegion>::default();
let index = c.push("abc".to_string());
assert_eq!("abc", c.index(index));
let index = c.push("def");
assert_eq!("def", c.index(index));
}
#[test]
fn test_container_string() {
let mut c = FlatStack::default_impl::<String>();
c.copy(&"abc".to_string());
assert_eq!("abc", c.get(0));
c.copy("def");
assert_eq!("def", c.get(1));
}
#[test]
fn test_vec() {
let mut c = <SliceRegion<MirrorRegion<_>>>::default();
let slice = &[1u8, 2, 3];
let idx = c.push(slice);
assert!(slice.iter().copied().eq(c.index(idx)));
}
#[test]
fn test_vec_onto() {
let mut c = <SliceRegion<MirrorRegion<u8>>>::default();
let slice = &[1u8, 2, 3][..];
let idx = c.push(slice);
assert!(slice.iter().copied().eq(c.index(idx)));
}
#[test]
fn test_result() {
let r: Result<_, u16> = Ok("abc");
let mut c = <ResultRegion<StringRegion, MirrorRegion<_>>>::default();
let idx = copy(&mut c, r);
assert_eq!(r, c.index(idx));
}
#[test]
fn all_types() {
fn test_copy<T, R: Region + Clone>(t: T)
where
for<'a> R: Push<T> + Push<<R as Region>::ReadItem<'a>>,
for<'a> R::ReadItem<'a>: Debug,
{
let mut c = FlatStack::default();
c.copy(t);
let mut cc = c.clone();
cc.copy(c.get(0));
c.clear();
let mut r = R::default();
let _ = r.push(cc.get(0));
c.reserve_regions(std::iter::once(&r));
let mut c = FlatStack::merge_capacity(std::iter::once(&c));
c.copy(cc.get(0));
}
test_copy::<_, StringRegion>(&"a".to_string());
test_copy::<_, StringRegion>("a".to_string());
test_copy::<_, StringRegion>("a");
test_copy::<_, MirrorRegion<()>>(());
test_copy::<_, MirrorRegion<()>>(&());
test_copy::<_, MirrorRegion<bool>>(true);
test_copy::<_, MirrorRegion<bool>>(&true);
test_copy::<_, MirrorRegion<char>>(' ');
test_copy::<_, MirrorRegion<char>>(&' ');
test_copy::<_, MirrorRegion<u8>>(0u8);
test_copy::<_, MirrorRegion<u8>>(&0u8);
test_copy::<_, MirrorRegion<u16>>(0u16);
test_copy::<_, MirrorRegion<u16>>(&0u16);
test_copy::<_, MirrorRegion<u32>>(0u32);
test_copy::<_, MirrorRegion<u32>>(&0u32);
test_copy::<_, MirrorRegion<u64>>(0u64);
test_copy::<_, MirrorRegion<u64>>(&0u64);
test_copy::<_, MirrorRegion<u128>>(0u128);
test_copy::<_, MirrorRegion<u128>>(&0u128);
test_copy::<_, MirrorRegion<usize>>(0usize);
test_copy::<_, MirrorRegion<usize>>(&0usize);
test_copy::<_, MirrorRegion<i8>>(0i8);
test_copy::<_, MirrorRegion<i8>>(&0i8);
test_copy::<_, MirrorRegion<i16>>(0i16);
test_copy::<_, MirrorRegion<i16>>(&0i16);
test_copy::<_, MirrorRegion<i32>>(0i32);
test_copy::<_, MirrorRegion<i32>>(&0i32);
test_copy::<_, MirrorRegion<i64>>(0i64);
test_copy::<_, MirrorRegion<i64>>(&0i64);
test_copy::<_, MirrorRegion<i128>>(0i128);
test_copy::<_, MirrorRegion<i128>>(&0i128);
test_copy::<_, MirrorRegion<isize>>(0isize);
test_copy::<_, MirrorRegion<isize>>(&0isize);
test_copy::<_, MirrorRegion<f32>>(0f32);
test_copy::<_, MirrorRegion<f32>>(&0f32);
test_copy::<_, MirrorRegion<f64>>(0f64);
test_copy::<_, MirrorRegion<f64>>(&0f64);
test_copy::<_, MirrorRegion<std::num::Wrapping<i8>>>(std::num::Wrapping(0i8));
test_copy::<_, MirrorRegion<std::num::Wrapping<i8>>>(&std::num::Wrapping(0i8));
test_copy::<_, MirrorRegion<std::num::Wrapping<i16>>>(std::num::Wrapping(0i16));
test_copy::<_, MirrorRegion<std::num::Wrapping<i16>>>(&std::num::Wrapping(0i16));
test_copy::<_, MirrorRegion<std::num::Wrapping<i32>>>(std::num::Wrapping(0i32));
test_copy::<_, MirrorRegion<std::num::Wrapping<i32>>>(&std::num::Wrapping(0i32));
test_copy::<_, MirrorRegion<std::num::Wrapping<i64>>>(std::num::Wrapping(0i64));
test_copy::<_, MirrorRegion<std::num::Wrapping<i64>>>(&std::num::Wrapping(0i64));
test_copy::<_, MirrorRegion<std::num::Wrapping<i128>>>(std::num::Wrapping(0i128));
test_copy::<_, MirrorRegion<std::num::Wrapping<i128>>>(&std::num::Wrapping(0i128));
test_copy::<_, MirrorRegion<std::num::Wrapping<isize>>>(std::num::Wrapping(0isize));
test_copy::<_, MirrorRegion<std::num::Wrapping<isize>>>(&std::num::Wrapping(0isize));
test_copy::<_, ResultRegion<MirrorRegion<u8>, MirrorRegion<u8>>>(Result::<u8, u8>::Ok(0));
test_copy::<_, ResultRegion<MirrorRegion<u8>, MirrorRegion<u8>>>(&Result::<u8, u8>::Ok(0));
test_copy::<_, ResultRegion<MirrorRegion<u8>, MirrorRegion<u8>>>(Result::<u8, u8>::Err(0));
test_copy::<_, ResultRegion<MirrorRegion<u8>, MirrorRegion<u8>>>(&Result::<u8, u8>::Err(0));
test_copy::<_, SliceRegion<MirrorRegion<u8>>>([0u8].as_slice());
test_copy::<_, SliceRegion<MirrorRegion<u8>>>(vec![0u8]);
test_copy::<_, SliceRegion<MirrorRegion<u8>>>(&vec![0u8]);
test_copy::<_, SliceRegion<StringRegion>>(["a"].as_slice());
test_copy::<_, SliceRegion<StringRegion>>(vec!["a"]);
test_copy::<_, SliceRegion<StringRegion>>(&vec!["a"]);
test_copy::<_, SliceRegion<TupleARegion<StringRegion>>>([("a",)].as_slice());
test_copy::<_, SliceRegion<TupleARegion<StringRegion>>>(vec![("a",)]);
test_copy::<_, SliceRegion<TupleARegion<StringRegion>>>(&vec![("a",)]);
test_copy::<_, OwnedRegion<_>>([0u8].as_slice());
test_copy::<_, OwnedRegion<_>>(&[0u8].as_slice());
test_copy::<_, <(u8, u8) as RegionPreference>::Region>((1, 2));
test_copy::<_, <(u8, u8) as RegionPreference>::Region>(&(1, 2));
test_copy::<_, ConsecutiveOffsetPairs<OwnedRegion<_>>>([1, 2, 3].as_slice());
test_copy::<_, CollapseSequence<OwnedRegion<_>>>([1, 2, 3].as_slice());
test_copy::<_, CollapseSequence<OwnedRegion<_>>>(&[1, 2, 3]);
test_copy::<_, OptionRegion<StringRegion>>(Some("abc"));
test_copy::<_, OptionRegion<StringRegion>>(&Some("abc"));
test_copy::<_, OptionRegion<StringRegion>>(Option::<&'static str>::None);
test_copy::<_, OptionRegion<StringRegion>>(&Option::<&'static str>::None);
test_copy::<_, ResultRegion<StringRegion, MirrorRegion<u8>>>(
Result::<&'static str, u8>::Ok("abc"),
);
test_copy::<_, ResultRegion<StringRegion, MirrorRegion<u8>>>(
&Result::<&'static str, u8>::Ok("abc"),
);
test_copy::<_, ResultRegion<StringRegion, MirrorRegion<u8>>>(
Result::<&'static str, u8>::Err(1),
);
test_copy::<_, ResultRegion<StringRegion, MirrorRegion<u8>>>(
Result::<&'static str, u8>::Err(2),
);
}
#[test]
fn slice_region_read_item() {
fn is_clone<T: Clone>(_: &T) {}
let mut c = FlatStack::<SliceRegion<MirrorRegion<u8>>>::default();
c.copy(vec![1, 2, 3]);
let mut r = SliceRegion::<MirrorRegion<u8>>::default();
let idx = r.push([1, 2, 3]);
let read_item = r.index(idx);
is_clone(&read_item);
let _read_item3 = read_item;
assert_eq!(vec![1, 2, 3], read_item.into_iter().collect::<Vec<_>>());
}
#[test]
fn nested_slice_copy() {
let mut c = FlatStack::default_impl::<[[[[[u8; 1]; 1]; 1]; 1]; 1]>();
c.copy([[[[[1]]]]]);
c.copy(&[[[[[1]]]]]);
c.copy(&[[[[[&1]]]]]);
c.copy([[[[[&1]]]]]);
c.copy([[&[[[&1]]]]]);
c.copy([[[[[1]]; 1]; 1]; 1]);
c.copy(&[[[[[1; 1]; 1]; 1]; 1]; 1]);
c.copy(&[[[[[&1; 1]; 1]; 1]; 1]; 1]);
c.copy([[[[[&1; 1]; 1]; 1]; 1]; 1]);
c.copy([[&[[[&1; 1]; 1]; 1]; 1]; 1]);
c.copy([[vec![[[1; 1]; 1]; 1]; 1]; 1]);
c.copy(&[[vec![[[1; 1]; 1]; 1]; 1]; 1]);
c.copy(&[[vec![[[&1; 1]; 1]; 1]; 1]; 1]);
c.copy([[[vec![[&1; 1]; 1]; 1]; 1]; 1]);
c.copy([[&vec![[[&1; 1]; 1]; 1]; 1]; 1]);
}
#[test]
fn test_owned() {
fn owned_roundtrip<R, O>(region: &mut R, index: R::Index)
where
for<'a> R: Region + Push<<<R as Region>::ReadItem<'a> as IntoOwned<'a>>::Owned>,
for<'a> R::ReadItem<'a>: IntoOwned<'a, Owned = O> + Eq + Debug,
{
let item = region.index(index);
let owned = item.into_owned();
let index2 = region.push(owned);
let item = region.index(index);
assert_eq!(item, region.index(index2));
}
let mut c = <StringRegion>::default();
let index = c.push("abc".to_string());
owned_roundtrip::<StringRegion, String>(&mut c, index);
}
fn _test_reborrow<R>(item: R::ReadItem<'_>, owned: &R::Owned)
where
R: Region,
for<'a> R::ReadItem<'a>: Eq,
{
let _ = R::reborrow(item) == R::reborrow(IntoOwned::borrow_as(owned));
}
}