Explorar el Código

feat(thingbuf): hahahaha static storage works

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Eliza Weisman hace 3 años
padre
commit
e47cd7dc80
Se han modificado 5 ficheros con 170 adiciones y 4 borrados
  1. 27 1
      src/lib.rs
  2. 1 1
      src/loom.rs
  3. 13 2
      src/stringbuf.rs
  4. 20 0
      src/sync_channel.rs
  5. 109 0
      tests/static_storage.rs

+ 27 - 1
src/lib.rs

@@ -45,6 +45,14 @@ use crate::util::{Backoff, CachePadded};
 #[cfg(feature = "alloc")]
 mod stringbuf;
 
+#[cfg(feature = "alloc")]
+pub use stringbuf::StringBuf;
+
+/// A ringbuf of...things.
+///
+/// # Examples
+///
+/// Using a
 pub struct ThingBuf<T, S = Box<[Slot<T>]>> {
     head: CachePadded<AtomicUsize>,
     tail: CachePadded<AtomicUsize>,
@@ -267,7 +275,7 @@ where
     }
 }
 
-impl<T> fmt::Debug for ThingBuf<T> {
+impl<T, S> fmt::Debug for ThingBuf<T, S> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("ThingBuf")
             .field("capacity", &self.capacity())
@@ -344,6 +352,16 @@ impl<T: Default> Default for Slot<T> {
 
 impl<T> Slot<T> {
     const UNINIT: usize = usize::MAX;
+
+    #[cfg(not(test))]
+    pub const fn new(t: T) -> Self {
+        Self {
+            value: UnsafeCell::new(t),
+            state: AtomicUsize::new(Self::UNINIT),
+        }
+    }
+
+    #[cfg(test)]
     pub fn new(t: T) -> Self {
         Self {
             value: UnsafeCell::new(t),
@@ -353,7 +371,15 @@ impl<T> Slot<T> {
 }
 
 impl<T> Slot<MaybeUninit<T>> {
+    #[cfg(not(test))]
+    pub const fn uninit() -> Self {
+        Self::new(MaybeUninit::uninit())
+    }
+
+    #[cfg(test)]
     pub fn uninit() -> Self {
         Self::new(MaybeUninit::uninit())
     }
 }
+
+unsafe impl<T: Sync> Sync for Slot<T> {}

+ 1 - 1
src/loom.rs

@@ -90,7 +90,7 @@ mod inner {
     pub(crate) struct UnsafeCell<T>(core::cell::UnsafeCell<T>);
 
     impl<T> UnsafeCell<T> {
-        pub fn new(data: T) -> UnsafeCell<T> {
+        pub const fn new(data: T) -> UnsafeCell<T> {
             UnsafeCell(core::cell::UnsafeCell::new(data))
         }
 

+ 13 - 2
src/stringbuf.rs

@@ -3,8 +3,8 @@ use super::*;
 use alloc::string::String;
 
 #[derive(Debug)]
-pub struct StringBuf {
-    inner: ThingBuf<String>,
+pub struct StringBuf<S = Box<[Slot<String>]>> {
+    inner: ThingBuf<String, S>,
     max_idle_capacity: usize,
 }
 
@@ -15,7 +15,18 @@ impl StringBuf {
             max_idle_capacity: usize::MAX,
         }
     }
+}
 
+impl<S> StringBuf<S>
+where
+    S: AsRef<[Slot<String>]>,
+{
+    pub fn from_array(array: S) -> Self {
+        Self {
+            inner: ThingBuf::from_array(array),
+            max_idle_capacity: usize::MAX,
+        }
+    }
     pub fn with_max_idle_capacity(self, max_idle_capacity: usize) -> Self {
         Self {
             max_idle_capacity,

+ 20 - 0
src/sync_channel.rs

@@ -0,0 +1,20 @@
+use super::*;
+use crate::loom::sync::{Condvar, Mutex};
+
+pub struct Sender<T> {
+    inner: Arc<Inner<T>>,
+}
+
+pub struct Receiver<T> {
+    inner: Arc<Inner<T>>,
+}
+
+struct Inner<T> {
+    lock: Mutex<bool>,
+    cv: Condvar,
+    buf: ThingBuf<T>,
+}
+
+impl<T> Receiver<T> {
+    
+}

+ 109 - 0
tests/static_storage.rs

@@ -0,0 +1,109 @@
+use std::{fmt::Write, sync::Arc, thread};
+use thingbuf::{Slot, StringBuf, ThingBuf};
+
+#[test]
+fn static_storage_thingbuf() {
+    let thingbuf = Arc::new(ThingBuf::from_array([
+        Slot::new(0),
+        Slot::new(0),
+        Slot::new(0),
+        Slot::new(0),
+        Slot::new(0),
+        Slot::new(0),
+        Slot::new(0),
+        Slot::new(0),
+    ]));
+
+    let producer = {
+        let thingbuf = thingbuf.clone();
+        thread::spawn(move || {
+            for i in 0..32 {
+                let mut thing = 'write: loop {
+                    match thingbuf.push_ref() {
+                        Ok(thing) => break 'write thing,
+                        _ => thread::yield_now(),
+                    }
+                };
+                thing.with_mut(|thing| *thing = i);
+            }
+        })
+    };
+
+    let mut i = 0;
+
+    // While the producer is writing to the queue, push each entry to the
+    // results string.
+    while Arc::strong_count(&thingbuf) > 1 {
+        match thingbuf.pop_ref() {
+            Some(thing) => thing.with(|thing| {
+                assert_eq!(*thing, i);
+                i += 1;
+            }),
+            None => thread::yield_now(),
+        }
+    }
+
+    producer.join().unwrap();
+
+    // drain the queue.
+    while let Some(thing) = thingbuf.pop_ref() {
+        thing.with(|thing| {
+            assert_eq!(*thing, i);
+            i += 1;
+        })
+    }
+}
+
+#[test]
+fn static_storage_stringbuf() {
+    let stringbuf = Arc::new(StringBuf::from_array([
+        Slot::new(String::new()),
+        Slot::new(String::new()),
+        Slot::new(String::new()),
+        Slot::new(String::new()),
+        Slot::new(String::new()),
+        Slot::new(String::new()),
+        Slot::new(String::new()),
+        Slot::new(String::new()),
+    ]));
+
+    let producer = {
+        let stringbuf = stringbuf.clone();
+        thread::spawn(move || {
+            for i in 0..16 {
+                let mut string = 'write: loop {
+                    match stringbuf.write() {
+                        Ok(string) => break 'write string,
+                        _ => thread::yield_now(),
+                    }
+                };
+
+                write!(&mut string, "{:?}", i).unwrap();
+            }
+        })
+    };
+
+    let mut results = String::new();
+
+    // While the producer is writing to the queue, push each entry to the
+    // results string.
+    while Arc::strong_count(&stringbuf) > 1 {
+        if let Some(string) = stringbuf.pop_ref() {
+            writeln!(results, "{}", string).unwrap();
+        }
+        thread::yield_now();
+    }
+
+    producer.join().unwrap();
+
+    // drain the queue.
+    while let Some(string) = stringbuf.pop_ref() {
+        writeln!(results, "{}", string).unwrap();
+    }
+
+    let results = dbg!(results);
+
+    for (n, ln) in results.lines().enumerate() {
+        assert_eq!(ln.parse::<usize>(), Ok(n));
+    }
+}