Skip to main content

atomr_serialization_hyperion/
lib.rs

1//! atomr-serialization-hyperion.
2//!
3//! Hyperion is a CLR-specific binary serializer tightly coupled to
4//! System.Reflection. A line-by-line port is impractical in Rust. To keep
5//! the crate name reserved (matching layout) while providing
6//! useful functionality, this crate exposes a Serde/bincode-based
7//! `HyperionSerializer<T>` that implements the same
8//! [`atomr_core::serialization::Serializer`] trait used everywhere
9//! else. Wire format is **not** compatible with CLR Hyperion and is only
10//! meant to be pluggable as the default binary serializer for a pure-Rust
11//! atomr deployment.
12
13use std::marker::PhantomData;
14
15use atomr_core::serialization::{Serializer, SerializerError};
16use bincode::config;
17use serde::{de::DeserializeOwned, Serialize};
18
19/// Default identifier for the Hyperion-compat slot. reserves
20/// serializer id 7 for Hyperion; we keep the same number for parity.
21pub const HYPERION_SERIALIZER_ID: u32 = 7;
22
23pub struct HyperionSerializer<T> {
24    id: u32,
25    _marker: PhantomData<fn() -> T>,
26}
27
28impl<T> HyperionSerializer<T> {
29    pub fn new() -> Self {
30        Self { id: HYPERION_SERIALIZER_ID, _marker: PhantomData }
31    }
32
33    pub fn with_id(id: u32) -> Self {
34        Self { id, _marker: PhantomData }
35    }
36}
37
38impl<T> Default for HyperionSerializer<T> {
39    fn default() -> Self {
40        Self::new()
41    }
42}
43
44impl<T> Serializer<T> for HyperionSerializer<T>
45where
46    T: Serialize + DeserializeOwned + Send + Sync + 'static,
47{
48    fn identifier(&self) -> u32 {
49        self.id
50    }
51
52    fn manifest(&self) -> &'static str {
53        std::any::type_name::<T>()
54    }
55
56    fn to_bytes(&self, value: &T) -> Result<Vec<u8>, SerializerError> {
57        bincode::serde::encode_to_vec(value, config::standard())
58            .map_err(|e| SerializerError::Encode(e.to_string()))
59    }
60
61    fn from_bytes(&self, bytes: &[u8]) -> Result<T, SerializerError> {
62        let (v, _) = bincode::serde::decode_from_slice::<T, _>(bytes, config::standard())
63            .map_err(|e| SerializerError::Decode(e.to_string()))?;
64        Ok(v)
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71    use serde::{Deserialize, Serialize};
72
73    #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
74    struct Payload {
75        id: u32,
76        name: String,
77        tags: Vec<String>,
78    }
79
80    #[test]
81    fn round_trip_struct() {
82        let s = HyperionSerializer::<Payload>::new();
83        let p = Payload { id: 42, name: "atomr".into(), tags: vec!["cluster".into(), "streams".into()] };
84        let bytes = s.to_bytes(&p).unwrap();
85        let back = s.from_bytes(&bytes).unwrap();
86        assert_eq!(back, p);
87        assert_eq!(s.identifier(), HYPERION_SERIALIZER_ID);
88    }
89
90    #[test]
91    fn identifier_is_overridable() {
92        let s = HyperionSerializer::<u32>::with_id(42);
93        assert_eq!(s.identifier(), 42);
94    }
95}