XArray
is an abstract data type functioning like an expansive array of items where each item must be an 8-byte object, such as Arc<T>
or Box<T>
.
User-stored pointers must have a minimum alignment of 4 bytes. XArray
facilitates efficient sequential access to adjacent entries,
supporting multiple concurrent reads and exclusively allowing one write operation at a time.
Add this to your Cargo.toml
:
[dependencies]
xarray = "0.1.0"
This crate is developed in no_std
environment, but std users can still use this crate with --feature="std"
:
The following section covers how to interact with XArray
including creating an XArray
, using cursors, marking, cloning, and more.
XArray
:// In std environment
extern crate alloc;
use alloc::sync::Arc;
use xarray::XArray;
// Create a new XArray instance
let mut xarray: XArray<Arc<i32>> = XArray::new();
ItemEntry
trait.
ItemEntry
for alloc::sync::Arc
and alloc::sync::Box
by default, hence std users can use them directly.extern crate alloc;
use alloc::sync::Arc;
use xarray::XArray;
let mut xarray_arc: XArray<Arc<i32>> = XArray::new();
let mut cursor = xarray_arc.cursor_mut(0);
// Store the Arc at the index range 0~10000.
for i in 0..10000 {
let value = Arc::new(i * 2);
cursor.store(value);
cursor.next();
}
cursor.reset_to(0);
for i in 0..10000 {
let value = cursor.load().unwrap();
assert!(*value.as_ref() == i * 2);
cursor.next();
}
Here is an example of declaring a SpinLock in your own project library as an inner lock for an xarray:
use crate::{SpinLock, SpinLockGuard};
impl<T> MutexLock<T> for SpinLock<T> {
type Target<'a> = SpinLockGuard<'a, T>
where T: 'a;
fn new(inner: T) -> Self {
SpinLock::new(inner)
}
fn lock(&self) -> Self::Target<'_> {
self.lock().unwrap()
}
}
abstract_lock_to!(SpinLock, MySpinLock);
let mut xarray_arc: XArray<Arc<i32>, MySpinLock> = XArray::new();
MySpinLock
is a HKT(Higher-Kind Type) abstraction for crate::SpinLock
.MutexLock
trait.std::sync::Mutex
to StdMutex
and set it as the default inner lock for std users.Here is an example of using marks for the stored pages in the XArray, where PageMark represents the states of each individual Page:
extern crate alloc;
use alloc::sync::Arc;
use xarray::{XArray, XMark, StdMutex};
#[derive(Clone, Copy)]
enum PageMark {
DirtyPage
...
}
impl From<PageState> for XMark {
fn from(mark: PageState) -> Self {
match mark {
PageState::DirtyPage => Self::Mark0,
...
}
}
}
let mut pages: XArray<Page, StdMutex, PageState> = XArray::new();
let mut cursor = pages.cursor_mut(1000);
cursor.store(Page::alloc_zero());
// Mark the Page as DirtyPage.
cursor.set_mark(PageState::DirtyPage).unwrap();
assert!(cursor.is_marked(PageState::DirtyPage));
XArray
can have up to three distinct marks by default, with each mark independently maintained.M
for marks, they should implement From<M>
trait for XMark
and declare M
in the generics list of XArray.use std::sync::Arc;
use xarray::{XArray};
let mut xarray: XArray<Arc<i32>> = XArray::new();
// Store values
let value = Arc::new(10);
xarray.store(1, value.clone());
assert_eq!(*xarray.load(1).unwrap().as_ref(), 10);
// Clone the XArray
let mut xarray_clone = xarray.clone();
assert_eq!(*xarray_clone.load(1).unwrap().as_ref(), 10);
// Store a new value in the clone
let new_value = Arc::new(100);
xarray_clone.store(1, new_value);
// The original XArray is unaffected by changes in the clone
assert_eq!(*xarray.load(1).unwrap().as_ref(), 10);
assert_eq!(*xarray_clone.load(1).unwrap().as_ref(), 100);
use std::sync::Arc;
use xarray::XArray;
let mut xarray: XArray<Arc<i32>> = XArray::new();
// Store item to even index in the range 100~200.
for i in 100..200 {
if i % 2 == 0 {
let value = Arc::new(i * 2);
cursor.store(value);
}
cursor.next();
}
// Iterate at the range 100~200.
let mut count = 0;
for item in xarray.range(100..200) {
count += 1;
}
assert_eq!(count == 50);