From: Ian Jackson Date: Wed, 17 Aug 2022 14:25:55 +0000 (+0100) Subject: AutoStackVec X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=53a85aaa8a2a709011481ec95720353a6e50594d;p=rust-experiments.git AutoStackVec --- diff --git a/src/main.rs b/src/main.rs index 476e59c..f82867b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,27 +2,104 @@ #![allow(unused_variables)] #![allow(unused_imports)] +use std::fmt::{self, Debug}; +use std::marker::PhantomData; use std::mem; use std::mem::MaybeUninit; +use std::ops::Deref; pub fn default() -> T { Default::default() } -#[derive(Debug)] -struct AutoStackVec { +pub struct AutoStackVec { used: usize, - buf: [T; N], + ph: PhantomData, + buf: B, } -impl AutoStackVec { - fn new() -> Self where T: Default { +impl Deref for AutoStackVec where B: Buffer { + type Target = [T]; + fn deref(&self) -> &[T] { + unsafe { + std::slice::from_raw_parts( + self.buf.raw_ptr() as _, + self.used, + ) + } + } +} + +impl Debug for AutoStackVec where B: Buffer, T: Debug { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + <[T] as Debug>::fmt(&*self, f) + } +} + +#[repr(C)] +pub struct Buf1 { + earlier: B, + item: MaybeUninit, +} + +pub unsafe trait Buffer { + fn len() -> usize; + fn raw_ptr(&self) -> *const MaybeUninit { self as *const _ as _ } + fn raw_mut(&mut self) -> *mut MaybeUninit { self as *mut _ as _ } +} +unsafe impl Buffer for () { + fn len() -> usize { 0 } +} +unsafe impl Buffer for Buf1 where B: Buffer { + fn len() -> usize { B::len() + 1 } +} + +impl AutoStackVec { + pub fn new() -> Self { AutoStackVec { used: 0, - buf: std::array::from_fn(|_| default()), + ph: PhantomData, + buf: (), + } + } +} + +impl AutoStackVec where B: Buffer { + pub fn push_none(mut self) -> AutoStackVec> { + let mut out = AutoStackVec { + used: 0, + ph: self.ph, + buf: Buf1 { + earlier: self.buf, + item: MaybeUninit::uninit(), + }, + }; + out.used = self.used; + self.used = 0; + out + } + + pub fn push(self, item: T) -> AutoStackVec> { + unsafe { + let mut out = self.push_none(); + let item = MaybeUninit::new(item); + (out.buf.raw_mut()) + .add(out.used) + .write(item); + out.used += 1; + out + } + } + + pub fn push_option(self, item: Option) -> AutoStackVec> { + if let Some(item) = item { + self.push(item) + } else { + self.push_none() } } } fn main(){ - let asv = AutoStackVec::<4, i32>::new(); + let asv = AutoStackVec::::new(); + let asv = asv.push(42); eprintln!("N {:?}", asv); }