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_SPEC: RingSpec = RingSpec::per_node(1_024, 1_024);
10
11pub trait LockLayout: Send + Sync + 'static {
13 const STATE_KIND: u8;
15 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}