fuchsia_rcu/
rcu_option_box.rs1use 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 RcuOptionBox<T: RcuDroppable + Sync> {
17 ptr: RcuPtr<T>,
18}
19
20impl<T: RcuDroppable + Sync> RcuOptionBox<T> {
21 pub fn new(data: Option<T>) -> Self {
23 Self::from(data.map(|data| Box::new(data)))
24 }
25
26 pub fn read(&self) -> Option<RcuReadGuard<T>> {
31 self.ptr.maybe_get()
32 }
33
34 pub fn as_ref<'a>(&self, scope: &'a RcuReadScope) -> Option<&'a T> {
39 self.ptr.read(scope).as_ref()
40 }
41
42 pub fn is_some(&self, scope: &RcuReadScope) -> bool {
44 self.as_ref(scope).is_some()
45 }
46
47 pub fn is_none(&self, scope: &RcuReadScope) -> bool {
49 self.as_ref(scope).is_none()
50 }
51
52 pub fn update(&self, data: Option<T>) {
57 let ptr = data.map(|data| Box::into_raw(Box::new(data))).unwrap_or(std::ptr::null_mut());
58 unsafe { self.replace(ptr) };
60 }
61
62 unsafe fn replace(&self, ptr: *mut T) {
68 let old_ptr = self.ptr.replace(ptr);
69 if !old_ptr.is_null() {
70 let object = unsafe { Box::from_raw(old_ptr) };
72 rcu_drop(object);
73 }
74 }
75}
76
77impl<T: Clone + RcuDroppable + Sync> RcuOptionBox<T> {
78 pub fn cloned(&self) -> Option<T> {
82 self.as_ref(&RcuReadScope::new()).cloned()
83 }
84}
85
86impl<T: RcuDroppable + Sync> Drop for RcuOptionBox<T> {
87 fn drop(&mut self) {
88 unsafe { self.replace(std::ptr::null_mut()) };
90 }
91}
92
93impl<T: RcuDroppable + Sync> Default for RcuOptionBox<T> {
94 fn default() -> Self {
95 Self::new(None)
96 }
97}
98
99impl<T: Clone + RcuDroppable + Sync> Clone for RcuOptionBox<T> {
100 fn clone(&self) -> Self {
101 let value = self.read();
102 Self::new(value.map(|value| value.clone()))
103 }
104}
105
106impl<T: RcuDroppable + Sync> From<Option<Box<T>>> for RcuOptionBox<T> {
107 fn from(value: Option<Box<T>>) -> Self {
108 let ptr = value.map(|value| Box::into_raw(value)).unwrap_or(std::ptr::null_mut());
109 Self { ptr: RcuPtr::new(ptr) }
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use crate::state_machine::rcu_run_callbacks;
117 use std::ops::Deref;
118
119 #[test]
120 fn test_rcu_option_cell() {
121 let scope = RcuReadScope::new();
122 let value = RcuOptionBox::new(Some(42));
123 assert_eq!(value.read().unwrap().deref(), &42);
124 assert!(value.is_some(&scope));
125 assert!(!value.is_none(&scope));
126
127 let value = RcuOptionBox::<i32>::new(None);
128 assert!(value.read().is_none());
129 assert!(value.is_none(&scope));
130 assert!(!value.is_some(&scope));
131 }
132
133 #[test]
134 fn test_rcu_option_cell_set_deferred() {
135 let value = RcuOptionBox::new(Some(42));
136 value.update(Some(43));
137 assert_eq!(value.read().unwrap().deref(), &43);
138
139 value.update(None);
140 assert!(value.read().is_none());
141
142 rcu_run_callbacks();
143 assert!(value.read().is_none());
144 }
145
146 #[test]
147 fn test_rcu_option_cell_drop() {
148 let value = RcuOptionBox::new(Some(42));
149 drop(value);
150 }
151}