use std::any::Any;
use std::ops::Deref;
use std::sync::Arc;
pub type Pin = Arc<dyn Any + Send + Sync>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Buffer<T> {
store: Store<T>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum Store<T> {
Owned(Vec<T>),
}
impl<T> Buffer<T> {
#[must_use]
pub fn new() -> Self {
Self { store: Store::Owned(Vec::new()) }
}
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self { store: Store::Owned(Vec::with_capacity(capacity)) }
}
#[must_use]
pub fn from_vec(values: Vec<T>) -> Self {
Self { store: Store::Owned(values) }
}
#[must_use]
pub fn footprint(&self) -> usize {
match &self.store {
Store::Owned(values) => values.capacity() * size_of::<T>(),
}
}
#[must_use]
#[inline]
pub fn as_slice(&self) -> &[T] {
match &self.store {
Store::Owned(values) => values,
}
}
#[must_use]
pub fn into_vec(self) -> Vec<T> {
match self.store {
Store::Owned(values) => values,
}
}
#[inline]
pub fn to_mut(&mut self) -> &mut Vec<T> {
match &mut self.store {
Store::Owned(values) => values,
}
}
#[inline]
pub fn push(&mut self, value: T) {
self.to_mut().push(value);
}
pub fn reserve(&mut self, additional: usize) {
self.to_mut().reserve(additional);
}
}
impl<T: Clone> Buffer<T> {
pub fn extend_from_slice(&mut self, values: &[T]) {
self.to_mut().extend_from_slice(values);
}
}
impl<T> Default for Buffer<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Deref for Buffer<T> {
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
self.as_slice()
}
}
impl<T> From<Vec<T>> for Buffer<T> {
fn from(values: Vec<T>) -> Self {
Self::from_vec(values)
}
}
impl<T> FromIterator<T> for Buffer<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self::from_vec(iter.into_iter().collect())
}
}
impl<T> Extend<T> for Buffer<T> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
self.to_mut().extend(iter);
}
}
impl<T> IntoIterator for Buffer<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.into_vec().into_iter()
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use super::{Buffer, Pin};
#[test]
fn a_buffer_reads_back_as_a_slice() {
let buffer: Buffer<i32> = vec![1, 2, 3].into();
assert_eq!(buffer.as_slice(), &[1, 2, 3]);
assert_eq!(buffer.len(), 3);
assert_eq!(buffer[1], 2);
assert_eq!(buffer.iter().sum::<i32>(), 6);
assert_eq!(buffer.clone().into_vec(), vec![1, 2, 3]);
}
#[test]
fn writing_goes_through_one_function() {
let mut buffer = Buffer::with_capacity(4);
buffer.push(1u8);
buffer.extend_from_slice(&[2, 3]);
buffer.extend([4u8]);
buffer.to_mut().sort_unstable_by(|a, b| b.cmp(a));
assert_eq!(buffer.as_slice(), &[4, 3, 2, 1]);
}
#[test]
fn an_empty_buffer_is_the_default_and_collects_like_a_vector() {
assert!(Buffer::<u64>::default().is_empty());
assert!(Buffer::<u64>::new().is_empty());
let collected: Buffer<u64> = (0..4).collect();
assert_eq!(collected.as_slice(), &[0, 1, 2, 3]);
assert_eq!(collected.into_iter().count(), 4);
}
#[test]
fn a_buffer_and_a_pin_both_cross_a_thread_boundary() {
const fn assert_send<T: Send>() {}
assert_send::<Buffer<i64>>();
assert_send::<Pin>();
let pin: Pin = Arc::new(vec![0u8; 8]);
let buffer: Buffer<i64> = vec![7; 2].into();
let handle = std::thread::spawn(move || (buffer.len(), Arc::strong_count(&pin)));
assert_eq!(handle.join().expect("the thread"), (2, 1));
}
}