irc only.Expand description
Intrusive Reference Counter (Irc)
Irc is an intrusive reference counting smart pointer, similar to Arc but without weak reference support.
It requires the inner type to implement IrcItem trait to provide a counter field.
The underlayer of Irc is customizable (default to be Box),
unlike Arc which wrap a hidden ArcInner on your inner types,
Irc use the pointer of your inner types by Pointer::into_raw
The atomic ordering is mostly the same with std Arc (miri test cases verified)
§Benefits
-
No need to manual implementing the inc / dec on counter.
-
No enforced weak counter if you don’t need it (every atomic op has cost).
-
Customized counter type (not limited to AtomicUsize)
-
IrcItem::on_drop in the trait allow you to have the ownship of underlying inner memory after the reference count of Irc is dropped. And you only need to define the drop behavior once, instead of write the same logic
Arc::into_innerin every possible places (If forgetting so make your code block and hard to debug). -
Using
Ircto wrap aBox, no additional memory allocation and memory fragmentation, no additional dereference cost (than usingArc<Box<T>>) -
You can allocate a box from the time of its birth and wrap it will
Ircfor temporary usage, don’t need to move bytes from / to stack. (especially when the inner object is large) -
Advanced usage, multiple layer customized counter, on the same heap object, while preserving the safe boundary
§Example
The follow example shows Irc wrapping a Box (You can also the same to Change the param P with Arc, or other Pointer type)
use embed_collections::irc::{Irc, IrcItem};
use core::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
use crossfire::oneshot;
use std::thread;
use std::time::Duration;
// Usually we use Irc for some large structure, but we show a simple demo here.
struct MyItem {
is_done: AtomicBool,
counter: AtomicUsize,
done_tx: Option<oneshot::TxOneshot<Box<MyItem>>>,
}
// The default parameter Tag=(), P=Box<Self>
unsafe impl IrcItem for MyItem {
type Counter = AtomicUsize;
fn counter(&self) -> &Self::Counter {
&self.counter
}
// overwrite default behavior to send the item through channel
fn on_drop(mut this: Box<Self>) {
let done_tx = this.done_tx.take().unwrap();
done_tx.send(this);
}
}
let (done_tx, done_rx) = oneshot::oneshot();
let boxed_item = Box::new(MyItem {
is_done: AtomicBool::new(false),
counter: AtomicUsize::new(0),
done_tx: Some(done_tx),
});
// Convert from Box to Irc, which does not have additional allocation.
let item = Irc::from(boxed_item);
thread::spawn(move || {
thread::sleep(Duration::from_secs(1));
item.is_done.store(true, Ordering::SeqCst);
drop(item);
});
let item: Box<MyItem> = done_rx.recv().unwrap();
assert!(item.is_done.load(Ordering::SeqCst));Structs§
- Irc
- Intrusive reference counter, which support conversion bwteween
P.