1use crate::rcu_ptr::{RcuPtr, RcuReadGuard};
6use crate::rcu_read_scope::RcuReadScope;
7use crate::state_machine::rcu_drop;
8
9use crate::rcu_droppable::RcuDroppable;
10
11#[derive(Debug)]
16pub struct RcuBox<T: RcuDroppable + Sync> {
17 ptr: RcuPtr<T>,
18}
19
20impl<T: RcuDroppable + Sync> RcuBox<T> {
21 pub fn new(data: T) -> Self {
23 Self::from(Box::new(data))
24 }
25
26 pub fn read(&self) -> RcuReadGuard<T> {
31 self.ptr.get()
32 }
33
34 pub fn as_ref<'a>(&self, scope: &'a RcuReadScope) -> &'a T {
39 self.ptr.read(scope).as_ref().unwrap()
40 }
41
42 pub fn update(&self, data: T) {
47 let ptr = Box::into_raw(Box::new(data));
48 unsafe { self.replace(ptr) };
50 }
51
52 unsafe fn replace(&self, ptr: *mut T) {
58 let old_ptr = self.ptr.replace(ptr);
59 let object = unsafe { Box::from_raw(old_ptr) };
60 rcu_drop(object);
61 }
62}
63
64impl<T: Clone + RcuDroppable + Sync> RcuBox<T> {
65 pub fn cloned(&self) -> T {
69 self.as_ref(&RcuReadScope::new()).clone()
70 }
71}
72
73impl<T: RcuDroppable + Sync> Drop for RcuBox<T> {
74 fn drop(&mut self) {
75 unsafe { self.replace(std::ptr::null_mut()) };
77 }
78}
79
80impl<T: Default + RcuDroppable + Sync> Default for RcuBox<T> {
81 fn default() -> Self {
82 Self::new(T::default())
83 }
84}
85
86impl<T: Clone + RcuDroppable + Sync> Clone for RcuBox<T> {
87 fn clone(&self) -> Self {
88 let value = self.read();
89 Self::new(value.clone())
90 }
91}
92
93impl<T: RcuDroppable + Sync> From<Box<T>> for RcuBox<T> {
94 fn from(value: Box<T>) -> Self {
95 Self { ptr: RcuPtr::new(Box::into_raw(value)) }
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::state_machine::rcu_run_callbacks;
103 use std::ops::Deref;
104
105 #[test]
106 fn test_rcu_cell() {
107 let value = RcuBox::new(42);
108 assert_eq!(value.read().deref(), &42);
109 }
110
111 #[test]
112 fn test_rcu_cell_set_deferred() {
113 let value = RcuBox::new(42);
114 value.update(43);
115 assert_eq!(value.read().deref(), &43);
116 rcu_run_callbacks();
117 }
118
119 #[test]
120 fn test_rcu_cell_drop() {
121 let value = RcuBox::new(42);
122 drop(value);
123 }
124}