rustbridge_transport/
codec.rs1use rustbridge_core::PluginError;
4use serde::{Serialize, de::DeserializeOwned};
5use thiserror::Error;
6
7#[derive(Error, Debug)]
9pub enum CodecError {
10 #[error("serialization error: {0}")]
11 Serialization(String),
12
13 #[error("deserialization error: {0}")]
14 Deserialization(String),
15
16 #[error("invalid format: {0}")]
17 InvalidFormat(String),
18}
19
20impl From<serde_json::Error> for CodecError {
21 fn from(err: serde_json::Error) -> Self {
22 if err.is_data() || err.is_syntax() || err.is_eof() {
23 CodecError::Deserialization(err.to_string())
24 } else {
25 CodecError::Serialization(err.to_string())
26 }
27 }
28}
29
30impl From<CodecError> for PluginError {
31 fn from(err: CodecError) -> Self {
32 PluginError::SerializationError(err.to_string())
33 }
34}
35
36pub trait Codec: Send + Sync {
38 fn encode<T: Serialize>(&self, value: &T) -> Result<Vec<u8>, CodecError>;
40
41 fn decode<T: DeserializeOwned>(&self, data: &[u8]) -> Result<T, CodecError>;
43
44 fn content_type(&self) -> &'static str;
46}
47
48#[derive(Debug, Clone, Default)]
50pub struct JsonCodec {
51 pretty: bool,
53}
54
55impl JsonCodec {
56 pub fn new() -> Self {
58 Self { pretty: false }
59 }
60
61 pub fn pretty() -> Self {
63 Self { pretty: true }
64 }
65
66 pub fn encode_string<T: Serialize>(&self, value: &T) -> Result<String, CodecError> {
68 if self.pretty {
69 serde_json::to_string_pretty(value).map_err(Into::into)
70 } else {
71 serde_json::to_string(value).map_err(Into::into)
72 }
73 }
74
75 pub fn decode_str<T: DeserializeOwned>(&self, data: &str) -> Result<T, CodecError> {
77 serde_json::from_str(data).map_err(Into::into)
78 }
79}
80
81impl Codec for JsonCodec {
82 fn encode<T: Serialize>(&self, value: &T) -> Result<Vec<u8>, CodecError> {
83 if self.pretty {
84 serde_json::to_vec_pretty(value).map_err(Into::into)
85 } else {
86 serde_json::to_vec(value).map_err(Into::into)
87 }
88 }
89
90 fn decode<T: DeserializeOwned>(&self, data: &[u8]) -> Result<T, CodecError> {
91 serde_json::from_slice(data).map_err(Into::into)
92 }
93
94 fn content_type(&self) -> &'static str {
95 "application/json"
96 }
97}
98
99#[cfg(test)]
100#[path = "codec/codec_tests.rs"]
101mod codec_tests;