hitbox_backend/format/rkyv.rs
1use bytes::Bytes;
2use hitbox_core::{BoxContext, Raw};
3use rkyv::util::AlignedVec;
4
5use super::{Format, FormatDeserializer, FormatError, FormatSerializer, FormatTypeId};
6use crate::context::Context;
7
8/// Rkyv format - high-performance zero-copy serialization (rkyv 0.8)
9///
10/// # Buffer Allocation
11///
12/// RkyvFormat pre-allocates a buffer to reduce reallocations during serialization.
13/// The buffer hint can be configured based on your typical payload size:
14///
15/// - Small payloads (<1KB): Use `RkyvFormat::new()` (default 4KB)
16/// - Medium payloads (1KB-100KB): Use `RkyvFormat::with_buffer_hint(16384)` (16KB)
17/// - Large payloads (>100KB): Use `RkyvFormat::with_buffer_hint(131072)` (128KB)
18///
19/// # Examples
20///
21/// ```
22/// use hitbox_backend::RkyvFormat;
23///
24/// // Default buffer size (4KB)
25/// let format = RkyvFormat::new();
26///
27/// // Custom buffer size for large payloads
28/// let format = RkyvFormat::with_buffer_hint(128 * 1024);
29/// ```
30#[cfg(feature = "rkyv_format")]
31#[cfg_attr(docsrs, doc(cfg(feature = "rkyv_format")))]
32#[derive(Debug, Clone, Copy)]
33pub struct RkyvFormat {
34 /// Initial buffer capacity hint in bytes.
35 /// Helps reduce reallocations during serialization.
36 buffer_hint: usize,
37}
38
39impl RkyvFormat {
40 /// Default buffer size (4KB) - suitable for most small to medium payloads
41 pub const DEFAULT_BUFFER_HINT: usize = 4096;
42
43 /// Creates a new RkyvFormat with the default buffer hint (4KB)
44 pub const fn new() -> Self {
45 Self {
46 buffer_hint: Self::DEFAULT_BUFFER_HINT,
47 }
48 }
49
50 /// Creates a new RkyvFormat with a custom buffer hint
51 ///
52 /// # Arguments
53 ///
54 /// * `buffer_hint` - Initial buffer capacity in bytes
55 ///
56 /// # Examples
57 ///
58 /// ```
59 /// use hitbox_backend::RkyvFormat;
60 ///
61 /// // For large payloads (128KB)
62 /// let format = RkyvFormat::with_buffer_hint(128 * 1024);
63 /// ```
64 pub const fn with_buffer_hint(buffer_hint: usize) -> Self {
65 Self { buffer_hint }
66 }
67
68 /// Returns the configured buffer hint
69 pub const fn buffer_hint(&self) -> usize {
70 self.buffer_hint
71 }
72}
73
74impl Default for RkyvFormat {
75 fn default() -> Self {
76 Self::new()
77 }
78}
79
80impl Format for RkyvFormat {
81 fn with_serializer(
82 &self,
83 f: &mut dyn FnMut(&mut FormatSerializer) -> Result<(), FormatError>,
84 _context: &dyn Context,
85 ) -> Result<Raw, FormatError> {
86 // Create a pre-allocated buffer with the configured hint
87 let mut buffer = AlignedVec::with_capacity(self.buffer_hint);
88
89 // Pass the buffer to the callback - serialization happens inside
90 {
91 let mut format_ser = FormatSerializer::Rkyv(&mut buffer);
92 f(&mut format_ser)?;
93 }
94
95 // Convert to Bytes
96 Ok(Bytes::from(buffer.into_vec()))
97 }
98
99 fn with_deserializer(
100 &self,
101 data: &[u8],
102 f: &mut dyn FnMut(&mut FormatDeserializer) -> Result<(), FormatError>,
103 _ctx: &mut BoxContext,
104 ) -> Result<(), FormatError> {
105 // For rkyv, we just pass the archived bytes directly
106 let mut format_deserializer = FormatDeserializer::Rkyv(data);
107 f(&mut format_deserializer)?;
108 Ok(())
109 }
110
111 fn clone_box(&self) -> Box<dyn Format> {
112 Box::new(*self)
113 }
114
115 fn format_type_id(&self) -> FormatTypeId {
116 FormatTypeId::Rkyv
117 }
118}