musli_serde/lib.rs
1//! [<img alt="github" src="https://img.shields.io/badge/github-udoprog/musli-8da0cb?style=for-the-badge&logo=github" height="20">](https://github.com/udoprog/musli)
2//! [<img alt="crates.io" src="https://img.shields.io/crates/v/musli-serde.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/musli-serde)
3//! [<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-musli--serde-66c2a5?style=for-the-badge&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/musli-serde)
4//!
5//! Transparent shim to use [`serde`] types in Müsli.
6//!
7//! This conveniently and transparently allows Müsli to use fields which are
8//! serde types by marking them with `#[musli(with = musli_serde)]`. This can
9//! be useful because there is a wide ecosystem of types which implements serde
10//! traits.
11//!
12//! Note that the exact method that fields are serialized and deserialized will
13//! not match what Müsli does, since serde requires the use of a fundamentally
14//! different model and Müsli metadata such as `#[musli(name = ..)]` is not
15//! available in [`serde`].
16//!
17//! <br>
18//!
19//! ## Examples
20//!
21//! ```
22//! use serde::{Serialize, Deserialize};
23//! use musli::{Encode, Decode};
24//! use url::Url;
25//!
26//! #[derive(Serialize, Deserialize)]
27//! struct Address {
28//! street: String,
29//! city: String,
30//! zip: u32,
31//! }
32//!
33//! #[derive(Encode, Decode)]
34//! #[musli(name_all = "name")]
35//! struct Person {
36//! name: String,
37//! #[musli(with = musli_serde)]
38//! address: Address,
39//! #[musli(with = musli_serde)]
40//! url: Url,
41//! }
42//! ```
43//!
44//! A compatible Müsli structure would look like this:
45//!
46//! ```
47//! use musli::{Encode, Decode};
48//! use url::Url;
49//! # use serde::{Serialize, Deserialize};
50//! # #[derive(Serialize, Deserialize)]
51//! # struct Address { street: String, city: String, zip: u32 }
52//! # #[derive(Encode, Decode)]
53//! # #[musli(name_all = "name")]
54//! # struct Person { name: String, #[musli(with = musli_serde)] address: Address, #[musli(with = musli_serde)] url: Url }
55//!
56//! #[derive(Encode, Decode)]
57//! #[musli(name_all = "name")]
58//! struct MusliAddress {
59//! street: String,
60//! city: String,
61//! zip: u32,
62//! }
63//!
64//! #[derive(Encode, Decode)]
65//! #[musli(name_all = "name")]
66//! struct MusliPerson {
67//! name: String,
68//! address: MusliAddress,
69//! url: String,
70//! }
71//!
72//! let json = musli_json::to_string(&Person {
73//! name: "John Doe".to_string(),
74//! address: Address {
75//! street: "Main St.".to_string(),
76//! city: "Springfield".to_string(),
77//! zip: 12345,
78//! },
79//! url: Url::parse("https://example.com")?,
80//! })?;
81//!
82//! let musli = musli_json::from_str::<MusliPerson>(&json)?;
83//!
84//! assert_eq!(musli.name, "John Doe");
85//! assert_eq!(musli.address.street, "Main St.");
86//! assert_eq!(musli.address.city, "Springfield");
87//! assert_eq!(musli.address.zip, 12345);
88//! assert_eq!(musli.url, "https://example.com/");
89//! # Ok::<_, Box<dyn std::error::Error>>(())
90//! ```
91//!
92//! [`serde`]: https://serde.rs
93
94#![no_std]
95
96#[cfg(feature = "std")]
97extern crate std;
98
99#[cfg(feature = "alloc")]
100extern crate alloc;
101
102mod deserializer;
103mod error;
104mod serializer;
105
106use core::cell::RefCell;
107use core::fmt;
108
109use musli::context::StdError;
110use musli::{Context, Decoder, Encoder};
111use serde::{Deserialize, Serialize};
112
113use self::deserializer::Deserializer;
114use self::serializer::Serializer;
115
116use musli_utils::buf::{self, BufString};
117
118struct SerdeContext<'a, C>
119where
120 C: ?Sized + Context,
121{
122 error: RefCell<Option<C::Error>>,
123 inner: &'a C,
124}
125
126impl<'a, C> Context for SerdeContext<'a, C>
127where
128 C: ?Sized + Context,
129{
130 type Mode = C::Mode;
131 type Error = error::SerdeError;
132 type Mark = C::Mark;
133 type Buf<'this> = C::Buf<'this>
134 where
135 Self: 'this;
136 type BufString<'this> = BufString<C::Buf<'this>>
137 where
138 Self: 'this;
139
140 #[inline]
141 fn clear(&self) {
142 self.inner.clear();
143 *self.error.borrow_mut() = None;
144 }
145
146 #[inline]
147 fn mark(&self) -> Self::Mark {
148 self.inner.mark()
149 }
150
151 #[inline]
152 fn alloc(&self) -> Option<Self::Buf<'_>> {
153 self.inner.alloc()
154 }
155
156 #[inline]
157 fn collect_string<T>(&self, value: &T) -> Result<Self::BufString<'_>, Self::Error>
158 where
159 T: ?Sized + fmt::Display,
160 {
161 buf::collect_string(self, value)
162 }
163
164 #[inline]
165 fn custom<T>(&self, error: T) -> Self::Error
166 where
167 T: 'static + Send + Sync + StdError,
168 {
169 *self.error.borrow_mut() = Some(self.inner.custom(error));
170 error::SerdeError::Captured
171 }
172
173 #[inline]
174 fn message<T>(&self, message: T) -> Self::Error
175 where
176 T: fmt::Display,
177 {
178 *self.error.borrow_mut() = Some(self.inner.message(message));
179 error::SerdeError::Captured
180 }
181}
182
183/// Encode the given serde value `T` to the given [Encoder] using the serde
184/// compatibility layer.
185pub fn encode<E, T>(value: &T, cx: &E::Cx, encoder: E) -> Result<E::Ok, E::Error>
186where
187 E: Encoder,
188 T: Serialize,
189{
190 let cx = SerdeContext {
191 error: RefCell::new(None),
192 inner: cx,
193 };
194
195 let encoder = encoder.with_context(&cx)?;
196
197 let serializer = Serializer::new(&cx, encoder);
198
199 let error = match value.serialize(serializer) {
200 Ok(value) => return Ok(value),
201 Err(error) => error,
202 };
203
204 if let Some(error) = error.report(cx.inner) {
205 return Err(error);
206 }
207
208 let Some(error) = cx.error.borrow_mut().take() else {
209 return Err(cx.inner.message("error during encoding (no information)"));
210 };
211
212 Err(error)
213}
214
215/// Decode the given serde value `T` from the given [Decoder] using the serde
216/// compatibility layer.
217pub fn decode<'de, D, T>(cx: &D::Cx, decoder: D) -> Result<T, D::Error>
218where
219 D: Decoder<'de>,
220 T: Deserialize<'de>,
221{
222 let cx = SerdeContext {
223 error: RefCell::new(None),
224 inner: cx,
225 };
226
227 let decoder = decoder.with_context(&cx)?;
228
229 let deserializer = Deserializer::new(&cx, decoder);
230
231 let error = match T::deserialize(deserializer) {
232 Ok(value) => return Ok(value),
233 Err(error) => error,
234 };
235
236 if let Some(error) = error.report(cx.inner) {
237 return Err(error);
238 }
239
240 let Some(error) = cx.error.borrow_mut().take() else {
241 return Err(cx.inner.message("error during encoding (no information)"));
242 };
243
244 Err(error)
245}