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
29pub trait LockLayout: Send + Sync + 'static {
31 const STATE_KIND: u8;
33 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}