1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
//! The `guard` module manages read access to shared memory, utilizing RAII (Resource Acquisition
//! Is Initialization) principles to control access lifecycle.
//!
//! `ReadGuard` is the primary structure in this module. On creation, `ReadGuard` provides a
//! reference to an entity in shared memory. This reference can be safely used until the
//! `grace_duration` set in the `write` method of the `synchronizer` module expires.
//!
//! `ReadGuard` relinquishes memory access rights automatically when it goes out of scope and
//! gets dropped, thus avoiding potential memory corruption due to lingering references.
//! Therefore, users must ensure all `ReadGuard` instances are dropped before `grace_duration`
//! expires.
//!
//! The `synchronizer` module utilizes this `guard` module to manage memory safety, allowing
//! users to focus on their application logic.
use rkyv::{Archive, Archived};
use std::ops::Deref;
use crate::instance::InstanceVersion;
use crate::state::State;
use crate::synchronizer::SynchronizerError;
/// An RAII implementation of a “scoped read lock” of a `State`
pub(crate) struct ReadGuard<'a> {
state: &'a mut State,
version: InstanceVersion,
}
impl<'a> ReadGuard<'a> {
/// Creates new `ReadGuard` with specified parameters
pub(crate) fn new(
state: &'a mut State,
version: InstanceVersion,
) -> Result<Self, SynchronizerError> {
state.rlock(version);
Ok(ReadGuard { version, state })
}
}
impl<'a> Drop for ReadGuard<'a> {
/// Unlocks stored `version` when `ReadGuard` goes out of scope
fn drop(&mut self) {
self.state.runlock(self.version);
}
}
/// `Synchronizer` result
pub struct ReadResult<'a, T: Archive> {
_guard: ReadGuard<'a>,
entity: &'a Archived<T>,
switched: bool,
}
impl<'a, T: Archive> ReadResult<'a, T> {
/// Creates new `ReadResult` with specified parameters
pub(crate) fn new(_guard: ReadGuard<'a>, entity: &'a Archived<T>, switched: bool) -> Self {
ReadResult {
_guard,
entity,
switched,
}
}
/// Indicates whether data was switched during last read
pub fn is_switched(&self) -> bool {
self.switched
}
}
impl<'a, T: Archive> Deref for ReadResult<'a, T> {
type Target = Archived<T>;
/// Dereferences stored `entity` for easier access
fn deref(&self) -> &Archived<T> {
self.entity
}
}