musli_core/de/
unsized_visitor.rs

1use core::borrow::Borrow;
2use core::fmt;
3use core::marker::PhantomData;
4
5use crate::alloc::ToOwned;
6use crate::expecting::{self, Expecting};
7use crate::{Allocator, Context};
8
9/// A visitor for data where we might need to borrow without copying from the
10/// underlying [`Decoder`].
11///
12/// When implementing this trait you must use the `#[musli::trait_defaults]`
13/// attribute macro.
14///
15/// A visitor is needed with [`Decoder::decode_bytes`] and
16/// [`Decoder::decode_string`] because the caller doesn't know if the encoding
17/// format is capable of producing references to the underlying data directly or
18/// if it needs to be processed first.
19///
20/// If all you want is to decode a value by reference, use the
21/// [`Decoder::decode_unsized`] method.
22///
23/// By requiring a visitor we ensure that the caller has to handle both
24/// scenarios, even if one involves erroring. A type like [`Cow`] is an example
25/// of a type which can comfortably handle both.
26///
27/// # Examples
28///
29/// ```
30/// use std::fmt;
31///
32/// use musli::Context;
33/// use musli::de::UnsizedVisitor;
34///
35/// struct Visitor;
36///
37/// #[musli::trait_defaults]
38/// impl<'de, C> UnsizedVisitor<'de, C, [u8]> for Visitor
39/// where
40///     C: Context,
41/// {
42///     type Ok = ();
43///
44///     #[inline]
45///     fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46///         write!(
47///             f,
48///             "a reference of bytes"
49///         )
50///     }
51/// }
52/// ```
53///
54/// [`Cow`]: std::borrow::Cow
55/// [`Decoder::decode_bytes`]: crate::de::Decoder::decode_bytes
56/// [`Decoder::decode_string`]: crate::de::Decoder::decode_string
57/// [`Decoder::decode_unsized`]: crate::de::Decoder::decode_unsized
58/// [`Decoder`]: crate::de::Decoder
59#[allow(unused_variables)]
60pub trait UnsizedVisitor<'de, C, T>: Sized
61where
62    C: Context<Error = Self::Error, Allocator = Self::Allocator>,
63    T: ?Sized + ToOwned,
64{
65    /// The value produced by the visitor.
66    type Ok;
67    /// The error produced by the visitor.
68    type Error;
69    /// The allocator associated with the visitor.
70    type Allocator: Allocator;
71
72    /// This is a type argument used to hint to any future implementor that they
73    /// should be using the `#[musli::trait_defaults]`.
74    #[doc(hidden)]
75    type __UseMusliUnsizedVisitorAttributeMacro;
76
77    /// Format an error indicating what was expected by this visitor.
78    ///
79    /// Override to be more specific about the type that failed.
80    fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
81
82    /// Visit an owned value.
83    #[inline]
84    fn visit_owned(self, cx: C, value: T::Owned<Self::Allocator>) -> Result<Self::Ok, Self::Error> {
85        self.visit_ref(cx, value.borrow())
86    }
87
88    /// Visit a string that is borrowed directly from the source data.
89    #[inline]
90    fn visit_borrowed(self, cx: C, value: &'de T) -> Result<Self::Ok, Self::Error> {
91        self.visit_ref(cx, value)
92    }
93
94    /// Visit a value reference that is provided from the decoder in any manner
95    /// possible. Which might require additional decoding work.
96    #[inline]
97    fn visit_ref(self, cx: C, value: &T) -> Result<Self::Ok, Self::Error> {
98        Err(cx.message(expecting::bad_visitor_type(
99            &expecting::AnyValue,
100            ExpectingWrapper::new(&self),
101        )))
102    }
103}
104
105#[repr(transparent)]
106struct ExpectingWrapper<'a, T, C, I>
107where
108    I: ?Sized,
109{
110    inner: T,
111    _marker: PhantomData<(C, &'a I)>,
112}
113
114impl<T, C, U> ExpectingWrapper<'_, T, C, U>
115where
116    U: ?Sized,
117{
118    #[inline]
119    fn new(value: &T) -> &Self {
120        // SAFETY: `ExpectingWrapper` is repr(transparent) over `T`.
121        unsafe { &*(value as *const T as *const Self) }
122    }
123}
124
125impl<'de, T, C, U> Expecting for ExpectingWrapper<'_, T, C, U>
126where
127    T: UnsizedVisitor<'de, C, U, Error = C::Error, Allocator = C::Allocator>,
128    C: Context,
129    U: ?Sized + ToOwned,
130{
131    #[inline]
132    fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        self.inner.expecting(f)
134    }
135}