chiark / gitweb /
wip
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 14 Nov 2024 21:27:29 +0000 (21:27 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 14 Nov 2024 21:49:40 +0000 (21:49 +0000)
src/lib.rs

index 96abfe0101b942f36b68f1a6e86182f487b5ca7c..2f07b8fa8f57b1719e58b3b2eef6f4bdd8da44fa 100644 (file)
@@ -1,9 +1,6 @@
 
-#![allow(unused)]
-
 use std::collections::HashSet;
 use std::fmt::{self, Debug};
-use std::hint::unreachable_unchecked;
 use std::marker::PhantomData;
 use std::ptr::NonNull;
 
@@ -32,13 +29,13 @@ pub unsafe trait IsRefToken<'a>: Sized {
 pub unsafe trait IsMutToken<'a>: IsRefToken<'a> + Sized {
     /// Obtain a new ZST token from something that might be a real object.
     #[inline]
-    fn mut_token<'r>(mut self) -> MutToken<'r>
+    fn mut_token<'r>(self) -> MutToken<'r>
     where 'a: 'r,
     {
         MutToken(PhantomData)
     }
 
-    fn multi_static<'r>(mut self) -> MultiStatic<'r, ()>
+    fn multi_static<'r>(self) -> MultiStatic<'r, ()>
     where 'a: 'r,
     {
         MultiStatic {
@@ -47,11 +44,11 @@ pub unsafe trait IsMutToken<'a>: IsRefToken<'a> + Sized {
         }
     }
 
-    fn multi_runtime<'r>(mut self) -> MultiRuntime<'r>
+    fn multi_runtime<'r>(self) -> MultiRuntime<'r>
     where 'a: 'r,
     {
         MultiRuntime {
-            tok: self.mut_token(),
+            _tok: self.mut_token(),
             ref_given: HashSet::new(),
             mut_given: HashSet::new(),
         }
@@ -93,7 +90,7 @@ impl<'a> MutToken<'a> {
     ///
     /// SAFETY
     ///
-    fn new_unchecked() -> Self { MutToken(PhantomData) }
+    pub unsafe fn new_unchecked() -> Self { MutToken(PhantomData) }
 }
 
 pub struct Ptr<T> {
@@ -149,6 +146,7 @@ TODO lifetime is hard
 
     #[inline]
     pub fn borrow<'a>(self, tok: impl IsRefToken<'a>) -> &'a T {
+        let _ = tok;
         unsafe {
             // SAFETY
             //
@@ -161,6 +159,7 @@ TODO lifetime is hard
 
     #[inline]
     pub fn borrow_mut<'a>(mut self, tok: impl IsMutToken<'a>) -> &'a mut T {
+        let _ = tok;
         unsafe {
             // SAFETY
             //
@@ -193,6 +192,7 @@ TODO lifetime is hard
     /// (The compiler will check that no borrows are live.)
     #[inline]
     pub unsafe fn free_heap<'a>(self, tok: impl IsMutToken<'a>) -> T {
+        let _ = tok;
         let t: Box<T> = unsafe {
             // SAFETY
             //
@@ -237,6 +237,7 @@ impl NoAliasSingleton {
     pub unsafe fn init() -> Self { NoAliasSingleton {} }
 }
 
+#[derive(Debug)]
 pub struct BorrowConflict;
 
 pub struct MultiStatic<'a, L> {
@@ -254,10 +255,10 @@ pub unsafe trait MultiStaticList {
     fn alias_check_mut(&self, p: NonNull<()>) -> Result<(), BorrowConflict>;
 }
 unsafe impl MultiStaticList for () {
-    fn alias_check_ref(&self, p: NonNull<()>) -> Result<(), BorrowConflict> {
+    fn alias_check_ref(&self, _: NonNull<()>) -> Result<(), BorrowConflict> {
         Ok(())
     }
-    fn alias_check_mut(&self, p: NonNull<()>) -> Result<(), BorrowConflict> {
+    fn alias_check_mut(&self, _: NonNull<()>) -> Result<(), BorrowConflict> {
         Ok(())
     }
 }
@@ -289,7 +290,7 @@ impl<'a, L: MultiStaticList> MultiStatic<'a, L> {
     where 'a: 'r
     {
         match self.l.alias_check_ref(p.ptr.cast()) {
-            Err(e) => Err(self),
+            Err(BorrowConflict) => Err(self),
             Ok(()) => Ok(MultiStatic {
                 tok: self.tok,
                 l: (self.l, unsafe { p.ptr.as_ref() }),
@@ -304,7 +305,7 @@ impl<'a, L: MultiStaticList> MultiStatic<'a, L> {
     where 'a: 'r
     {
         match self.l.alias_check_mut(p.ptr.cast()) {
-            Err(e) => Err(self),
+            Err(BorrowConflict) => Err(self),
             Ok(()) => Ok(MultiStatic {
                 tok: self.tok,
                 l: (self.l, unsafe { p.ptr.as_mut() }),
@@ -318,7 +319,7 @@ impl<'a, L: MultiStaticList> MultiStatic<'a, L> {
 }
 
 pub struct MultiRuntime<'a> {
-    tok: MutToken<'a>,
+    _tok: MutToken<'a>,
     ref_given: HashSet<NonNull<()>>,
     mut_given: HashSet<NonNull<()>>,
 }
@@ -372,6 +373,8 @@ mod tests {
 
     mod list {
         use super::*;
+        use std::hint::unreachable_unchecked;
+        use std::iter;
 
         #[derive(Debug)]
         pub struct Node<T> {
@@ -394,6 +397,8 @@ mod tests {
             Both(T, T),
         }
 
+        type P<T> = Ptr<Node<T>>;
+
         impl<T: Debug> List<T> {
             pub fn new() -> Self {
                 let noalias = unsafe { NoAliasSingleton::init() };
@@ -403,7 +408,7 @@ mod tests {
             pub fn check_consistency(&self) {
                 dbg!(self);
                 let tok = self.noalias.ref_token();
-                let mut last: Option<Ptr<Node<T>>> = None;
+                let mut last: Option<P<T>> = None;
                 let mut node = self.head;
                 while let Some(node_) = node {
                     dbg!(node_);
@@ -475,12 +480,36 @@ mod tests {
                 }
             }
 
+            pub fn all(&self) -> impl Iterator<Item = &T> {
+                let tok = self.noalias.ref_token();
+                Self::iter_ptrs(self.head, move |node| {
+                    let node = node.borrow(tok);
+                    (&node.data, node.next)
+                })
+            }
+
+            pub fn all_mut_safe(&mut self) -> impl Iterator<Item = &mut T> {
+                let mut multi = self.noalias.multi_runtime();
+                Self::iter_ptrs(self.head, move |node| {
+                    let node = multi.borrow_mut(node).expect("untangled!");
+                    (&mut node.data, node.next)
+                })
+            }
+
+            pub fn all_mut_fast(&mut self) -> impl Iterator<Item = &mut T> {
+                Self::iter_ptrs(self.head, |node| {
+                    let tok = unsafe { MutToken::new_unchecked() };
+                    let node = node.borrow_mut(tok);
+                    (&mut node.data, node.next)
+                })
+            }
+
             // We wouldn't do this, since it's daft, but
             // it lets us demonstrate passing a token.
             fn pop_front_inner<'a>(
                 mut tok: MutToken<'a>,
-                head: &mut Option<Ptr<Node<T>>>,
-                tail: &mut Option<Ptr<Node<T>>>,
+                head: &mut Option<P<T>>,
+                tail: &mut Option<P<T>>,
             ) -> Option<T> {
                 let deleting = (*head)?;
                 let new_head = deleting.borrow(&tok).next;
@@ -493,6 +522,21 @@ mod tests {
                 let deleted = unsafe { deleting.free_heap(&mut tok) };
                 Some(deleted.data)
             }
+
+            fn iter_ptrs<'i, I: 'i>(
+                head: Option<P<T>>,
+                mut node_map: impl FnMut(P<T>) -> (I, Option<P<T>>) + 'i,
+            ) -> impl Iterator<Item = I> + 'i
+            where T: 'i
+            {
+                let mut next = head;
+                iter::from_fn(move || {
+                    let node = next?;
+                    let item;
+                    (item, next) = node_map(node);
+                    Some(item)
+                })
+            }
         }
 
         impl<T: Debug> Drop for List<T> {