Skip to main content

agave_event_system/
queue_cell.rs

1use wincode_dynamic::SerializedSize;
2
3/// This ByteArray trait is a workaround as [`generic-const-exprs`](https://doc.rust-lang.org/beta/unstable-book/language-features/generic-const-exprs.html)
4/// is not yet stable.
5///
6/// The trait is sealed, so only `[u8; N]` can be used as a queue cell:
7///
8/// ```compile_fail
9/// # use agave_event_system::{
10/// #     Event,
11/// #     wincode::{SchemaRead, SchemaWrite},
12/// #     wincode_dynamic::SchemaDynamic,
13/// # };
14/// #[derive(SchemaRead, SchemaWrite, SchemaDynamic)]
15/// #[wincode(crate = "agave_event_system::__private::event_macro")]
16/// struct Message {
17///     value: u64,
18/// }
19///
20/// impl Event for Message {
21///     type QueueCell = [u64; 1];
22/// }
23/// ```
24pub trait ByteArray: sealed::Sealed + Copy + Send + Sync + AsMut<[u8]> + 'static {}
25
26impl<const N: usize> ByteArray for [u8; N] {}
27
28/// internal module such that Sealed is only implemented for `[u8; N]` to keep ByteArray's contract
29mod sealed {
30    pub trait Sealed {}
31
32    impl<const N: usize> Sealed for [u8; N] {}
33}
34
35// The function is hidden from docs as it's only intended for macro expansion.
36#[doc(hidden)]
37pub const fn event_queue_cell_size(
38    size: SerializedSize,
39    max_serialized_size: Option<usize>,
40) -> usize {
41    match size {
42        SerializedSize::Static(size) => size,
43        SerializedSize::Dynamic(lower_bound) => match max_serialized_size {
44            Some(max_serialized_size) if max_serialized_size > lower_bound => max_serialized_size,
45            Some(_) => {
46                panic!(
47                    "`max_serialized_size` must be greater than wincode's dynamic serialized-size \
48                     lower bound"
49                )
50            }
51            None => {
52                panic!(
53                    "event has a dynamic serialized size; specify `max_serialized_size` in the \
54                     `#[event(...)]` attribute"
55                )
56            }
57        },
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use {super::event_queue_cell_size, wincode_dynamic::SerializedSize};
64
65    #[test]
66    fn static_size_uses_wincode_upper_bound() {
67        assert_eq!(event_queue_cell_size(SerializedSize::Static(8), None), 8);
68        assert_eq!(
69            event_queue_cell_size(SerializedSize::Static(8), Some(16)),
70            8
71        );
72    }
73
74    #[test]
75    fn dynamic_size_uses_explicit_upper_bound() {
76        assert_eq!(
77            event_queue_cell_size(SerializedSize::Dynamic(8), Some(16)),
78            16
79        );
80    }
81
82    #[test]
83    #[should_panic(expected = "event has a dynamic serialized size")]
84    fn dynamic_size_requires_explicit_upper_bound() {
85        event_queue_cell_size(SerializedSize::Dynamic(8), None);
86    }
87
88    #[test]
89    #[should_panic(expected = "must be greater than")]
90    fn dynamic_size_rejects_bound_equal_to_lower_bound() {
91        event_queue_cell_size(SerializedSize::Dynamic(8), Some(8));
92    }
93
94    #[test]
95    #[should_panic(expected = "must be greater than")]
96    fn dynamic_size_rejects_bound_below_lower_bound() {
97        event_queue_cell_size(SerializedSize::Dynamic(8), Some(7));
98    }
99}