diff --git a/src/lib.rs b/src/lib.rs index 7ecb45b933861008e028bb234c0fe2f914e12664..9fd8ad6a559a2a554ffa7fb2b5af208c720b6b21 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,5 @@ mod test; pub use runtime::{errors, Connector, PortBinding}; -pub use crate::runtime::experimental::api::Port; - #[cfg(feature = "ffi")] pub use runtime::ffi; diff --git a/src/runtime/experimental/api.rs b/src/runtime/experimental/api.rs index b10895a690b4d201f592a51f5579fa74664f0560..28b5c5b0125025312f7a5afcdb6c141e02303ed5 100644 --- a/src/runtime/experimental/api.rs +++ b/src/runtime/experimental/api.rs @@ -2,6 +2,8 @@ use crate::common::*; use crate::runtime::endpoint::Endpoint; use crate::runtime::endpoint::EndpointExt; use crate::runtime::endpoint::EndpointInfo; +use core::mem::MaybeUninit; +use std::collections::BTreeSet; use std::net::SocketAddr; use std::sync::Arc; @@ -25,30 +27,6 @@ impl From<(Coupling, Polarity, SocketAddr)> for Binding { } } -pub struct MsgBuffer<'a> { - slice: &'a mut [u8], - len: usize, -} -impl MsgBuffer<'_> { - pub fn clear(&mut self) { - self.len = 0; - } - pub fn write_msg(&mut self, r: &[u8]) -> std::io::Result<()> { - use std::io::Write; - self.slice.write_all(r)?; - self.len = r.len(); - Ok(()) - } - pub fn read_msg(&self) -> &[u8] { - &self.slice[0..self.len] - } -} -impl<'a> From<&'a mut [u8]> for MsgBuffer<'a> { - fn from(slice: &'a mut [u8]) -> Self { - Self { slice, len: 0 } - } -} - #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] #[repr(C)] pub struct Port(pub u32); @@ -296,3 +274,222 @@ unsafe fn as_mut_slice<'a, T>(len: usize, ptr: *mut T) -> &'a mut [T] { unsafe fn as_const_slice<'a, T>(len: usize, ptr: *const T) -> &'a [T] { std::slice::from_raw_parts(ptr, len) } + +// data contains values in one of three states: +// 1. occupied: ininitialized. will be dropped. +// 2. vacant: uninitialized. may be reused implicitly. won't be dropped. +// 2. reserved: uninitialized. may be occupied implicitly. won't be dropped. +struct VecStorage { + // invariant A: elements at indices (0..data.len()) / vacant / reserved are occupied + // invariant B: reserved & vacant = {} + // invariant C: (vacant U reserved) subset of (0..data.len) + data: Vec>, + vacant: BTreeSet, + reserved: BTreeSet, +} +impl Default for VecStorage { + fn default() -> Self { + Self { data: Default::default(), vacant: Default::default(), reserved: Default::default() } + } +} +impl Debug for VecStorage +where + T: Debug, +{ + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + enum FmtT<'a, T> { + Vacant, + Reserved, + Occupied(&'a T), + }; + impl Debug for FmtT<'_, T> + where + T: Debug, + { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + match self { + FmtT::Vacant => write!(f, "Vacant"), + FmtT::Reserved => write!(f, "Reserved"), + FmtT::Occupied(t) => write!(f, "Occupied({:?})", t), + } + } + } + let iter = (0..self.data.len()).map(|i| { + if self.vacant.contains(&i) { + FmtT::Vacant + } else if self.reserved.contains(&i) { + FmtT::Reserved + } else { + // 2. Invariant A => reading valid ata + unsafe { + // 1. index is within bounds + // 2. i is occupied => initialized data is being dropped + FmtT::Occupied(&*self.data.get_unchecked(i).as_ptr()) + } + } + }); + f.debug_list().entries(iter).finish() + } +} +impl Drop for VecStorage { + fn drop(&mut self) { + self.clear(); + } +} +impl VecStorage { + // ASSUMES that i in 0..self.data.len() + unsafe fn get_occupied_unchecked(&self, i: usize) -> Option<&T> { + if self.vacant.contains(&i) || self.reserved.contains(&i) { + None + } else { + // 2. Invariant A => reading valid ata + Some(&*self.data.get_unchecked(i).as_ptr()) + } + } + // ASSUMES that i in 0..self.data.len() + unsafe fn get_mut_occupied_unchecked(&mut self, i: usize) -> Option<&mut T> { + if self.vacant.contains(&i) || self.reserved.contains(&i) { + None + } else { + // 2. Invariant A => reading valid ata + Some(&mut *self.data.get_unchecked_mut(i).as_mut_ptr()) + } + } + // breaks invariant A: returned index is in NO state + fn pop_vacant(&mut self) -> usize { + if let Some(i) = pop_set_arb(&mut self.vacant) { + i + } else { + self.data.push(MaybeUninit::uninit()); + self.data.len() - 1 + } + } + ////////////// + pub fn clear(&mut self) { + for i in 0..self.data.len() { + if !self.vacant.contains(&i) && !self.reserved.contains(&i) { + // invariant A: this element is OCCUPIED + unsafe { + // 1. by construction, i is in bounds + // 2. i is occupied => initialized data is being dropped + drop(self.data.get_unchecked_mut(i).as_ptr().read()); + } + } + } + self.vacant.clear(); + self.reserved.clear(); + } + pub fn iter(&self) -> impl Iterator { + (0..self.data.len()).filter_map(move |i| unsafe { self.get_occupied_unchecked(i) }) + } + pub fn get_occupied(&self, i: usize) -> Option<&T> { + if i >= self.data.len() { + None + } else { + unsafe { + // index is within bounds + self.get_occupied_unchecked(i) + } + } + } + pub fn get_mut_occupied(&mut self, i: usize) -> Option<&mut T> { + if i >= self.data.len() { + None + } else { + unsafe { + // index is within bounds + self.get_mut_occupied_unchecked(i) + } + } + } + pub fn new_reserved(&mut self) -> usize { + let i = self.pop_vacant(); // breaks invariant A: i is in NO state + self.reserved.insert(i); // restores invariant A + i + } + pub fn occupy_reserved(&mut self, i: usize, t: T) { + assert!(self.reserved.remove(&i)); // breaks invariant A + unsafe { + // 1. invariant C => write is within bounds + // 2. i WAS reserved => no initialized data is being overwritten + self.data.get_unchecked_mut(i).as_mut_ptr().write(t) + // restores invariant A + }; + } + pub fn new_occupied(&mut self, t: T) -> usize { + let i = self.pop_vacant(); // breaks invariant A: i is in NO state + unsafe { + // 1. invariant C => write is within bounds + // 2. i WAS reserved => no initialized data is being overwritten + self.data.get_unchecked_mut(i).as_mut_ptr().write(t) + // restores invariant A + }; + i + } + pub fn vacate(&mut self, i: usize) -> Option { + if i >= self.data.len() || self.vacant.contains(&i) { + // already vacant. nothing to do here + return None; + } + // i is certainly within bounds of self.data + let value = if self.reserved.remove(&i) { + // no data to drop + None + } else { + // invariant A => this element is OCCUPIED! + unsafe { + // 1. index is within bounds + // 2. i is occupied => initialized data is being dropped + Some(self.data.get_unchecked_mut(i).as_ptr().read()) + } + }; + // Mark as vacant... + if i + 1 == self.data.len() { + // ... by truncating self.data. + self.data.pop(); // truncate last data element + let mut walking = i; + while walking > 0 && self.vacant.remove(&(walking - 1)) { + self.data.pop(); // truncate another element + walking -= 1; + } + } else { + // ... by populating self.vacant. + self.vacant.insert(i); + } + value + } + pub fn iter_reserved(&self) -> impl Iterator + '_ { + self.reserved.iter().copied() + } +} + +fn pop_set_arb(s: &mut BTreeSet) -> Option { + if let Some(&x) = s.iter().next() { + s.remove(&x); + Some(x) + } else { + None + } +} + +#[test] +fn vec_storage() { + #[derive(Debug)] + struct Foo; + impl Drop for Foo { + fn drop(&mut self) { + println!("DROPPING FOO!"); + } + } + + let mut v = VecStorage::default(); + let i0 = v.new_occupied(Foo); + println!("{:?}", &v); + let i1 = v.new_reserved(); + println!("{:?}", &v); + let q = v.vacate(i0); + println!("q {:?}", q); + println!("{:?}", &v); + v.occupy_reserved(i1, Foo); + println!("{:?}", &v); +} diff --git a/src/runtime/experimental/mod.rs b/src/runtime/experimental/mod.rs index 700533992b6a3c82da62005fab4239d84b72dead..c1187ad2c3d353ff7601c5d95b35bb84c6721d5c 100644 --- a/src/runtime/experimental/mod.rs +++ b/src/runtime/experimental/mod.rs @@ -1,2 +1,2 @@ -pub mod api; +mod api; mod bits;