dioxus_fullstack/
encoding.rs

1use bytes::Bytes;
2use serde::{de::DeserializeOwned, Serialize};
3
4/// A trait for encoding and decoding data.
5///
6/// This takes an owned self to make it easier for zero-copy encodings.
7pub trait Encoding: 'static {
8    fn content_type() -> &'static str;
9    fn stream_content_type() -> &'static str;
10    fn to_bytes(data: impl Serialize) -> Option<Bytes> {
11        let mut buf = Vec::new();
12        Self::encode(data, &mut buf)?;
13        Some(buf.into())
14    }
15    fn encode(data: impl Serialize, buf: &mut Vec<u8>) -> Option<usize>;
16    fn decode<O: DeserializeOwned>(bytes: Bytes) -> Option<O>;
17}
18
19pub struct JsonEncoding;
20impl Encoding for JsonEncoding {
21    fn content_type() -> &'static str {
22        "application/json"
23    }
24    fn stream_content_type() -> &'static str {
25        "application/stream+json"
26    }
27
28    fn encode(data: impl Serialize, mut buf: &mut Vec<u8>) -> Option<usize> {
29        let len = buf.len();
30        serde_json::to_writer(&mut buf, &data).ok()?;
31        Some(buf.len() - len)
32    }
33
34    fn decode<O: DeserializeOwned>(bytes: Bytes) -> Option<O> {
35        serde_json::from_slice(&bytes).ok()
36    }
37}
38
39pub struct CborEncoding;
40impl Encoding for CborEncoding {
41    fn content_type() -> &'static str {
42        "application/cbor"
43    }
44    fn stream_content_type() -> &'static str {
45        "application/stream+cbor"
46    }
47
48    fn decode<O: DeserializeOwned>(bytes: Bytes) -> Option<O> {
49        ciborium::de::from_reader(bytes.as_ref()).ok()
50    }
51
52    fn encode(data: impl Serialize, mut buf: &mut Vec<u8>) -> Option<usize> {
53        let len = buf.len();
54        ciborium::into_writer(&data, &mut buf).ok()?;
55        Some(buf.len() - len)
56    }
57}
58
59#[cfg(feature = "postcard")]
60pub struct PostcardEncoding;
61#[cfg(feature = "postcard")]
62impl Encoding for PostcardEncoding {
63    fn content_type() -> &'static str {
64        "application/postcard"
65    }
66    fn stream_content_type() -> &'static str {
67        "application/stream+postcard"
68    }
69
70    fn encode(data: impl Serialize, mut buf: &mut Vec<u8>) -> Option<usize> {
71        let len = buf.len();
72        postcard::to_io(&data, &mut buf).ok()?;
73        Some(buf.len() - len)
74    }
75
76    fn decode<O: DeserializeOwned>(bytes: Bytes) -> Option<O> {
77        postcard::from_bytes(bytes.as_ref()).ok()
78    }
79}
80
81#[cfg(feature = "msgpack")]
82pub struct MsgPackEncoding;
83#[cfg(feature = "msgpack")]
84impl Encoding for MsgPackEncoding {
85    fn content_type() -> &'static str {
86        "application/msgpack"
87    }
88    fn stream_content_type() -> &'static str {
89        "application/stream+msgpack"
90    }
91    fn encode(data: impl Serialize, buf: &mut Vec<u8>) -> Option<usize> {
92        let len = buf.len();
93        rmp_serde::encode::write(buf, &data).ok()?;
94        Some(buf.len() - len)
95    }
96
97    fn decode<O: DeserializeOwned>(bytes: Bytes) -> Option<O> {
98        rmp_serde::from_slice(&bytes).ok()
99    }
100}
101
102// todo: ... add rkyv support
103// pub struct RkyvEncoding;
104// impl Encoding for RkyvEncoding {
105//     fn content_type() -> &'static str {
106//         "application/rkyv"
107//     }
108//     fn stream_content_type() -> &'static str {
109//         "application/stream+rkyv"
110//     }
111//     fn to_bytes(data: impl Serialize) -> Option<Bytes> {
112//         let mut buf = rkyv::ser::Serializer::new(rkyv::ser::AllocSerializer::new());
113//         rkyv::ser::Serializer::serialize(&mut buf, &data).ok()?;
114//         Some(Bytes::from(buf.into_inner()))
115//     }
116//     fn from_bytes<O: DeserializeOwned>(bytes: Bytes) -> Option<O> {
117//         let archived = unsafe { rkyv::archived_root::<O>(&bytes) };
118//         rkyv::Deserialize::deserialize(archived).ok()
119//     }
120// }