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 = RingSpec::per_node(
51 L::EVENT_RING_SPEC.capacity,
52 L::EVENT_RING_SPEC.payload_capacity,
53 );
54}
55
56pub(crate) fn validate<L: LockLayout>() -> Result<()> {
57 if L::STATE_KIND == L::EVENT_RING_KIND {
58 return Err(Error::InvalidLayout(
59 "state and event-ring kinds must differ",
60 ));
61 }
62 if L::EVENT_RING_SPEC.topology != RingTopology::PerNode {
63 return Err(Error::InvalidLayout(
64 "the lock event ring must use per-node lanes",
65 ));
66 }
67 if L::EVENT_RING_SPEC.capacity == 0 || !L::EVENT_RING_SPEC.capacity.is_power_of_two() {
68 return Err(Error::InvalidLayout(
69 "event-ring capacity must be a non-zero power of two",
70 ));
71 }
72 if L::EVENT_RING_SPEC.payload_capacity < crate::protocol::EVENT_HEADER_LEN + 2 {
73 return Err(Error::InvalidLayout(
74 "event-ring payload cannot fit a lock event",
75 ));
76 }
77 Ok(())
78}