| Crates.io | atomic_list |
| lib.rs | atomic_list |
| version | 2.0.0 |
| created_at | 2025-11-05 01:50:36.146456+00 |
| updated_at | 2026-01-24 01:04:48.080233+00 |
| description | Lock-free circular ring of intrusive ref-counted nodes plus shared cursors. |
| homepage | |
| repository | https://github.com/orkking2/AtomicList |
| max_upload_size | |
| id | 1917290 |
| size | 82,003 |
AtomicList is an experimental circular list built directly from intrusive,
reference-counted nodes. The crate ships nodes and cursors only—there is no
separate list container—so you keep a Node<T> (and optionally a shared
cursor::Cursor) as your handle into the ring. A sync::Node<T> acts like a
tiny Arc<T> that also stores strong and weak successors, letting CAS
loops splice nodes in and out of a ring without locks or external hazard-pointer
schemes.
Node<T> / WeakNode<T>: Arc/Weak-like handles with embedded successor edges.push_before, pop_when, and remove rearrange
a ring while maintaining the self-loop invariants on detached nodes.load_next_* plus resolve_next follow weak
breadcrumbs after a node has been popped out.cursor::Cursor is an atomic cursor that multiple holders
advance together.atm_p exports generic atomic pointer wrappers used by the
list but also usable for Arc/Weak.use atomic_list::sync::Node;
let root = Node::new("root");
root.push_before("worker-1", |cur| *cur == "root").unwrap();
root.push_before("worker-2", |_| true).unwrap();
// Remove the first node whose payload ends with "1".
let removed = Node::pop_when(&root, |cur| cur.ends_with('1')).unwrap();
assert_eq!(*removed, "worker-1");
// The ring closes back over the gap.
let worker_2 = Node::load_next_strong(&root);
assert_eq!(worker_2.to_string(), "worker-2");
assert!(Node::ptr_eq(
&Node::load_next_strong(&worker_2),
&root
));
// Detached nodes keep a weak breadcrumb into the live ring.
assert_eq!(
Node::resolve_next(&removed).unwrap().to_string(),
"root"
);
assert_eq!(Node::into_inner(removed), Some("worker-1"));
use atomic_list::{cursor::Cursor, sync::Node};
let head = Node::new(0);
for i in 1..=3 {
head.push_before(i, |_| true).unwrap();
}
// Multiple holders share the same atomic cursor position.
let mut cursor_a = Cursor::new(head.clone());
let mut cursor_b = cursor_a.clone();
assert_eq!(*cursor_a.next().unwrap(), 3);
assert_eq!(*cursor_b.next().unwrap(), 3);
// Advancing from either handle moves everyone forward.
assert_eq!(*cursor_a.next().unwrap(), 2);
assert_eq!(*cursor_b.next().unwrap(), 2);
AtomicList struct; hang on to a Node<T> as your entry
point into the ring.This project is distributed under the terms of the MIT license. See LICENSE for details.