musli/value/mod.rs
1//! Transparent buffered values.
2//!
3//! The [`Value`] type can losslessly store and represent anything which is
4//! supported in the [Müsli data model].
5//!
6//! [Müsli data model]: crate::_help::data_model
7
8#![cfg(any(feature = "json", feature = "descriptive", feature = "value"))]
9#![cfg_attr(doc_cfg, doc(cfg(feature = "value")))]
10
11mod de;
12mod en;
13mod error;
14mod type_hint;
15mod value;
16
17use core::marker;
18
19/// Convenient result alias for use with `musli_value`.
20#[cfg(feature = "alloc")]
21#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
22pub type Result<T, E = Error> = core::result::Result<T, E>;
23
24#[doc(inline)]
25pub use self::value::{AsValueDecoder, IntoValueDecoder, Value};
26use self::value::{Number, ValueKind};
27#[doc(inline)]
28pub use error::Error;
29
30use crate::alloc::Allocator;
31#[cfg(feature = "alloc")]
32use crate::alloc::Global;
33use crate::mode::{Binary, Text};
34use crate::value::en::ValueEncoder;
35use crate::{Context, Decode, Decoder, Encode, Encoder, Options};
36
37const ENCODING_BINARY: Encoding<OPTIONS, Binary> = Encoding::new();
38const ENCODING_TEXT: Encoding<OPTIONS, Text> = Encoding::new().with_mode();
39
40/// The default options used in the value encoding and decoding.
41pub const OPTIONS: Options = crate::options::new().build();
42
43/// Encode something that implements [`Encode`] into a [`Value`] in the
44/// [`Binary`] mode.
45///
46/// # Examples
47///
48/// ```
49/// use musli::{Encode, Decode};
50/// use musli::value;
51/// use musli::mode::Binary;
52///
53/// #[derive(Debug, PartialEq, Encode, Decode)]
54/// struct Person<'de> {
55/// name: &'de str,
56/// age: u32,
57/// }
58///
59/// let person = Person { name: "Alice", age: 30 };
60/// let value = value::encode(&person)?;
61///
62/// let decoded: Person<'_> = value::decode(&value)?;
63/// assert_eq!(decoded, person);
64/// # Ok::<_, value::Error>(())
65/// ```
66#[cfg(feature = "alloc")]
67#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
68#[inline]
69pub fn encode(value: impl Encode<Binary>) -> Result<Value<Global>, Error> {
70 ENCODING_BINARY.encode(value)
71}
72
73/// Encode something that implements [`Encode`] into a [`Value`] in the
74/// [`Text`] mode.
75///
76/// # Examples
77///
78/// ```
79/// use musli::{Encode, Decode};
80/// use musli::value;
81///
82/// #[derive(Debug, PartialEq, Encode, Decode)]
83/// struct Person<'de> {
84/// name: &'de str,
85/// age: u32,
86/// }
87///
88/// let person = Person { name: "Alice", age: 30 };
89/// let value = value::encode_text(&person)?;
90///
91/// let decoded: Person<'_> = value::decode_text(&value)?;
92/// assert_eq!(decoded, person);
93/// # Ok::<_, value::Error>(())
94/// ```
95#[cfg(feature = "alloc")]
96#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
97#[inline]
98pub fn encode_text(value: impl Encode<Text>) -> Result<Value<Global>, Error> {
99 ENCODING_TEXT.encode(value)
100}
101
102/// Encode something that implements [`Encode`] into a [`Value`] using a custom
103/// [`Context`] `C` in the [`Binary`] mode.
104///
105/// A custom context allows [`Value`] encoding to be performed without an
106/// allocator.
107///
108/// # Examples
109///
110/// ```
111/// use musli::{Encode, Decode};
112/// use musli::context;
113/// use musli::value;
114///
115/// #[derive(Debug, PartialEq, Encode, Decode)]
116/// struct Person<'de> {
117/// name: &'de str,
118/// age: u32,
119/// }
120///
121/// let person = Person { name: "Alice", age: 30 };
122///
123/// let cx = context::new();
124/// let value = value::encode_with(&cx, &person)?;
125///
126/// let decoded: Person<'_> = value::decode(&value)?;
127/// assert_eq!(decoded, person);
128/// # Ok::<_, Box<dyn core::error::Error>>(())
129/// ```
130#[inline]
131pub fn encode_with<C>(cx: C, value: impl Encode<Binary>) -> Result<Value<C::Allocator>, C::Error>
132where
133 C: Context,
134{
135 ENCODING_BINARY.encode_with(cx, value)
136}
137
138/// Encode something that implements [`Encode`] into a [`Value`] using a custom
139/// [`Context`] `C` in the [`Text`] mode.
140///
141/// A custom context allows [`Value`] encoding to be performed without an
142/// allocator.
143///
144/// # Examples
145///
146/// ```
147/// use musli::{Encode, Decode};
148/// use musli::context;
149/// use musli::value;
150///
151/// #[derive(Debug, PartialEq, Encode, Decode)]
152/// struct Person<'de> {
153/// name: &'de str,
154/// age: u32,
155/// }
156///
157/// let person = Person { name: "Alice", age: 30 };
158///
159/// let cx = context::new();
160/// let value = value::encode_text_with(&cx, &person)?;
161///
162/// let decoded: Person<'_> = value::decode_text(&value)?;
163/// assert_eq!(decoded, person);
164/// # Ok::<_, Box<dyn core::error::Error>>(())
165/// ```
166#[inline]
167pub fn encode_text_with<C>(cx: C, value: impl Encode<Text>) -> Result<Value<C::Allocator>, C::Error>
168where
169 C: Context,
170{
171 ENCODING_TEXT.encode_with(cx, value)
172}
173
174/// Decode a [`Value`] into a type which implements [`Decode`] in the [`Binary`]
175/// mode.
176///
177/// # Examples
178///
179/// ```
180/// use musli::{Encode, Decode};
181/// use musli::value;
182///
183/// #[derive(Debug, PartialEq, Encode, Decode)]
184/// struct Person<'de> {
185/// name: &'de str,
186/// age: u32,
187/// }
188///
189/// let person = Person { name: "Alice", age: 30 };
190/// let encoded = value::encode(&person)?;
191///
192/// let decoded: Person<'_> = value::decode(&encoded)?;
193/// assert_eq!(decoded, person);
194/// # Ok::<_, value::Error>(())
195/// ```
196#[cfg(feature = "alloc")]
197#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
198#[inline]
199pub fn decode<'de, T>(value: &'de Value<impl Allocator>) -> Result<T, Error>
200where
201 T: Decode<'de, Binary, Global>,
202{
203 ENCODING_BINARY.decode(value)
204}
205
206/// Decode a [`Value`] into a type which implements [`Decode`] in the [`Text`]
207/// mode.
208///
209/// # Examples
210///
211/// ```
212/// use musli::{Encode, Decode};
213/// use musli::value;
214///
215/// #[derive(Debug, PartialEq, Encode, Decode)]
216/// struct Person<'de> {
217/// name: &'de str,
218/// age: u32,
219/// }
220///
221/// let person = Person { name: "Alice", age: 30 };
222/// let encoded = value::encode_text(&person)?;
223///
224/// let decoded: Person<'_> = value::decode_text(&encoded)?;
225/// assert_eq!(decoded, person);
226/// # Ok::<_, value::Error>(())
227/// ```
228#[cfg(feature = "alloc")]
229#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
230#[inline]
231pub fn decode_text<'de, T>(value: &'de Value<impl Allocator>) -> Result<T, Error>
232where
233 T: Decode<'de, Text, Global>,
234{
235 ENCODING_TEXT.decode(value)
236}
237
238/// Decode a [`Value`] into a type which implements [`Decode`] using a custom
239/// [`Context`] `C` in the [`Binary`] mode.
240///
241/// A custom context allows [`Value`] decoding to be performed without an
242/// allocator.
243///
244/// # Examples
245///
246/// ```
247/// use musli::{Encode, Decode};
248/// use musli::context;
249/// use musli::value;
250///
251/// #[derive(Debug, PartialEq, Encode, Decode)]
252/// struct Person<'de> {
253/// name: &'de str,
254/// age: u32,
255/// }
256///
257/// let person = Person { name: "Alice", age: 30 };
258/// let value = value::encode(&person)?;
259///
260/// let cx = context::new();
261/// let decoded: Person<'_> = value::decode_with(&cx, &value)?;
262/// assert_eq!(decoded, person);
263/// # Ok::<_, Box<dyn core::error::Error>>(())
264/// ```
265#[inline]
266pub fn decode_with<'de, C, T>(cx: C, value: &'de Value<impl Allocator>) -> Result<T, C::Error>
267where
268 C: Context,
269 T: Decode<'de, Binary, C::Allocator>,
270{
271 ENCODING_BINARY.decode_with(cx, value)
272}
273
274/// Decode a [`Value`] into a type which implements [`Decode`] using a custom
275/// [`Context`] `C` in the [`Text`] mode.
276///
277/// A custom context allows [`Value`] decoding to be performed without an
278/// allocator.
279///
280/// # Examples
281///
282/// ```
283/// use musli::{Encode, Decode};
284/// use musli::context;
285/// use musli::value;
286///
287/// #[derive(Debug, PartialEq, Encode, Decode)]
288/// struct Person<'de> {
289/// name: &'de str,
290/// age: u32,
291/// }
292///
293/// let person = Person { name: "Alice", age: 30 };
294/// let value = value::encode_text(&person)?;
295///
296/// let cx = context::new();
297/// let decoded: Person<'_> = value::decode_text_with(&cx, &value)?;
298/// assert_eq!(decoded, person);
299/// # Ok::<_, Box<dyn core::error::Error>>(())
300/// ```
301#[inline]
302pub fn decode_text_with<'de, C, T>(cx: C, value: &'de Value<impl Allocator>) -> Result<T, C::Error>
303where
304 C: Context,
305 T: Decode<'de, Text, C::Allocator>,
306{
307 ENCODING_TEXT.decode_with(cx, value)
308}
309
310/// Setting up encoding with parameters.
311pub struct Encoding<const OPT: Options = OPTIONS, M = Binary>
312where
313 M: 'static,
314{
315 _marker: marker::PhantomData<M>,
316}
317
318impl Default for Encoding<OPTIONS, Binary> {
319 #[inline]
320 fn default() -> Self {
321 Self::new()
322 }
323}
324
325impl Encoding<OPTIONS, Binary> {
326 /// Construct a new [`Encoding`].
327 ///
328 /// ```
329 /// use musli::{Encode, Decode};
330 /// use musli::value::Encoding;
331 ///
332 /// const ENCODING: Encoding = Encoding::new();
333 ///
334 /// #[derive(Debug, PartialEq, Encode, Decode)]
335 /// struct Person<'a> {
336 /// name: &'a str,
337 /// age: u32,
338 /// }
339 ///
340 /// let person = Person { name: "Alice", age: 30 };
341 /// let value = ENCODING.encode(&person)?;
342 ///
343 /// let decoded: Person<'_> = ENCODING.decode(&value)?;
344 /// assert_eq!(decoded, person);
345 /// # Ok::<_, musli::value::Error>(())
346 /// ```
347 pub const fn new() -> Self {
348 Encoding {
349 _marker: marker::PhantomData,
350 }
351 }
352}
353
354impl<const OPT: Options, M> Encoding<OPT, M>
355where
356 M: 'static,
357{
358 /// Change the mode of the encoding.
359 ///
360 /// # Examples
361 ///
362 /// ```
363 /// use musli::value::{OPTIONS, Encoding};
364 ///
365 /// enum Custom {}
366 ///
367 /// const ENCODING: Encoding<OPTIONS, Custom> = Encoding::new().with_mode();
368 /// ```
369 pub const fn with_mode<T>(self) -> Encoding<OPT, T>
370 where
371 T: 'static,
372 {
373 Encoding {
374 _marker: marker::PhantomData,
375 }
376 }
377
378 /// Change the options of the encoding.
379 ///
380 /// # Examples
381 ///
382 /// ```
383 /// use musli::options::{self, Options, Integer};
384 /// use musli::value::Encoding;
385 ///
386 /// const OPTIONS: Options = options::new().integer(Integer::Fixed).build();
387 /// const ENCODING: Encoding<OPTIONS> = Encoding::new().with_options();
388 /// ```
389 pub const fn with_options<const U: Options>(self) -> Encoding<U, M> {
390 Encoding {
391 _marker: marker::PhantomData,
392 }
393 }
394
395 /// Encode something that implements [`Encode`] into a [`Value`].
396 ///
397 /// # Examples
398 ///
399 /// ```
400 /// use musli::{Encode, Decode};
401 /// use musli::value;
402 ///
403 /// const ENCODING: value::Encoding = value::Encoding::new();
404 ///
405 /// #[derive(Debug, PartialEq, Encode, Decode)]
406 /// struct Person<'de> {
407 /// name: &'de str,
408 /// age: u32,
409 /// }
410 ///
411 /// let person = Person { name: "Alice", age: 30 };
412 /// let value = ENCODING.encode(&person)?;
413 ///
414 /// let decoded: Person<'_> = ENCODING.decode(&value)?;
415 /// assert_eq!(decoded, person);
416 /// # Ok::<_, value::Error>(())
417 /// ```
418 #[cfg(feature = "alloc")]
419 #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
420 pub fn encode(&self, value: impl Encode<M>) -> Result<Value<Global>, Error> {
421 let mut output = Value::new(ValueKind::Empty);
422 let cx = crate::context::new().with_error();
423 ValueEncoder::<OPT, _, _, M>::new(&cx, 0, &mut output).encode(value)?;
424 Ok(output)
425 }
426
427 /// Encode something that implements [`Encode`] into a [`Value`] using a
428 /// custom [`Context`] `C`.
429 ///
430 /// A custom context allows [`Value`] encoding to be performed without an
431 /// allocator.
432 ///
433 /// # Examples
434 ///
435 /// ```
436 /// use musli::{Encode, Decode};
437 /// use musli::context;
438 /// use musli::value;
439 ///
440 /// const ENCODING: value::Encoding = value::Encoding::new();
441 ///
442 /// #[derive(Debug, PartialEq, Encode, Decode)]
443 /// struct Person<'de> {
444 /// name: &'de str,
445 /// age: u32,
446 /// }
447 ///
448 /// let person = Person { name: "Alice", age: 30 };
449 ///
450 /// let cx = context::new();
451 /// let value = ENCODING.encode_with(&cx, &person)?;
452 ///
453 /// let decoded: Person<'_> = ENCODING.decode(&value)?;
454 /// assert_eq!(decoded, person);
455 /// # Ok::<_, Box<dyn core::error::Error>>(())
456 /// ```
457 pub fn encode_with<C>(
458 &self,
459 cx: C,
460 value: impl Encode<M>,
461 ) -> Result<Value<C::Allocator>, C::Error>
462 where
463 C: Context,
464 {
465 let mut output = Value::new(ValueKind::Empty);
466 ValueEncoder::<OPT, _, _, M>::new(cx, 0, &mut output).encode(value)?;
467 Ok(output)
468 }
469
470 /// Decode a [`Value`] into a type which implements [`Decode`].
471 ///
472 /// # Examples
473 ///
474 /// ```
475 /// use musli::{Encode, Decode};
476 /// use musli::value;
477 ///
478 /// const ENCODING: value::Encoding = value::Encoding::new();
479 ///
480 /// #[derive(Debug, PartialEq, Encode, Decode)]
481 /// struct Person<'de> {
482 /// name: &'de str,
483 /// age: u32,
484 /// }
485 ///
486 /// let person = Person { name: "Alice", age: 30 };
487 /// let encoded = ENCODING.encode(&person)?;
488 ///
489 /// let decoded: Person<'_> = ENCODING.decode(&encoded)?;
490 /// assert_eq!(decoded, person);
491 /// # Ok::<_, value::Error>(())
492 /// ```
493 #[cfg(feature = "alloc")]
494 #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
495 pub fn decode<'de, T>(&self, value: &'de Value<impl Allocator>) -> Result<T, Error>
496 where
497 T: Decode<'de, M, Global>,
498 {
499 let cx = crate::context::new().with_error();
500 value.decoder::<OPT, _, M>(&cx).decode()
501 }
502
503 /// Decode a [`Value`] into a type which implements [`Decode`] using a
504 /// custom [`Context`] `C`.
505 ///
506 /// A custom context allows [`Value`] decoding to be performed without an
507 /// allocator.
508 ///
509 /// # Examples
510 ///
511 /// ```
512 /// use musli::{Encode, Decode};
513 /// use musli::context;
514 /// use musli::value;
515 ///
516 /// const ENCODING: value::Encoding = value::Encoding::new();
517 ///
518 /// #[derive(Debug, PartialEq, Encode, Decode)]
519 /// struct Person<'de> {
520 /// name: &'de str,
521 /// age: u32,
522 /// }
523 ///
524 /// let person = Person { name: "Alice", age: 30 };
525 ///
526 /// let value = ENCODING.encode(&person)?;
527 ///
528 /// let cx = context::new();
529 /// let decoded: Person<'_> = ENCODING.decode_with(&cx, &value)?;
530 /// assert_eq!(decoded, person);
531 /// # Ok::<_, Box<dyn core::error::Error>>(())
532 /// ```
533 pub fn decode_with<'de, C, T>(
534 &self,
535 cx: C,
536 value: &'de Value<impl Allocator>,
537 ) -> Result<T, C::Error>
538 where
539 C: Context,
540 T: Decode<'de, M, C::Allocator>,
541 {
542 cx.clear();
543 value.decoder::<OPT, _, M>(cx).decode()
544 }
545}