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.131", 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().fixed().native_byte_order().build();
92//! const ENCODING: Encoding<OPTIONS> = Encoding::new().with_options();
93//!
94//! #[derive(Encode, Decode)]
95//! #[musli(packed)]
96//! pub struct Storage {
97//! left: u32,
98//! right: u32,
99//! }
100//!
101//! fn with_musli(storage: &Storage) -> Result<[u8; 8]> {
102//! let mut array = [0; 8];
103//! ENCODING.encode(&mut array[..], storage)?;
104//! Ok(array)
105//! }
106//!
107//! fn without_musli(storage: &Storage) -> Result<[u8; 8]> {
108//! let mut array = [0; 8];
109//! array[..4].copy_from_slice(&storage.left.to_ne_bytes());
110//! array[4..].copy_from_slice(&storage.right.to_ne_bytes());
111//! Ok(array)
112//! }
113//! ```
114//!
115//! <br>
116//!
117//! ## Müsli is different from [`serde`]
118//!
119//! **Müsli's data model does not speak Rust**. There are no
120//! `serialize_struct_variant` methods which provides metadata about the type
121//! being serialized. The [`Encoder`] and [`Decoder`] traits are agnostic on
122//! this. Compatibility with Rust types is entirely handled using the [`Encode`]
123//! and [`Decode`] derives in combination with [modes](#Modes).
124//!
125//! **We use GATs** to provide easier to use abstractions. GATs were not
126//! available when serde was designed.
127//!
128//! **Everything is a [`Decoder`] or [`Encoder`]**. Field names are therefore
129//! not limited to be strings or indexes, but can be named to [arbitrary
130//! types][musli-name-type] if needed.
131//!
132//! **Visitor are only used when needed**. `serde` [completely uses visitors]
133//! when deserializing and the corresponding method is treated as a "hint" to
134//! the underlying format. The deserializer is then free to call any method on
135//! the visitor depending on what the underlying format actually contains. In
136//! Müsli, we swap this around. If the caller wants to decode an arbitrary type
137//! it calls [`decode_any`]. The format can then either signal the appropriate
138//! underlying type or call [`Visitor::visit_unknown`] telling the implementer
139//! that it does not have access to type information.
140//!
141//! **We've invented [*moded encoding*](#Modes)** allowing the same Rust types
142//! to be encoded in many different ways with much greater control over how
143//! things encoded. By default we include the [`Binary`] and [`Text`] modes
144//! providing sensible defaults for binary and text-based formats.
145//!
146//! **Müsli fully supports [no-std and no-alloc]** from the ground up without
147//! compromising on features using safe and efficient [scoped allocations].
148//!
149//! **We support [detailed tracing]** when decoding for much improved
150//! diagnostics of *where* something went wrong.
151//!
152//! <br>
153//!
154//! ## Formats
155//!
156//! Formats are currently distinguished by supporting various degrees of
157//! *upgrade stability*. A fully upgrade stable encoding format must tolerate
158//! that one model can add fields that an older version of the model should be
159//! capable of ignoring.
160//!
161//! Partial upgrade stability can still be useful as is the case of the
162//! [`musli::storage`] format below, because reading from storage only requires
163//! decoding to be upgrade stable. So if correctly managed with
164//! `#[musli(default)]` this will never result in any readers seeing unknown
165//! fields.
166//!
167//! The available formats and their capabilities are:
168//!
169//! | | `reorder` | `missing` | `unknown` | `self` |
170//! |-|-|-|-|-|
171//! | [`musli::packed`] (with `#[musli(packed)]`) | ✗ | ✗ | ✗ | ✗ |
172//! | [`musli::storage`] | ✔ | ✔ | ✗ | ✗ |
173//! | [`musli::wire`] | ✔ | ✔ | ✔ | ✗ |
174//! | [`musli::descriptive`] | ✔ | ✔ | ✔ | ✔ |
175//! | [`musli::json`] [^json] | ✔ | ✔ | ✔ | ✔ |
176//!
177//! `reorder` determines whether fields must occur in exactly the order in which
178//! they are specified in their type. Reordering fields in such a type would
179//! cause unknown but safe behavior of some kind. This is only suitable for
180//! communication where the data models of each client are strictly
181//! synchronized.
182//!
183//! `missing` determines if reading can handle missing fields through something
184//! like `Option<T>`. This is suitable for on-disk storage, because it means
185//! that new optional fields can be added as the schema evolves.
186//!
187//! `unknown` determines if the format can skip over unknown fields. This is
188//! suitable for network communication. At this point you've reached [*upgrade
189//! stability*](#upgrade-stability). Some level of introspection is possible
190//! here, because the serialized format must contain enough information about
191//! fields to know what to skip which usually allows for reasoning about basic
192//! types.
193//!
194//! `self` determines if the format is self-descriptive. Allowing the structure
195//! of the data to be fully reconstructed from its serialized state. These
196//! formats do not require models to decode and can be converted to and from
197//! dynamic containers such as [`musli::value`] for introspection. Such formats
198//! also allows for type-coercions to be performed, so that a signed number can
199//! be correctly read as an unsigned number if it fits in the destination type.
200//!
201//! For every feature you drop, the format becomes more compact and efficient.
202//! [`musli::storage`] using `#[musli(packed)]` for example is roughly as compact
203//! as [`bincode`] while [`musli::wire`] is comparable in size to something like
204//! [`protobuf`]. All formats are primarily byte-oriented, but some might
205//! perform [bit packing] if the benefits are obvious.
206//!
207//! [^json]: This is strictly not a binary serialization, but it was implemented
208//! as a litmus test to ensure that Müsli has the necessary framework features
209//! to support it. Luckily, the implementation is also quite good!
210//!
211//! <br>
212//!
213//! ## Upgrade stability
214//!
215//! The following is an example of *full upgrade stability* using
216//! [`musli::wire`]. `Version1` can be decoded from an instance of `Version2`
217//! because it understands how to skip fields which are part of `Version2`.
218//! We're also explicitly adding `#[musli(name = ..)]` to the fields to ensure
219//! that they don't change in case they are re-ordered.
220//!
221//! ```
222//! use musli::{Encode, Decode};
223//!
224//! #[derive(Debug, PartialEq, Encode, Decode)]
225//! struct Version1 {
226//! #[musli(Binary, name = 0)]
227//! name: String,
228//! }
229//!
230//! #[derive(Debug, PartialEq, Encode, Decode)]
231//! struct Version2 {
232//! #[musli(Binary, name = 0)]
233//! name: String,
234//! #[musli(Binary, name = 1)]
235//! #[musli(default)]
236//! age: Option<u32>,
237//! }
238//!
239//! let version2 = musli::wire::to_vec(&Version2 {
240//! name: String::from("Aristotle"),
241//! age: Some(61),
242//! })?;
243//!
244//! let version1: Version1 = musli::wire::decode(version2.as_slice())?;
245//! # Ok::<_, musli::wire::Error>(())
246//! ```
247//!
248//! The following is an example of *partial upgrade stability* using
249//! [`musli::storage`] on the same data models. Note how `Version2` can be
250//! decoded from `Version1` but *not* the other way around making it suitable
251//! for on-disk storage where the schema can evolve from older to newer
252//! versions.
253//!
254//! ```
255//! # use musli::{Encode, Decode};
256//! # #[derive(Debug, PartialEq, Encode, Decode)]
257//! # struct Version1 { name: String }
258//! # #[derive(Debug, PartialEq, Encode, Decode)]
259//! # struct Version2 { name: String, #[musli(default)] age: Option<u32> }
260//! # fn main() -> Result<(), Box<dyn core::error::Error>> {
261//! let version2 = musli::storage::to_vec(&Version2 {
262//! name: String::from("Aristotle"),
263//! age: Some(61),
264//! })?;
265//!
266//! assert!(musli::storage::decode::<_, Version1>(version2.as_slice()).is_err());
267//!
268//! let version1 = musli::storage::to_vec(&Version1 {
269//! name: String::from("Aristotle"),
270//! })?;
271//!
272//! let version2: Version2 = musli::storage::decode(version1.as_slice())?;
273//! # Ok(()) }
274//! ```
275//!
276//! <br>
277//!
278//! ## Modes
279//!
280//! In Müsli in contrast to [`serde`] the same model can be serialized in
281//! different ways. Instead of requiring the use of distinct models we support
282//! implementing different *modes* for a single model.
283//!
284//! A mode is a type parameter, which allows for different attributes to apply
285//! depending on which mode an encoder is configured to use. A mode can apply to
286//! *any* musli attributes giving you a lot of flexibility.
287//!
288//! If a mode is not specified, an implementation will apply to all modes (`M`),
289//! if at least one mode is specified it will be implemented for all modes which
290//! are present in a model and [`Binary`] and [`Text`]. This way, an encoding
291//! which uses [`Binary`] or [`Text`] which are the default modes should always
292//! work.
293//!
294//! For more information on how to configure modes, see [`derives`].
295//!
296//! Below is a simple example of how we can use two modes to provide two
297//! completely different formats using a single struct:
298//!
299//! ```
300//! use musli::{Decode, Encode};
301//! use musli::json::Encoding;
302//!
303//! enum Alt {}
304//!
305//! #[derive(Decode, Encode)]
306//! #[musli(Text, name_all = "name")]
307//! #[musli(mode = Alt, packed)]
308//! struct Word<'a> {
309//! text: &'a str,
310//! teineigo: bool,
311//! }
312//!
313//! const TEXT: Encoding = Encoding::new();
314//! const ALT: Encoding<Alt> = Encoding::new().with_mode();
315//!
316//! let word = Word {
317//! text: "あります",
318//! teineigo: true,
319//! };
320//!
321//! let out = TEXT.to_string(&word)?;
322//! assert_eq!(out, r#"{"text":"あります","teineigo":true}"#);
323//!
324//! let out = ALT.to_string(&word)?;
325//! assert_eq!(out, r#"["あります",true]"#);
326//! # Ok::<_, musli::json::Error>(())
327//! ```
328//!
329//! <br>
330//!
331//! ## Going very fast
332//!
333//! With the previous sections it should be apparent that speed is primarily a
334//! game of tradeoffs. If we make every tradeoff in favor of speed Müsli is
335//! designed to be the fastest framework out there.
336//!
337//! The tradeoffs we will be showcasing to achieve speed here are:
338//!
339//! * *Pre-allocate serialization space*. This avoids all allocations during
340//! serialization. The tradeoff is that if the data we are serializing
341//! contains dynamically sized information which goes beyond the pre-allocated
342//! space, we will error.
343//! * *Use fixed-sized integers and floats*. We use more space, but the cost of
344//! serializing numerical fields essentially boils down to copying them.
345//! * *Use a native byte order*. With this we avoid any byte-swapping
346//! operations. But our data becomes less portable.
347//! * *Use a packed format*. This doesn't allow for any upgrades, but we avoid
348//! paying the overhead of serializing field identifiers.
349//! * *Use the [`Slice` allocator]*. This avoids all heap allocations using the
350//! system allocator. While the system allocator is quite efficient and
351//! normally shouldn't be avoided, the slice allocator is a fixed-slab
352//! allocator. The tradeoff here is that we will error in case we run out of
353//! memory, but we only need to use the allocator if the types being
354//! serialized (or the format) demands it.
355//! * *Disable error handling*. Code generation will be able to remove
356//! everything related to error handling, like allocations. To do this we can
357//! make use of the [default context] without configuring it for tracing. If
358//! an error happens, we are only informed of that fact through a zero-sized
359//! marker type.
360//!
361//! We achieve this through the following methods:
362//!
363//! ```
364//! use musli::alloc::{Allocator, System};
365//! use musli::context::{self, ErrorMarker as Error};
366//! use musli::options::{self, Float, Integer, Width, Options};
367//! use musli::storage::Encoding;
368//! use musli::{Decode, Encode};
369//! use musli::alloc::Slice;
370//!
371//! enum Packed {}
372//!
373//! const OPTIONS: Options = options::new().fixed().native_byte_order().build();
374//! const ENCODING: Encoding<OPTIONS, Packed> = Encoding::new().with_options().with_mode();
375//!
376//! #[inline]
377//! pub fn encode<'buf, T, A>(buf: &'buf mut [u8], value: &T, alloc: A) -> Result<&'buf [u8], Error>
378//! where
379//! T: Encode<Packed>,
380//! A: Allocator,
381//! {
382//! let cx = context::new_in(alloc);
383//! let w = ENCODING.to_slice_with(&cx, &mut buf[..], value)?;
384//! Ok(&buf[..w])
385//! }
386//!
387//! #[inline]
388//! pub fn decode<'buf, T, A>(buf: &'buf [u8], alloc: A) -> Result<T, Error>
389//! where
390//! T: Decode<'buf, Packed, A>,
391//! A: Allocator,
392//! {
393//! let cx = context::new_in(alloc);
394//! ENCODING.from_slice_with(&cx, buf)
395//! }
396//! ```
397//!
398//! We also need some cooperation from the types being serialized since they
399//! need to use the `Packed` mode we defined just above:
400//!
401//! ```
402//! use musli::{Encode, Decode};
403//! # enum Packed {}
404//!
405//! #[derive(Encode, Decode)]
406//! #[musli(mode = Packed, packed)]
407//! struct Person {
408//! name: String,
409//! age: u32,
410//! }
411//! ```
412//!
413//! Using the framework above also needs a bit of prep, namely the slice
414//! allocator need to be initialized:
415//!
416//! ```
417//! use musli::alloc::{ArrayBuffer, Slice};
418//!
419//! let mut buf = ArrayBuffer::new();
420//! let alloc = Slice::new(&mut buf);
421//! ```
422//!
423//! That's it! You are now using Müsli in the fastest possible mode. Feel free
424//! to use it to "beat" any benchmarks. In fact, the `musli_packed` mode in our
425//! internal [benchmarks] beat pretty much every framework with these methods.
426//!
427//! > My hope is that this should illustrate why you shouldn't blindly trust
428//! > benchmarks. Sometimes code is not fully optimized, but most of the time
429//! > there is a tradeoff. If a benchmark doesn't tell you what tradeoffs are
430//! > being made, don't just naively trust a number.
431//!
432//! <br>
433//!
434//! ## Unsafety
435//!
436//! This is a non-exhaustive list of unsafe use in this crate, and why they are
437//! used:
438//!
439//! * A `mem::transmute` in `Tag::kind`. Which guarantees that converting into
440//! the `Kind` enum which is `#[repr(u8)]` is as efficient as possible.
441//!
442//! * A largely unsafe `SliceReader` which provides more efficient reading than
443//! the default `Reader` impl for `&[u8]` does. Since it can perform most of
444//! the necessary comparisons directly on the pointers.
445//!
446//! * Some unsafety related to UTF-8 handling in `musli::json`, because we check
447//! UTF-8 validity internally ourselves (like `serde_json`).
448//!
449//! * `FixedBytes<N>`, which is a stack-based container that can operate over
450//! uninitialized data. Its implementation is largely unsafe. With it
451//! stack-based serialization can be performed which is useful in no-std
452//! environments.
453//!
454//! * Some `unsafe` is used for owned `String` decoding in all binary formats to
455//! support faster string processing through [`simdutf8`]. Disabling the
456//! `simdutf8` feature (enabled by default) removes the use of this unsafe.
457//!
458//! To ensure this library is correctly implemented with regards to memory
459//! safety, extensive testing and fuzzing is performed using `miri`. See
460//! [`tests`] for more information.
461//!
462//! <br>
463//!
464//! [`Binary`]: <https://docs.rs/musli/latest/musli/mode/enum.Binary.html>
465//! [`bincode`]: <https://docs.rs/bincode>
466//! [`data_model`]: <https://docs.rs/musli/latest/musli/_help/data_model/>
467//! [`decode_any`]: https://docs.rs/musli/latest/musli/trait.Decoder.html#method.decode_any
468//! [`Decode`]: <https://docs.rs/musli/latest/musli/de/trait.Decode.html>
469//! [`Decoder`]: <https://docs.rs/musli/latest/musli/trait.Decoder.html>
470//! [`derives`]: <https://docs.rs/musli/latest/musli/_help/derives/>
471//! [`Encode`]: <https://docs.rs/musli/latest/musli/en/trait.Encode.html>
472//! [`Encoder`]: <https://docs.rs/musli/latest/musli/trait.Encoder.html>
473//! [`musli::descriptive`]: <https://docs.rs/musli/latest/musli/descriptive/>
474//! [`musli::json`]: <https://docs.rs/musli/latest/musli/json/>
475//! [`musli::packed`]: <https://docs.rs/musli/latest/musli/packed/>
476//! [`musli::serde`]: <https://docs.rs/musli/latest/musli/serde/>
477//! [`musli::storage`]: <https://docs.rs/musli/latest/musli/storage/>
478//! [`musli::value`]: <https://docs.rs/musli/latest/musli/value/>
479//! [`musli::wire`]: <https://docs.rs/musli/latest/musli/wire/>
480//! [`protobuf`]: <https://developers.google.com/protocol-buffers>
481//! [`serde`]: <https://serde.rs>
482//! [`simdutf8`]: <https://docs.rs/simdutf8>
483//! [`Slice` allocator]: <https://docs.rs/musli/latest/musli/alloc/struct.Slice.html>
484//! [`tests`]: <https://github.com/udoprog/musli/tree/main/tests>
485//! [`Text`]: <https://docs.rs/musli/latest/musli/mode/enum.Text.html>
486//! [`Visitor::visit_unknown`]: https://docs.rs/musli/latest/musli/de/trait.Visitor.html#method.visit_unknown
487//! [benchmarks]: <https://udoprog.github.io/musli/benchmarks/>
488//! [bit packing]: <https://github.com/udoprog/musli/blob/main/crates/musli/src/descriptive/tag.rs>
489//! [completely uses visitors]: https://docs.rs/serde/latest/serde/trait.Deserializer.html#tymethod.deserialize_u32
490//! [default context]: <https://docs.rs/musli/latest/musli/context/new_in.html>
491//! [detailed tracing]: <https://udoprog.github.io/rust/2023-05-22/abductive-diagnostics-for-musli.html>
492//! [musli-name-type]: <https://docs.rs/musli/latest/musli/_help/derives/#muslinametype--type>
493//! [no-std and no-alloc]: <https://github.com/udoprog/musli/blob/main/no-std/examples/>
494//! [scoped allocations]: <https://docs.rs/musli/latest/musli/trait.Context.html#tymethod.alloc>
495//! [size comparisons]: <https://udoprog.github.io/musli/benchmarks/#size-comparisons>
496//! [zerocopy]: <https://docs.rs/musli-zerocopy>
497
498#![deny(missing_docs)]
499#![allow(clippy::module_inception)]
500#![no_std]
501#![cfg_attr(doc_cfg, feature(doc_cfg))]
502
503#[cfg(feature = "alloc")]
504extern crate alloc as rust_alloc;
505
506#[cfg(feature = "std")]
507extern crate std;
508
509pub mod macros;
510
511#[cfg(test)]
512mod tests;
513
514#[cfg(feature = "json")]
515mod dec2flt;
516
517pub mod _help {
518 //! Detailed documentation for Müsli
519 //!
520 //! * [The data model of Müsli][data_model].
521 //! * [Deriving `Encode` and `Decode`][derives].
522
523 #[doc = include_str!("../help/data_model.md")]
524 pub mod data_model {}
525
526 #[doc = include_str!("../help/derives.md")]
527 pub mod derives {}
528}
529
530pub mod de;
531pub mod en;
532
533#[doc(inline)]
534pub use musli_core::hint;
535#[doc(inline)]
536pub use musli_core::mode;
537
538#[doc(inline)]
539pub use musli_core::Context;
540
541#[doc(inline)]
542pub use self::de::{decoder, Decode, Decoder};
543
544#[doc(inline)]
545pub use self::en::{encoder, Encode, Encoder};
546
547#[doc(hidden)]
548pub use musli_core::__priv;
549
550pub mod alloc;
551#[doc(inline)]
552pub use self::alloc::Allocator;
553
554pub mod descriptive;
555pub mod json;
556pub mod packed;
557pub mod serde;
558pub mod storage;
559pub mod value;
560pub mod wire;
561
562pub mod context;
563
564pub mod compat;
565
566pub mod fixed;
567#[doc(inline)]
568pub use self::fixed::FixedBytes;
569
570pub mod options;
571#[doc(inline)]
572pub use self::options::Options;
573
574pub mod reader;
575#[doc(inline)]
576pub use self::reader::{IntoReader, Reader};
577
578pub mod wrap;
579
580pub mod writer;
581#[doc(inline)]
582pub use self::writer::{IntoWriter, Writer};
583
584pub mod no_std;
585
586mod int;
587mod str;
588
589use crate::alloc::Disabled;
590use crate::mode::Binary;
591
592/// Test if the given type `T` is marked with the `#[musli(packed)]` attribute,
593/// and is bitwise encodeable in the [`Binary`] mode.
594///
595/// See the [help section for `#[musli(packed)]`][help] for more information.
596///
597/// [help]: crate::_help::derives#muslipacked
598#[inline]
599pub const fn is_bitwise_encode<T>() -> bool
600where
601 T: Encode<Binary>,
602{
603 T::IS_BITWISE_ENCODE
604}
605
606/// Test if the given type `T` is marked with the `#[musli(packed)]` attribute,
607/// and is bitwise encodeable in the [`Binary`] mode using the [`Disabled`]
608/// allocator.
609///
610/// See the [help section for `#[musli(packed)]`][help] for more information.
611///
612/// [help]: crate::_help::derives#muslipacked
613#[inline]
614pub const fn is_bitwise_decode<T>() -> bool
615where
616 T: for<'de> Decode<'de, Binary, Disabled>,
617{
618 T::IS_BITWISE_DECODE
619}