Skip to main content

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}