musli/
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.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/musli)
3//! [<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-musli-66c2a5?style=for-the-badge&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/musli)
4//!
5//! Excellent performance, no compromises[^1]!
6//!
7//! Müsli is a flexible, fast, and generic binary serialization framework for
8//! Rust, in the same vein as [`serde`].
9//!
10//! It provides a set of [formats](#formats), each with its own well-documented
11//! set of features and tradeoffs. Every byte-oriented serialization method
12//! including escaped formats like [`musli::json`] has full `#[no_std]` support
13//! with or without `alloc`. And a particularly neat component providing
14//! low-level refreshingly simple [zero-copy serialization][zerocopy].
15//!
16//! [^1]: As in Müsli should be able to do everything you need and more.
17//!
18//! <br>
19//!
20//! ## Overview
21//!
22//! * See [`derives`] to learn how to implement [`Encode`] and [`Decode`].
23//! * See [`data_model`] to learn about the abstract data model of Müsli.
24//! * See [benchmarks] and [size comparisons] to learn about the performance of
25//!   this framework.
26//! * See [`tests`] to learn how this library is tested.
27//! * See [`musli::serde`] for seamless compatibility with [`serde`]. You might
28//!   also be interested to learn how [Müsli is different][different].
29//!
30//! [different]: #müsli-is-different-from-serde
31//!
32//! <br>
33//!
34//! ## Usage
35//!
36//! Add the following to your `Cargo.toml` using the [format](#formats) you want
37//! to use:
38//!
39//! ```toml
40//! [dependencies]
41//! musli = { version = "0.0.124", features = ["storage"] }
42//! ```
43//!
44//! <br>
45//!
46//! ## Design
47//!
48//! The heavy lifting is done by the [`Encode`] and [`Decode`] derives which are
49//! documented in the [`derives`] module.
50//!
51//! Müsli operates based on the schema represented by the types which implement
52//! these traits.
53//!
54//! ```
55//! use musli::{Encode, Decode};
56//!
57//! #[derive(Encode, Decode)]
58//! struct Person {
59//!     /* .. fields .. */
60//! }
61//! ```
62//!
63//! > **Note** by default a field is identified by its *numerical index* which
64//! > would change if they are re-ordered. Renaming fields and setting a default
65//! > naming policy can be done by configuring the [`derives`].
66//!
67//! The binary serialization formats provided aim to efficiently and accurately
68//! encode every type and data structure available in Rust. Each format comes
69//! with [well-documented tradeoffs](#formats) and aims to be fully memory safe
70//! to use.
71//!
72//! Internally we use the terms "encoding", "encode", and "decode" because it's
73//! distinct from [`serde`]'s use of "serialization", "serialize", and
74//! "deserialize" allowing for the clearer interoperability between the two
75//! libraries. Encoding and decoding also has more of a "binary serialization"
76//! vibe, which more closely reflects the focus of this framework.
77//!
78//! Müsli is designed on similar principles as [`serde`]. Relying on Rust's
79//! powerful trait system to generate code which can largely be optimized away.
80//! The end result should be very similar to handwritten, highly optimized code.
81//!
82//! As an example of this, these two functions both produce the same assembly
83//! (built with `--release`):
84//!
85//! ```
86//! # use musli::{Decode, Encode};
87//! # use musli::mode::Binary;
88//! # use musli::options::{self, Options, Integer, ByteOrder};
89//! # use musli::storage::Encoding;
90//! # type Result<T, E = musli::storage::Error> = core::result::Result<T, E>;
91//! const OPTIONS: Options = options::new()
92//!     .with_integer(Integer::Fixed)
93//!     .with_byte_order(ByteOrder::NATIVE)
94//!     .build();
95//!
96//! const ENCODING: Encoding<OPTIONS> = Encoding::new().with_options();
97//!
98//! #[derive(Encode, Decode)]
99//! #[musli(packed)]
100//! pub struct Storage {
101//!     left: u32,
102//!     right: u32,
103//! }
104//!
105//! fn with_musli(storage: &Storage) -> Result<[u8; 8]> {
106//!     let mut array = [0; 8];
107//!     ENCODING.encode(&mut array[..], storage)?;
108//!     Ok(array)
109//! }
110//!
111//! fn without_musli(storage: &Storage) -> Result<[u8; 8]> {
112//!     let mut array = [0; 8];
113//!     array[..4].copy_from_slice(&storage.left.to_ne_bytes());
114//!     array[4..].copy_from_slice(&storage.right.to_ne_bytes());
115//!     Ok(array)
116//! }
117//! ```
118//!
119//! <br>
120//!
121//! ## Müsli is different from [`serde`]
122//!
123//! **Müsli's data model does not speak Rust**. There are no
124//! `serialize_struct_variant` methods which provides metadata about the type
125//! being serialized. The [`Encoder`] and [`Decoder`] traits are agnostic on
126//! this. Compatibility with Rust types is entirely handled using the [`Encode`]
127//! and [`Decode`] derives in combination with [modes](#Modes).
128//!
129//! **We use GATs** to provide easier to use abstractions. GATs were not
130//! available when serde was designed.
131//!
132//! **Everything is a [`Decoder`] or [`Encoder`]**. Field names are therefore
133//! not limited to be strings or indexes, but can be named to [arbitrary
134//! types][musli-name-type] if needed.
135//!
136//! **Visitor are only used when needed**. `serde` [completely uses visitors]
137//! when deserializing and the corresponding method is treated as a "hint" to
138//! the underlying format. The deserializer is then free to call any method on
139//! the visitor depending on what the underlying format actually contains. In
140//! Müsli, we swap this around. If the caller wants to decode an arbitrary type
141//! it calls [`decode_any`]. The format can then either signal the appropriate
142//! underlying type or call [`Visitor::visit_unknown`] telling the implementer
143//! that it does not have access to type information.
144//!
145//! **We've invented [*moded encoding*](#Modes)** allowing the same Rust types
146//! to be encoded in many different ways with much greater control over how
147//! things encoded. By default we include the [`Binary`] and [`Text`] modes
148//! providing sensible defaults for binary and text-based formats.
149//!
150//! **Müsli fully supports [no-std and no-alloc]** from the ground up without
151//! compromising on features using safe and efficient [scoped allocations].
152//!
153//! **We support [detailed tracing]** when decoding for much improved
154//! diagnostics of *where* something went wrong.
155//!
156//! <br>
157//!
158//! ## Formats
159//!
160//! Formats are currently distinguished by supporting various degrees of
161//! *upgrade stability*. A fully upgrade stable encoding format must tolerate
162//! that one model can add fields that an older version of the model should be
163//! capable of ignoring.
164//!
165//! Partial upgrade stability can still be useful as is the case of the
166//! [`musli::storage`] format below, because reading from storage only requires
167//! decoding to be upgrade stable. So if correctly managed with
168//! `#[musli(default)]` this will never result in any readers seeing unknown
169//! fields.
170//!
171//! The available formats and their capabilities are:
172//!
173//! | | `reorder` | `missing` | `unknown` | `self` |
174//! |-|-|-|-|-|
175//! | [`musli::storage`] `#[musli(packed)]` | ✗ | ✗ | ✗ | ✗ |
176//! | [`musli::storage`]                    | ✔ | ✔ | ✗ | ✗ |
177//! | [`musli::wire`]                       | ✔ | ✔ | ✔ | ✗ |
178//! | [`musli::descriptive`]                | ✔ | ✔ | ✔ | ✔ |
179//! | [`musli::json`] [^json]               | ✔ | ✔ | ✔ | ✔ |
180//!
181//! `reorder` determines whether fields must occur in exactly the order in which
182//! they are specified in their type. Reordering fields in such a type would
183//! cause unknown but safe behavior of some kind. This is only suitable for
184//! communication where the data models of each client are strictly
185//! synchronized.
186//!
187//! `missing` determines if reading can handle missing fields through something
188//! like `Option<T>`. This is suitable for on-disk storage, because it means
189//! that new optional fields can be added as the schema evolves.
190//!
191//! `unknown` determines if the format can skip over unknown fields. This is
192//! suitable for network communication. At this point you've reached [*upgrade
193//! stability*](#upgrade-stability). Some level of introspection is possible
194//! here, because the serialized format must contain enough information about
195//! fields to know what to skip which usually allows for reasoning about basic
196//! types.
197//!
198//! `self` determines if the format is self-descriptive. Allowing the structure
199//! of the data to be fully reconstructed from its serialized state. These
200//! formats do not require models to decode and can be converted to and from
201//! dynamic containers such as [`musli::value`] for introspection. Such formats
202//! also allows for type-coercions to be performed, so that a signed number can
203//! be correctly read as an unsigned number if it fits in the destination type.
204//!
205//! For every feature you drop, the format becomes more compact and efficient.
206//! [`musli::storage`] using `#[musli(packed)]` for example is roughly as compact
207//! as [`bincode`] while [`musli::wire`] is comparable in size to something like
208//! [`protobuf`]. All formats are primarily byte-oriented, but some might
209//! perform [bit packing] if the benefits are obvious.
210//!
211//! [^json]: This is strictly not a binary serialization, but it was implemented
212//! as a litmus test to ensure that Müsli has the necessary framework features
213//! to support it. Luckily, the implementation is also quite good!
214//!
215//! <br>
216//!
217//! ## Upgrade stability
218//!
219//! The following is an example of *full upgrade stability* using
220//! [`musli::wire`]. `Version1` can be decoded from an instance of `Version2`
221//! because it understands how to skip fields which are part of `Version2`.
222//! We're also explicitly adding `#[musli(name = ..)]` to the fields to ensure
223//! that they don't change in case they are re-ordered.
224//!
225//! ```
226//! use musli::{Encode, Decode};
227//!
228//! #[derive(Debug, PartialEq, Encode, Decode)]
229//! struct Version1 {
230//!     #[musli(mode = Binary, name = 0)]
231//!     name: String,
232//! }
233//!
234//! #[derive(Debug, PartialEq, Encode, Decode)]
235//! struct Version2 {
236//!     #[musli(mode = Binary, name = 0)]
237//!     name: String,
238//!     #[musli(mode = Binary, name = 1)]
239//!     #[musli(default)]
240//!     age: Option<u32>,
241//! }
242//!
243//! let version2 = musli::wire::to_vec(&Version2 {
244//!     name: String::from("Aristotle"),
245//!     age: Some(61),
246//! })?;
247//!
248//! let version1: Version1 = musli::wire::decode(version2.as_slice())?;
249//! # Ok::<_, musli::wire::Error>(())
250//! ```
251//!
252//! The following is an example of *partial upgrade stability* using
253//! [`musli::storage`] on the same data models. Note how `Version2` can be
254//! decoded from `Version1` but *not* the other way around making it suitable
255//! for on-disk storage where the schema can evolve from older to newer
256//! versions.
257//!
258//! ```
259//! # use musli::{Encode, Decode};
260//! # #[derive(Debug, PartialEq, Encode, Decode)]
261//! # struct Version1 { name: String }
262//! # #[derive(Debug, PartialEq, Encode, Decode)]
263//! # struct Version2 { name: String, #[musli(default)] age: Option<u32> }
264//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
265//! let version2 = musli::storage::to_vec(&Version2 {
266//!     name: String::from("Aristotle"),
267//!     age: Some(61),
268//! })?;
269//!
270//! assert!(musli::storage::decode::<_, Version1>(version2.as_slice()).is_err());
271//!
272//! let version1 = musli::storage::to_vec(&Version1 {
273//!     name: String::from("Aristotle"),
274//! })?;
275//!
276//! let version2: Version2 = musli::storage::decode(version1.as_slice())?;
277//! # Ok(()) }
278//! ```
279//!
280//! <br>
281//!
282//! ## Modes
283//!
284//! In Müsli in contrast to [`serde`] the same model can be serialized in
285//! different ways. Instead of requiring the use of distinct models we support
286//! implementing different *modes* for a single model.
287//!
288//! A mode is a type parameter, which allows for different attributes to apply
289//! depending on which mode an encoder is configured to use. A mode can apply to
290//! *any* musli attributes giving you a lot of flexibility.
291//!
292//! If a mode is not specified, an implementation will apply to all modes (`M`),
293//! if at least one mode is specified it will be implemented for all modes which
294//! are present in a model and [`Binary`]. This way, an encoding which uses
295//! `Binary` which is the default mode should always work.
296//!
297//! For more information on how to configure modes, see [`derives`].
298//!
299//! Below is a simple example of how we can use two modes to provide two
300//! completely different formats using a single struct:
301//!
302//! ```
303//! use musli::{Decode, Encode};
304//! use musli::json::Encoding;
305//!
306//! enum Alt {}
307//!
308//! #[derive(Decode, Encode)]
309//! #[musli(mode = Alt, packed)]
310//! #[musli(name_all = "name")]
311//! struct Word<'a> {
312//!     text: &'a str,
313//!     teineigo: bool,
314//! }
315//!
316//! const CONFIG: Encoding = Encoding::new();
317//! const ALT_CONFIG: Encoding<Alt> = Encoding::new().with_mode();
318//!
319//! let word = Word {
320//!     text: "あります",
321//!     teineigo: true,
322//! };
323//!
324//! let out = CONFIG.to_string(&word)?;
325//! assert_eq!(out, r#"{"text":"あります","teineigo":true}"#);
326//!
327//! let out = ALT_CONFIG.to_string(&word)?;
328//! assert_eq!(out, r#"["あります",true]"#);
329//! # Ok::<_, musli::json::Error>(())
330//! ```
331//!
332//! <br>
333//!
334//! ## Unsafety
335//!
336//! This is a non-exhaustive list of unsafe use in this crate, and why they are
337//! used:
338//!
339//! * A `mem::transmute` in `Tag::kind`. Which guarantees that converting into
340//!   the `Kind` enum which is `#[repr(u8)]` is as efficient as possible.
341//!
342//! * A largely unsafe `SliceReader` which provides more efficient reading than
343//!   the default `Reader` impl for `&[u8]` does. Since it can perform most of
344//!   the necessary comparisons directly on the pointers.
345//!
346//! * Some unsafety related to UTF-8 handling in `musli::json`, because we check
347//!   UTF-8 validity internally ourselves (like `serde_json`).
348//!
349//! * `FixedBytes<N>`, which is a stack-based container that can operate over
350//!   uninitialized data. Its implementation is largely unsafe. With it
351//!   stack-based serialization can be performed which is useful in no-std
352//!   environments.
353//!
354//! * Some `unsafe` is used for owned `String` decoding in all binary formats to
355//!   support faster string processing through [`simdutf8`]. Disabling the
356//!   `simdutf8` feature (enabled by default) removes the use of this unsafe.
357//!
358//! To ensure this library is correctly implemented with regards to memory
359//! safety, extensive testing and fuzzing is performed using `miri`. See
360//! [`tests`] for more information.
361//!
362//! <br>
363//!
364//! [`Binary`]: <https://docs.rs/musli/latest/musli/mode/enum.Binary.html>
365//! [`bincode`]: <https://docs.rs/bincode>
366//! [`data_model`]: <https://docs.rs/musli/latest/musli/help/data_model/index.html>
367//! [`decode_any`]: https://docs.rs/musli/latest/musli/trait.Decoder.html#method.decode_any
368//! [`Decode`]: <https://docs.rs/musli/latest/musli/de/trait.Decode.html>
369//! [`Decoder`]: <https://docs.rs/musli/latest/musli/trait.Decoder.html>
370//! [`derives`]: <https://docs.rs/musli/latest/musli/help/derives/index.html>
371//! [`Encode`]: <https://docs.rs/musli/latest/musli/en/trait.Encode.html>
372//! [`Encoder`]: <https://docs.rs/musli/latest/musli/trait.Encoder.html>
373//! [`musli::descriptive`]: <https://docs.rs/musli/latest/musli/descriptive/index.html>
374//! [`musli::json`]: <https://docs.rs/musli/latest/musli/json/index.html>
375//! [`musli::serde`]: <https://docs.rs/musli/latest/musli/serde/index.html>
376//! [`musli::storage`]: <https://docs.rs/musli/latest/musli/storage/index.html>
377//! [`musli::value`]: <https://docs.rs/musli/latest/musli/value/index.html>
378//! [`musli::wire`]: <https://docs.rs/musli/latest/musli/wire/index.html>
379//! [`protobuf`]: <https://developers.google.com/protocol-buffers>
380//! [`serde`]: <https://serde.rs>
381//! [`simdutf8`]: <https://docs.rs/simdutf8>
382//! [`tests`]: <https://github.com/udoprog/musli/tree/main/tests>
383//! [`Text`]: <https://docs.rs/musli/latest/musli/mode/enum.Text.html>
384//! [`Visitor::visit_unknown`]: https://docs.rs/musli/latest/musli/de/trait.Visitor.html#method.visit_unknown
385//! [benchmarks]: <https://udoprog.github.io/musli/benchmarks/>
386//! [bit packing]: <https://github.com/udoprog/musli/blob/main/crates/musli/src/descriptive/tag.rs>
387//! [completely uses visitors]: https://docs.rs/serde/latest/serde/trait.Deserializer.html#tymethod.deserialize_u32
388//! [detailed tracing]: <https://udoprog.github.io/rust/2023-05-22/abductive-diagnostics-for-musli.html>
389//! [musli-name-type]: <https://docs.rs/musli/latest/musli/help/derives/index.html#musliname_type-->
390//! [no-std and no-alloc]: <https://github.com/udoprog/musli/blob/main/no-std/examples/>
391//! [scoped allocations]: <https://docs.rs/musli/latest/musli/trait.Context.html#tymethod.alloc>
392//! [size comparisons]: <https://udoprog.github.io/musli/benchmarks/#size-comparisons>
393//! [zerocopy]: <https://docs.rs/musli-zerocopy>
394
395#![deny(missing_docs)]
396#![allow(clippy::module_inception)]
397#![no_std]
398#![cfg_attr(doc_cfg, feature(doc_cfg))]
399
400#[cfg(feature = "alloc")]
401extern crate alloc as rust_alloc;
402
403#[cfg(feature = "std")]
404extern crate std;
405
406pub mod macros;
407
408#[cfg(test)]
409mod tests;
410
411#[cfg(feature = "json")]
412mod dec2flt;
413
414pub mod help;
415
416pub mod de;
417pub mod en;
418
419#[doc(inline)]
420pub use musli_core::hint;
421#[doc(inline)]
422pub use musli_core::mode;
423
424/// This is an attribute macro that must be used when implementing a
425/// [`Encoder`].
426///
427/// It is required to use because a [`Encoder`] implementation might introduce
428/// new associated types in the future, and this [not yet supported] on a
429/// language level in Rust. So this attribute macro polyfills any missing types
430/// automatically.
431///
432/// [not yet supported]: https://rust-lang.github.io/rfcs/2532-associated-type-defaults.html
433///
434/// # Examples
435///
436/// ```
437/// use std::fmt;
438///
439/// use musli::Context;
440/// use musli::en::{Encoder, Encode};
441///
442/// struct MyEncoder<'a, C: ?Sized> {
443///     value: &'a mut Option<u32>,
444///     cx: &'a C,
445/// }
446///
447/// #[musli::encoder]
448/// impl<C: ?Sized + Context> Encoder for MyEncoder<'_, C> {
449///     type Cx = C;
450///     type Ok = ();
451///
452///     fn cx(&self) -> &C {
453///         self.cx
454///     }
455///
456///     fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
457///         write!(f, "32-bit unsigned integers")
458///     }
459///
460///     fn encode<T>(self, value: T) -> Result<Self::Ok, C::Error>
461///     where
462///         T: Encode<Self::Mode>,
463///     {
464///         value.encode(self.cx, self)
465///     }
466///
467///     fn encode_u32(self, value: u32) -> Result<(), Self::Error> {
468///         *self.value = Some(value);
469///         Ok(())
470///     }
471/// }
472/// ```
473#[doc(inline)]
474pub use musli_core::encoder;
475
476/// This is an attribute macro that must be used when implementing a
477/// [`Decoder`].
478///
479/// It is required to use because a [`Decoder`] implementation might introduce
480/// new associated types in the future, and this is [not yet supported] on a
481/// language level in Rust. So this attribute macro polyfills any missing types
482/// automatically.
483///
484/// [not yet supported]: https://rust-lang.github.io/rfcs/2532-associated-type-defaults.html
485///
486/// # Examples
487///
488/// ```
489/// use std::fmt;
490///
491/// use musli::Context;
492/// use musli::de::{Decoder, Decode};
493///
494/// struct MyDecoder<'a, C: ?Sized> {
495///     cx: &'a C,
496/// }
497///
498/// #[musli::decoder]
499/// impl<'de, C: ?Sized + Context> Decoder<'de> for MyDecoder<'_, C> {
500///     type Cx = C;
501///
502///     fn cx(&self) -> &C {
503///         self.cx
504///     }
505///
506///     fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
507///         write!(f, "32-bit unsigned integers")
508///     }
509///
510///     fn decode_u32(self) -> Result<u32, Self::Error> {
511///         Ok(42)
512///     }
513/// }
514/// ```
515#[doc(inline)]
516pub use musli_core::decoder;
517
518/// This is an attribute macro that must be used when implementing a
519/// [`Visitor`].
520///
521/// It is required to use because a [`Visitor`] implementation might introduce
522/// new associated types in the future, and this is [not yet supported] on a
523/// language level in Rust. So this attribute macro polyfills any missing types
524/// automatically.
525///
526/// [not yet supported]:
527///     https://rust-lang.github.io/rfcs/2532-associated-type-defaults.html
528/// [`Visitor`]: crate::de::Visitor
529///
530/// # Examples
531///
532/// ```
533/// use std::fmt;
534///
535/// use musli::Context;
536/// use musli::de::Visitor;
537///
538/// struct AnyVisitor;
539///
540/// #[musli::visitor]
541/// impl<'de, C: ?Sized + Context> Visitor<'de, C> for AnyVisitor {
542///     type Ok = ();
543///
544///     #[inline]
545///     fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
546///         write!(
547///             f,
548///             "value that can be decoded into dynamic container"
549///         )
550///     }
551/// }
552/// ```
553#[doc(inline)]
554pub use musli_core::visitor;
555
556#[doc(inline)]
557pub use musli_core::{Context, Decode, Decoder, Encode, Encoder};
558
559#[doc(hidden)]
560pub use musli_core::__priv;
561
562pub mod alloc;
563
564pub mod descriptive;
565pub mod json;
566pub mod serde;
567pub mod storage;
568pub mod value;
569pub mod wire;
570
571pub mod context;
572
573pub mod compat;
574
575pub mod fixed;
576#[doc(inline)]
577pub use self::fixed::FixedBytes;
578
579pub mod options;
580#[doc(inline)]
581pub use self::options::Options;
582
583pub mod reader;
584#[doc(inline)]
585pub use self::reader::{IntoReader, Reader};
586
587pub mod wrap;
588
589pub mod writer;
590#[doc(inline)]
591pub use self::writer::Writer;
592
593pub mod no_std;
594
595mod int;
596mod str;