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
22pub trait LockLayout: Send + Sync + 'static {
24 const STATE_KIND: u8;
26 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}