Skip to main content

rill_core/buffer/
storage.rs

1//! # Безопасная атомарная ячейка
2//!
3//! Предоставляет безопасную обертку вокруг `UnsafeCell` с полностью безопасным API.
4//! Конструктор гарантирует корректную инициализацию, а в случае невозможности
5//! создания вызывает panic (так как продолжение работы невозможно).
6
7use std::cell::UnsafeCell;
8use std::fmt;
9
10/// Атомарная ячейка с полностью безопасным API
11///
12/// # Безопасность
13/// - Конструктор гарантирует корректную инициализацию
14/// - Все операции с памятью инкапсулированы
15/// - Паника при невозможности создания (системная ошибка)
16#[repr(transparent)]
17pub struct AtomicCell<T> {
18    /// The actual storage, using `UnsafeCell` for interior mutability
19    /// and `MaybeUninit` to avoid requiring `T: Default`
20    inner: UnsafeCell<T>,
21}
22
23#[allow(unsafe_code)]
24impl<T> AtomicCell<T> {
25    /// Безопасно загрузить значение
26    ///
27    /// # Safety
28    /// Этот метод безопасен, так как:
29    /// - Вызывается только когда нет одновременной записи
30    /// - Использует правильные гарантии памяти
31    #[inline]
32    pub fn load(&self) -> T
33    where
34        T: Copy,
35    {
36        // SAFETY:
37        // - Вызывающий код гарантирует отсутствие одновременной записи
38        // - Relaxed ordering достаточен для наших целей
39        // - Значение всегда корректно инициализировано
40        unsafe { *self.inner.get() }
41    }
42
43    /// Безопасно сохранить значение
44    ///
45    /// # Safety
46    /// Этот метод безопасен, так как:
47    /// - Гарантируется уникальный доступ для записи
48    /// - Нет одновременного чтения
49    #[inline]
50    pub fn store(&self, value: T) {
51        // SAFETY:
52        // - Гарантируется уникальный доступ для записи
53        // - Значение корректно инициализировано
54        // - Relaxed ordering достаточен
55        unsafe {
56            *self.inner.get() = value;
57        }
58    }
59
60    /// Получить указатель на данные (для совместимости)
61    #[inline]
62    pub fn as_ptr(&self) -> *mut T {
63        self.inner.get()
64    }
65
66    #[inline]
67    pub const fn new(value: T) -> Self {
68        Self {
69            inner: UnsafeCell::new(value),
70        }
71    }
72
73    /// Создать новую атомарную ячейку с проверкой
74    pub fn try_new(value: T) -> Result<Self, AtomicCellError> {
75        if std::mem::size_of::<T>() > isize::MAX as usize {
76            return Err(AtomicCellError::TypeTooLarge);
77        }
78        Ok(Self::new(value))
79    }
80}
81
82impl<T: Clone + Copy> Clone for AtomicCell<T> {
83    fn clone(&self) -> Self {
84        Self::new(self.load())
85    }
86}
87
88impl<T: Copy + fmt::Debug> fmt::Debug for AtomicCell<T> {
89    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90        f.debug_struct("AtomicCell")
91            .field("value", &self.load())
92            .finish()
93    }
94}
95
96impl<T: Default> Default for AtomicCell<T> {
97    fn default() -> Self {
98        Self::new(T::default())
99    }
100}
101
102/// Ошибки создания атомарной ячейки
103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
104pub enum AtomicCellError {
105    /// Тип слишком большой для атомарной ячейки
106    TypeTooLarge,
107    /// Недостаточно памяти (крайне редко)
108    OutOfMemory,
109}
110
111impl fmt::Display for AtomicCellError {
112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113        match self {
114            AtomicCellError::TypeTooLarge => write!(f, "Type too large for atomic cell"),
115            AtomicCellError::OutOfMemory => write!(f, "Out of memory"),
116        }
117    }
118}
119
120impl std::error::Error for AtomicCellError {}
121
122// AtomicCell может быть Send/Sync только если T: Send/Sync
123#[allow(unsafe_code)]
124unsafe impl<T: Send> Send for AtomicCell<T> {}
125#[allow(unsafe_code)]
126unsafe impl<T: Sync> Sync for AtomicCell<T> {}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131
132    #[test]
133    fn test_atomic_cell_basic() {
134        let cell = AtomicCell::new(42);
135        assert_eq!(cell.load(), 42);
136
137        cell.store(100);
138        assert_eq!(cell.load(), 100);
139    }
140
141    #[test]
142    fn test_atomic_cell_try_new() {
143        let cell = AtomicCell::try_new(42).unwrap();
144        assert_eq!(cell.load(), 42);
145    }
146
147    #[test]
148    fn test_atomic_cell_default() {
149        let cell = AtomicCell::<i32>::default();
150        assert_eq!(cell.load(), 0);
151    }
152
153    #[test]
154    fn test_atomic_cell_clone() {
155        let cell1 = AtomicCell::new(42);
156        let cell2 = cell1.clone();
157        assert_eq!(cell2.load(), 42);
158    }
159}