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