Skip to main content

orbit_lock/
layout.rs

1use std::marker::PhantomData;
2
3use orbit_core::{OrbitTyped, RingSpec, RingTopology};
4
5use crate::{Error, Result};
6
7pub const LOCK_STATE_KIND: u8 = 228;
8pub const LOCK_EVENT_RING_KIND: u8 = 229;
9pub const LOCK_EVENT_RING_CAPACITY: usize =
10    orbit_core::compile::usize_from_env(option_env!("ORBIT_LOCK_EVENT_RING_CAPACITY"), 1_024);
11pub const LOCK_EVENT_RING_PAYLOAD_CAPACITY: usize = orbit_core::compile::usize_from_env(
12    option_env!("ORBIT_LOCK_EVENT_RING_PAYLOAD_CAPACITY"),
13    1_024
14);
15pub const LOCK_EVENT_RING_SPEC: RingSpec =
16    RingSpec::per_node(LOCK_EVENT_RING_CAPACITY, LOCK_EVENT_RING_PAYLOAD_CAPACITY);
17
18const _: () = assert!(LOCK_EVENT_RING_CAPACITY.is_power_of_two());
19const _: () = assert!(LOCK_EVENT_RING_PAYLOAD_CAPACITY >= crate::protocol::EVENT_HEADER_LEN + 2);
20const _: () = assert!(LOCK_EVENT_RING_PAYLOAD_CAPACITY <= u32::MAX as usize);
21
22/// Physical Orbit surfaces used by one lock domain.
23pub trait LockLayout: Send + Sync + 'static {
24    /// Kind used to name the current-state SHM object and mint lock ids.
25    const STATE_KIND: u8;
26    /// Kind used by the notified transition ring.
27    const EVENT_RING_KIND: u8;
28    const EVENT_RING_SPEC: RingSpec;
29}
30
31#[derive(Clone, Copy, Debug, Default)]
32pub struct DefaultLockLayout;
33
34impl LockLayout for DefaultLockLayout {
35    const STATE_KIND: u8 = LOCK_STATE_KIND;
36    const EVENT_RING_KIND: u8 = LOCK_EVENT_RING_KIND;
37    const EVENT_RING_SPEC: RingSpec = LOCK_EVENT_RING_SPEC;
38}
39
40pub(crate) struct LockEventRecord<L>(PhantomData<L>);
41
42impl<L> Clone for LockEventRecord<L> {
43    fn clone(&self) -> Self {
44        Self(PhantomData)
45    }
46}
47
48impl<L: LockLayout> OrbitTyped for LockEventRecord<L> {
49    const KIND: u8 = L::EVENT_RING_KIND;
50    const RING_SPEC: RingSpec =
51        RingSpec::per_node(L::EVENT_RING_SPEC.capacity, L::EVENT_RING_SPEC.payload_capacity);
52}
53
54pub(crate) fn validate<L: LockLayout>() -> Result<()> {
55    if L::STATE_KIND == L::EVENT_RING_KIND {
56        return Err(Error::InvalidLayout("state and event-ring kinds must differ"));
57    }
58    if L::EVENT_RING_SPEC.topology != RingTopology::PerNode {
59        return Err(Error::InvalidLayout("the lock event ring must use per-node lanes"));
60    }
61    if L::EVENT_RING_SPEC.capacity == 0 || !L::EVENT_RING_SPEC.capacity.is_power_of_two() {
62        return Err(Error::InvalidLayout("event-ring capacity must be a non-zero power of two"));
63    }
64    if L::EVENT_RING_SPEC.payload_capacity < crate::protocol::EVENT_HEADER_LEN + 2 {
65        return Err(Error::InvalidLayout("event-ring payload cannot fit a lock event"));
66    }
67    Ok(())
68}