fuchsia_rcu/
rcu_option_box.rs1use crate::rcu_ptr::{RcuPtr, RcuReadGuard};
6use crate::rcu_read_scope::RcuReadScope;
7use crate::state_machine::rcu_drop;
8
9#[derive(Debug)]
14pub struct RcuOptionBox<T: Send + Sync + 'static> {
15 ptr: RcuPtr<T>,
16}
17
18impl<T: Send + Sync + 'static> RcuOptionBox<T> {
19 pub fn new(data: Option<T>) -> Self {
21 Self::from(data.map(|data| Box::new(data)))
22 }
23
24 pub fn read(&self) -> Option<RcuReadGuard<T>> {
29 self.ptr.maybe_get()
30 }
31
32 pub fn as_ref<'a>(&self, scope: &'a RcuReadScope) -> Option<&'a T> {
37 self.ptr.read(scope).as_ref()
38 }
39
40 pub fn update(&self, data: Option<T>) {
45 let ptr = data.map(|data| Box::into_raw(Box::new(data))).unwrap_or(std::ptr::null_mut());
46 unsafe { self.replace(ptr) };
48 }
49
50 unsafe fn replace(&self, ptr: *mut T) {
56 let old_ptr = self.ptr.replace(ptr);
57 if !old_ptr.is_null() {
58 let object = unsafe { Box::from_raw(old_ptr) };
60 rcu_drop(object);
61 }
62 }
63}
64
65impl<T: Clone + Send + Sync + 'static> RcuOptionBox<T> {
66 pub fn cloned(&self) -> Option<T> {
70 self.as_ref(&RcuReadScope::new()).cloned()
71 }
72}
73
74impl<T: Send + Sync + 'static> Drop for RcuOptionBox<T> {
75 fn drop(&mut self) {
76 unsafe { self.replace(std::ptr::null_mut()) };
78 }
79}
80
81impl<T: Send + Sync + 'static> Default for RcuOptionBox<T> {
82 fn default() -> Self {
83 Self::new(None)
84 }
85}
86
87impl<T: Clone + Send + Sync + 'static> Clone for RcuOptionBox<T> {
88 fn clone(&self) -> Self {
89 let value = self.read();
90 Self::new(value.map(|value| value.clone()))
91 }
92}
93
94impl<T: Send + Sync + 'static> From<Option<Box<T>>> for RcuOptionBox<T> {
95 fn from(value: Option<Box<T>>) -> Self {
96 let ptr = value.map(|value| Box::into_raw(value)).unwrap_or(std::ptr::null_mut());
97 Self { ptr: RcuPtr::new(ptr) }
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use crate::state_machine::rcu_synchronize;
105 use std::ops::Deref;
106
107 #[test]
108 fn test_rcu_option_cell() {
109 let value = RcuOptionBox::new(Some(42));
110 assert_eq!(value.read().unwrap().deref(), &42);
111
112 let value = RcuOptionBox::<i32>::new(None);
113 assert!(value.read().is_none());
114 }
115
116 #[test]
117 fn test_rcu_option_cell_set_deferred() {
118 let value = RcuOptionBox::new(Some(42));
119 value.update(Some(43));
120 assert_eq!(value.read().unwrap().deref(), &43);
121
122 value.update(None);
123 assert!(value.read().is_none());
124
125 rcu_synchronize();
126 assert!(value.read().is_none());
127 }
128
129 #[test]
130 fn test_rcu_option_cell_drop() {
131 let value = RcuOptionBox::new(Some(42));
132 drop(value);
133 }
134}