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

index cd6b173a48a4b615121d97a292178af134ac213d..65d4f209623e0524155183e47218a69a13716f63 100644 (file)
@@ -2,6 +2,7 @@
 #![allow(unused)]
 
 use std::fmt::{self, Debug};
+use std::hint::unreachable_unchecked;
 use std::marker::PhantomData;
 use std::ptr::NonNull;
 
@@ -237,11 +238,11 @@ fn forbid_alias<T>(this: &T, new: *const ()) -> Result<(), BorrowConflict> {
     Ok(())
 }
 
-pub trait MultiStaticList {
+pub unsafe trait MultiStaticList {
     fn alias_check_ref(&self, p: *const ()) -> Result<(), BorrowConflict>;
     fn alias_check_mut(&self, p: *const ()) -> Result<(), BorrowConflict>;
 }
-impl MultiStaticList for () {
+unsafe impl MultiStaticList for () {
     fn alias_check_ref(&self, p: *const ()) -> Result<(), BorrowConflict> {
         Ok(())
     }
@@ -249,7 +250,7 @@ impl MultiStaticList for () {
         Ok(())
     }
 }
-impl<T, L: MultiStaticList> MultiStaticList for (L, &T) {
+unsafe impl<T, L: MultiStaticList> MultiStaticList for (L, &T) {
     fn alias_check_ref(&self, p: *const ()) -> Result<(), BorrowConflict> {
         self.0.alias_check_ref(p)
     }
@@ -258,7 +259,7 @@ impl<T, L: MultiStaticList> MultiStaticList for (L, &T) {
         self.0.alias_check_mut(p)
     }
 }
-impl<T, L: MultiStaticList> MultiStaticList for (L, &mut T) {
+unsafe impl<T, L: MultiStaticList> MultiStaticList for (L, &mut T) {
     fn alias_check_ref(&self, p: *const ()) -> Result<(), BorrowConflict> {
         forbid_alias(&*self.1, p)?;
         self.0.alias_check_ref(p)
@@ -272,28 +273,36 @@ impl<T, L: MultiStaticList> MultiStaticList for (L, &mut T) {
 impl<'a, L: MultiStaticList> MultiStatic<'a, L> {
     pub fn borrow<'r, T>(self, p: Ptr<T>) -> Result<
         MultiStatic<'a, (L, &'r T)>,
-        BorrowConflict
+        Self
     >
     where 'a: 'r
     {
-        self.l.alias_check_ref(p.ptr.as_ptr() as *const ())?;
-        Ok(MultiStatic {
-            tok: self.tok,
-            l: (self.l, unsafe { p.ptr.as_ref() }),
-        })
+        match self.l.alias_check_ref(p.ptr.as_ptr() as *const ()) {
+            Err(e) => Err(self),
+            Ok(()) => Ok(MultiStatic {
+                tok: self.tok,
+                l: (self.l, unsafe { p.ptr.as_ref() }),
+            })
+        }
     }
 
     pub fn borrow_mut<'r, T>(self, mut p: Ptr<T>) -> Result<
         MultiStatic<'a, (L, &'r mut T)>,
-        BorrowConflict
+        Self
     >
     where 'a: 'r
     {
-        self.l.alias_check_mut(p.ptr.as_ptr() as *const ())?;
-        Ok(MultiStatic {
-            tok: self.tok,
-            l: (self.l, unsafe { p.ptr.as_mut() }),
-        })
+        match self.l.alias_check_mut(p.ptr.as_ptr() as *const ()) {
+            Err(e) => Err(self),
+            Ok(()) => Ok(MultiStatic {
+                tok: self.tok,
+                l: (self.l, unsafe { p.ptr.as_mut() }),
+            })
+        }
+    }
+
+    pub fn finish(self) -> L {
+        self.l
     }
 }
 
@@ -319,6 +328,13 @@ mod tests {
             noalias: NoAliasSingleton,
         }
 
+        #[derive(Debug, Eq, PartialEq)]
+        pub enum HeadAndTail<T> {
+            None,
+            One(T),
+            Both(T, T),
+        }
+
         impl<T: Debug> List<T> {
             pub fn new() -> Self {
                 let noalias = unsafe { NoAliasSingleton::init() };
@@ -377,6 +393,29 @@ mod tests {
                 )
             }
 
+            pub fn head_and_tail_mut(&mut self) -> HeadAndTail<&mut T> {
+                let Some(head) = self.head
+                else { return HeadAndTail::None };
+
+                let multi = self.noalias.mut_token().multi_static();
+
+                let Ok(multi) = multi.borrow_mut(head)
+                else { unsafe { unreachable_unchecked() } };
+
+                let tail = unsafe { self.tail.unwrap_unchecked() };
+
+                match multi.borrow_mut(tail) {
+                    Ok(y) => {
+                        let (((), head), tail) = y.finish();
+                        HeadAndTail::Both(&mut head.data, &mut tail.data)
+                    },
+                    Err(n) => {
+                        let ((), head) = n.finish();
+                        HeadAndTail::One(&mut head.data)
+                    }
+                }
+            }
+
             // We wouldn't do this, since it's daft, but
             // it lets us demonstrate passing a token.
             fn pop_front_inner<'a>(
@@ -410,7 +449,7 @@ mod tests {
 
     #[test]
     fn demo() {
-        use list::List;
+        use list::{List, HeadAndTail};
 
         let s = |s: &str| format!("{s}");
 
@@ -420,6 +459,8 @@ mod tests {
         drop(l);
 
         let mut l = List::new();     l.check_consistency();
+        assert_eq!(l.head_and_tail_mut(), HeadAndTail::None);
+
         l.append(s("hi"));           l.check_consistency();
         l.append(s("ho"));           l.check_consistency();