Skip to main content

orbit_lock/
layout.rs

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