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}