chiark / gitweb /
code motion
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 14 Nov 2024 21:48:56 +0000 (21:48 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 14 Nov 2024 21:49:40 +0000 (21:49 +0000)
src/lib.rs
src/test.rs [new file with mode: 0644]
src/test/list.rs [new file with mode: 0644]

index 2f07b8fa8f57b1719e58b3b2eef6f4bdd8da44fa..6b886fbdec4daffac53681e09a1381eb3202a586 100644 (file)
@@ -1,4 +1,7 @@
 
+#[cfg(test)]
+mod test;
+
 use std::collections::HashSet;
 use std::fmt::{self, Debug};
 use std::marker::PhantomData;
@@ -365,219 +368,3 @@ impl<'a> MultiRuntime<'a> {
         Ok(())
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use fmt::Write as _;
-
-    mod list {
-        use super::*;
-        use std::hint::unreachable_unchecked;
-        use std::iter;
-
-        #[derive(Debug)]
-        pub struct Node<T> {
-            back: Option<Ptr<Node<T>>>,
-            next: Option<Ptr<Node<T>>>,
-            pub data: T,
-        }
-
-        #[derive(Debug)]
-        pub struct List<T: Debug> {
-            head: Option<Ptr<Node<T>>>,
-            tail: Option<Ptr<Node<T>>>,
-            noalias: NoAliasSingleton,
-        }
-
-        #[derive(Debug, Eq, PartialEq)]
-        pub enum HeadAndTail<T> {
-            None,
-            One(T),
-            Both(T, T),
-        }
-
-        type P<T> = Ptr<Node<T>>;
-
-        impl<T: Debug> List<T> {
-            pub fn new() -> Self {
-                let noalias = unsafe { NoAliasSingleton::init() };
-                List { head: None, tail: None, noalias }
-            }
-
-            pub fn check_consistency(&self) {
-                dbg!(self);
-                let tok = self.noalias.ref_token();
-                let mut last: Option<P<T>> = None;
-                let mut node = self.head;
-                while let Some(node_) = node {
-                    dbg!(node_);
-                    let node__ = node_.borrow(&tok);
-                    dbg!(node__);
-                    assert_eq!(last.as_ptr(), node__.back.as_ptr());
-                    last = Some(node_);
-                    node = node__.next;
-                }
-                assert_eq!(self.tail.as_ptr(), last.as_ptr());
-            }
-
-            pub fn append(&mut self, data: T) {
-                let node = Node {
-                    back: self.head,
-                    next: None,
-                    data,
-                };
-                let node = Ptr::new_heap(node);
-                if let Some(old_tail) = self.tail {
-                    old_tail.borrow_mut(&mut self.noalias).next = Some(node);
-                } else {
-                    self.head = Some(node);
-                };
-                self.tail = Some(node);
-            }
-
-            pub fn front(&self) -> Option<&T> {
-                let tok = self.noalias.ref_token();
-                let head = self.head?;
-                Some(&head.borrow(tok).data)
-            }
-
-            pub fn front_mut(&mut self) -> Option<&mut T> {
-                let tok = self.noalias.mut_token();
-                let head = self.head?;
-                Some(&mut head.borrow_mut(tok).data)
-            }
-
-            pub fn pop_front(&mut self) -> Option<T> {
-                let tok = self.noalias.mut_token();
-                Self::pop_front_inner(
-                    tok,
-                    &mut self.head,
-                    &mut self.tail,
-                )
-            }
-
-            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)
-                    }
-                }
-            }
-
-            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<P<T>>,
-                tail: &mut Option<P<T>>,
-            ) -> Option<T> {
-                let deleting = (*head)?;
-                let new_head = deleting.borrow(&tok).next;
-                *head = new_head;
-                if let Some(new_head) = new_head {
-                    new_head.borrow_mut(&mut tok).back = None;
-                } else {
-                    *tail = None;
-                }
-                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> {
-            fn drop(&mut self) {
-                while let Some(_) = Self::pop_front_inner(
-                    self.noalias.mut_token(),
-                    &mut self.head,
-                    &mut self.tail,
-                ) { }
-            }
-        }
-    }
-
-    #[test]
-    fn demo() {
-        use list::{List, HeadAndTail};
-        use HeadAndTail as H;
-
-        let s = |s: &str| format!("{s}");
-
-        let l = List::<String>::new();
-        l.check_consistency();
-        assert_eq!(l.front(), None);
-        drop(l);
-
-        let mut l = List::new();     l.check_consistency();
-        assert_eq!(l.head_and_tail_mut(), H::None);
-
-        l.append(s("hi"));           l.check_consistency();
-        assert_eq!(l.head_and_tail_mut(), H::One(&mut s("hi")));
-
-        l.append(s("ho"));           l.check_consistency();
-        assert_eq!(l.head_and_tail_mut(), H::Both(&mut s("hi"), &mut s("ho")));
-
-        write!(l.front_mut().unwrap(), "!").unwrap();
-        assert_eq!(l.pop_front(), Some(s("hi!")));  l.check_consistency();
-        assert_eq!(l.front(), Some(&s("ho")));      l.check_consistency();
-
-        drop(l);
-    }
-}
-
-
-
diff --git a/src/test.rs b/src/test.rs
new file mode 100644 (file)
index 0000000..55ca991
--- /dev/null
@@ -0,0 +1,33 @@
+
+use super::*;
+use fmt::Write as _;
+
+mod list;
+use list::{List, HeadAndTail};
+
+#[test]
+fn demo() {
+    use HeadAndTail as H;
+
+    let s = |s: &str| format!("{s}");
+
+    let l = List::<String>::new();
+    l.check_consistency();
+    assert_eq!(l.front(), None);
+    drop(l);
+
+    let mut l = List::new();     l.check_consistency();
+    assert_eq!(l.head_and_tail_mut(), H::None);
+
+    l.append(s("hi"));           l.check_consistency();
+    assert_eq!(l.head_and_tail_mut(), H::One(&mut s("hi")));
+
+    l.append(s("ho"));           l.check_consistency();
+    assert_eq!(l.head_and_tail_mut(), H::Both(&mut s("hi"), &mut s("ho")));
+
+    write!(l.front_mut().unwrap(), "!").unwrap();
+    assert_eq!(l.pop_front(), Some(s("hi!")));  l.check_consistency();
+    assert_eq!(l.front(), Some(&s("ho")));      l.check_consistency();
+
+    drop(l);
+}
diff --git a/src/test/list.rs b/src/test/list.rs
new file mode 100644 (file)
index 0000000..5514e75
--- /dev/null
@@ -0,0 +1,177 @@
+use super::*;
+use std::hint::unreachable_unchecked;
+use std::iter;
+
+#[derive(Debug)]
+pub struct Node<T> {
+    back: Option<Ptr<Node<T>>>,
+    next: Option<Ptr<Node<T>>>,
+    pub data: T,
+}
+
+#[derive(Debug)]
+pub struct List<T: Debug> {
+    head: Option<Ptr<Node<T>>>,
+    tail: Option<Ptr<Node<T>>>,
+    noalias: NoAliasSingleton,
+}
+
+#[derive(Debug, Eq, PartialEq)]
+pub enum HeadAndTail<T> {
+    None,
+    One(T),
+    Both(T, T),
+}
+
+type P<T> = Ptr<Node<T>>;
+
+impl<T: Debug> List<T> {
+    pub fn new() -> Self {
+        let noalias = unsafe { NoAliasSingleton::init() };
+        List { head: None, tail: None, noalias }
+    }
+
+    pub fn check_consistency(&self) {
+        dbg!(self);
+        let tok = self.noalias.ref_token();
+        let mut last: Option<P<T>> = None;
+        let mut node = self.head;
+        while let Some(node_) = node {
+            dbg!(node_);
+            let node__ = node_.borrow(&tok);
+            dbg!(node__);
+            assert_eq!(last.as_ptr(), node__.back.as_ptr());
+            last = Some(node_);
+            node = node__.next;
+        }
+        assert_eq!(self.tail.as_ptr(), last.as_ptr());
+    }
+
+    pub fn append(&mut self, data: T) {
+        let node = Node {
+            back: self.head,
+            next: None,
+            data,
+        };
+        let node = Ptr::new_heap(node);
+        if let Some(old_tail) = self.tail {
+            old_tail.borrow_mut(&mut self.noalias).next = Some(node);
+        } else {
+            self.head = Some(node);
+        };
+        self.tail = Some(node);
+    }
+
+    pub fn front(&self) -> Option<&T> {
+        let tok = self.noalias.ref_token();
+        let head = self.head?;
+        Some(&head.borrow(tok).data)
+    }
+
+    pub fn front_mut(&mut self) -> Option<&mut T> {
+        let tok = self.noalias.mut_token();
+        let head = self.head?;
+        Some(&mut head.borrow_mut(tok).data)
+    }
+
+    pub fn pop_front(&mut self) -> Option<T> {
+        let tok = self.noalias.mut_token();
+        Self::pop_front_inner(
+            tok,
+            &mut self.head,
+            &mut self.tail,
+        )
+    }
+
+    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)
+            }
+        }
+    }
+
+    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<P<T>>,
+        tail: &mut Option<P<T>>,
+    ) -> Option<T> {
+        let deleting = (*head)?;
+        let new_head = deleting.borrow(&tok).next;
+        *head = new_head;
+        if let Some(new_head) = new_head {
+            new_head.borrow_mut(&mut tok).back = None;
+        } else {
+            *tail = None;
+        }
+        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> {
+    fn drop(&mut self) {
+        while let Some(_) = Self::pop_front_inner(
+            self.noalias.mut_token(),
+            &mut self.head,
+            &mut self.tail,
+        ) { }
+    }
+}
+