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