asteroid_mq_model/
codec.rs1use std::{
2 borrow::Cow,
3 collections::{HashMap, HashSet},
4 fmt::Display,
5 str::FromStr,
6 sync::Arc,
7};
8#[cfg(feature = "bincode")]
9mod bincode;
10#[cfg(feature = "bincode")]
11pub use bincode::*;
12#[cfg(feature = "cbor")]
13mod cbor;
14#[cfg(feature = "cbor")]
15pub use cbor::*;
16mod json;
17pub use json::*;
18
19use crate::EdgePayload;
20
21#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22#[repr(transparent)]
23#[derive(serde::Serialize, serde::Deserialize)]
24#[serde(transparent)]
25pub struct CodecKind(pub u8);
26
27impl CodecKind {
28 pub const CBOR: Self = Self(0x00);
29 pub const BINCODE: Self = Self(0x01);
30 pub const JSON: Self = Self(0x40);
31}
32
33impl FromStr for CodecKind {
34 type Err = &'static str;
35 fn from_str(s: &str) -> Result<Self, Self::Err> {
36 match s {
37 "cbor" => Ok(Self::CBOR),
38 "bincode" => Ok(Self::BINCODE),
39 "json" => Ok(Self::JSON),
40 _ => u8::from_str_radix(s, 16)
41 .map(Self)
42 .map_err(|_| "invalid codec kind"),
43 }
44 }
45}
46
47impl Display for CodecKind {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 match *self {
50 CodecKind::CBOR => write!(f, "CBOR"),
51 CodecKind::BINCODE => write!(f, "Bincode"),
52 CodecKind::JSON => write!(f, "JSON"),
53 _ => write!(f, "Unknown({:02x})", self.0),
54 }
55 }
56}
57
58#[derive(Debug)]
59pub struct CodecError {
60 reason: Cow<'static, str>,
61}
62
63impl std::fmt::Display for CodecError {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 write!(f, "codec error: {}", self.reason)
66 }
67}
68impl std::error::Error for CodecError {}
69
70impl CodecError {
71 pub fn decode_error<E: std::fmt::Display>(e: E) -> Self {
72 Self {
73 reason: format!("decode error: {}", e).into(),
74 }
75 }
76 pub fn encode_error<E: std::fmt::Display>(e: E) -> Self {
77 Self {
78 reason: format!("encode error: {}", e).into(),
79 }
80 }
81 pub fn unregistered_codec(codec: CodecKind) -> Self {
82 Self {
83 reason: format!("unregistered codec: {}", codec).into(),
84 }
85 }
86}
87
88pub trait Codec: Send + Sync + 'static {
89 fn encode(&self, value: &EdgePayload) -> Result<Vec<u8>, CodecError>;
90 fn decode(&self, bytes: &[u8]) -> Result<EdgePayload, CodecError>;
91 fn kind(&self) -> CodecKind;
92}
93#[derive(Clone)]
94pub struct DynCodec {
95 codec: Arc<dyn Codec>,
96}
97
98impl std::fmt::Debug for DynCodec {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 f.debug_struct("DynCodec")
101 .field("kind", &self.codec.kind())
102 .finish()
103 }
104}
105
106impl Codec for DynCodec {
107 fn encode(&self, value: &EdgePayload) -> Result<Vec<u8>, CodecError> {
108 self.codec.encode(value)
109 }
110 fn decode(&self, bytes: &[u8]) -> Result<EdgePayload, CodecError> {
111 self.codec.decode(bytes)
112 }
113 fn kind(&self) -> CodecKind {
114 self.codec.kind()
115 }
116}
117
118impl DynCodec {
119 pub fn new<C: Codec>(codec: C) -> Self {
120 Self {
121 codec: Arc::new(codec),
122 }
123 }
124 pub fn form_kind(kind: CodecKind) -> Option<Self> {
125 match kind {
126 #[cfg(feature = "cbor")]
127 CodecKind::CBOR => Some(Self::new(cbor::Cbor)),
128 CodecKind::BINCODE => Some(Self::new(bincode::Bincode)),
129 CodecKind::JSON => Some(Self::new(json::Json)),
130 _ => None,
131 }
132 }
133}
134
135pub struct CodecRegistry {
136 registry: HashMap<CodecKind, Arc<dyn Codec>>,
137}
138
139impl std::fmt::Debug for CodecRegistry {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 f.debug_set().entries(self.registry.keys()).finish()
142 }
143}
144
145impl CodecRegistry {
146 pub fn new_empty() -> Self {
147 Self {
148 registry: HashMap::new(),
149 }
150 }
151 pub fn new_preloaded() -> Self {
152 let mut registry = Self::new_empty();
153 #[cfg(feature = "cbor")]
154 registry.register(CodecKind::CBOR, cbor::Cbor);
155 registry.register(CodecKind::BINCODE, bincode::Bincode);
156 registry.register(CodecKind::JSON, json::Json);
157 registry
158 }
159 pub fn register<C: Codec + 'static>(&mut self, kind: CodecKind, codec: C) {
160 self.registry.insert(kind, Arc::new(codec));
161 }
162 pub fn get(&self, kind: &CodecKind) -> Option<Arc<dyn Codec>> {
163 self.registry.get(kind).cloned()
164 }
165 pub fn pick_preferred_codec(&self, supported: &HashSet<CodecKind>) -> Option<CodecKind> {
166 supported
167 .iter()
168 .find(|kind| self.registry.contains_key(kind))
169 .copied()
170 }
171 pub fn encode(&self, kind: CodecKind, value: &EdgePayload) -> Result<Vec<u8>, CodecError> {
172 self.registry
173 .get(&kind)
174 .ok_or_else(|| CodecError::unregistered_codec(kind))
175 .and_then(|codec| codec.encode(value))
176 }
177 pub fn decode(&self, kind: CodecKind, bytes: &[u8]) -> Result<EdgePayload, CodecError> {
178 self.registry
179 .get(&kind)
180 .ok_or_else(|| CodecError::unregistered_codec(kind))
181 .and_then(|codec| codec.decode(bytes))
182 }
183}