const_format/marker_traits/
write_marker.rs

1//! Marker trait for types that can be written to.
2//!
3//!
4
5use crate::fmt::{Formatter, StrWriter, StrWriterMut};
6
7use core::marker::PhantomData;
8
9////////////////////////////////////////////////////////////////////////////////
10
11/// Marker trait for types that can be written into.
12///
13/// # Implementors
14///
15/// Types that implement this trait are also expected to implement these inherent methods:
16///
17/// ```ignore
18/// // use const_format::{FormattingFlags, Formatter};
19///
20/// const fn borrow_mutably(&mut self) -> &mut Self
21/// const fn make_formatter(&mut self, flags: FormattingFlags) -> Formatter<'_>
22/// ```
23///
24/// # Coercions
25///
26/// The [`Kind`](#associatedtype.Kind) and [`This`](#associatedtype.This) associated types
27/// are used in the [`IsAWriteMarker`] marker type
28/// to convert a `&mut StrWriter<_>` to a `StrWriterMut<'_>`,
29/// and leave other mutable references unconverted.
30///
31/// # Example
32///
33/// Implementing this trait for a String-like inline allocated type.
34///
35/// ```rust
36///
37/// use const_format::marker_traits::{IsNotAStrWriter, WriteMarker};
38/// use const_format::{Formatter, FormattingFlags};
39/// use const_format::writec;
40///
41/// mod arraystring {
42///     use const_format::marker_traits::{IsNotAStrWriter, WriteMarker};
43///     use const_format::{Formatter, FormattingFlags};
44///
45///     const ARRAY_CAP: usize = 64;
46///     pub struct ArrayString  {
47///         len: usize,
48///         arr: [u8; ARRAY_CAP],
49///     }
50///    
51///     impl WriteMarker for ArrayString  {
52///         type Kind = IsNotAStrWriter;
53///         type This = Self;
54///     }
55///    
56///     impl ArrayString {
57///         pub const fn new() -> Self {
58///             Self { len: 0, arr: [0; ARRAY_CAP] }
59///         }
60///         
61///         // Gets the part of the array that has been written to.
62///         pub const fn as_bytes(&self) -> &[u8] {
63///             const_format::utils::slice_up_to_len_alt(&self.arr, self.len)
64///         }
65///    
66///         pub const fn borrow_mutably(&mut self) -> &mut Self {
67///             self
68///         }
69///    
70///         pub const fn make_formatter(&mut self, flags: FormattingFlags) -> Formatter<'_> {
71///             Formatter::from_custom(&mut self.arr, &mut self.len, flags)
72///         }
73///     }
74/// }
75/// use arraystring::ArrayString;
76///
77///
78/// let mut buffer = ArrayString::new();
79///
80/// writec!(buffer, "{:?}", [3u8, 5])?;
81/// assert_eq!(buffer.as_bytes(), b"[3, 5]");
82///
83/// writec!(buffer, "{}{:b}", "Hello, world!", 100u16)?;
84/// assert_eq!(buffer.as_bytes(), b"[3, 5]Hello, world!1100100");
85///
86/// # Ok::<(), const_format::Error>(())
87/// ```
88pub trait WriteMarker {
89    /// Whether this is a StrWriter or not, this can be either of
90    /// [`IsAStrWriter`] or [`IsNotAStrWriter`]
91    ///
92    /// [`IsAStrWriter`]: crate::marker_traits::IsAStrWriter
93    /// [`IsNotAStrWriter`]: crate::marker_traits::IsNotAStrWriter
94    type Kind;
95
96    /// The type after dereferencing,
97    /// implemented as `type This = Self;` for all non-reference types
98    type This: ?Sized;
99}
100
101/// Marker type for `StrWriter`'s [`Kind`] in [`WriteMarker`]s
102///
103/// [`Kind`]: ./trait.WriteMarker.html#associatedtype.Kind
104/// [`WriteMarker`]: ./trait.WriteMarker.html
105///
106pub struct IsAStrWriter;
107
108/// Marker type for the [`Kind`] of all non-`StrWriter` types that implement [`WriteMarker`].
109///
110/// [`Kind`]: ./trait.WriteMarker.html#associatedtype.Kind
111/// [`WriteMarker`]: ./trait.WriteMarker.html
112///
113pub struct IsNotAStrWriter;
114
115///////////////////////////////////////////////////////////////////////////////
116
117impl<T: ?Sized> WriteMarker for StrWriter<T> {
118    type Kind = IsAStrWriter;
119    type This = Self;
120}
121
122impl WriteMarker for StrWriterMut<'_> {
123    type Kind = IsNotAStrWriter;
124    type This = Self;
125}
126
127impl WriteMarker for Formatter<'_> {
128    type Kind = IsNotAStrWriter;
129    type This = Self;
130}
131
132impl<T> WriteMarker for &T
133where
134    T: ?Sized + WriteMarker,
135{
136    type Kind = T::Kind;
137    type This = T::This;
138}
139
140impl<T> WriteMarker for &mut T
141where
142    T: ?Sized + WriteMarker,
143{
144    type Kind = T::Kind;
145    type This = T::This;
146}
147
148///////////////////////////////////////////////////////////////////////////////
149
150/// Hack used to automatically convert a
151/// mutable reference to a [`StrWriter`] to a [`StrWriterMut`],
152/// and do nothing with other types.
153///
154/// The conversion is done with the `coerce` methods.
155///
156///
157/// # Type parameters
158///
159/// `K` is `<R as WriteMarker>::Kind`
160/// The kind of type that `T` is, either a [`IsAStrWriter`] or [`IsNotAStrWriter`]
161///
162/// `T` is `<R as WriteMarker>::This`:
163/// The `R` type after removing all layers of references.
164///
165/// `R`: A type that implements `WriteMarker`.
166///
167/// # Coerce Method
168///
169/// The `coerce` method is what does the conversion from a `&mut T`
170/// depending on the `K` type parameter:
171///
172/// - [`IsAStrWriter`]: the reference is converted into a `StrWriterMut<'_>`.
173///
174/// - [`IsNotAStrWriter`]: the reference is simply returned unchanged.
175///  
176///
177/// [`StrWriter`]: ../fmt/struct.StrWriter.html
178///
179/// [`StrWriterMut`]: ../fmt/struct.StrWriterMut.html
180///
181/// [`IsAStrWriter`]: ./struct.IsAStrWriter.html
182///
183/// [`IsNotAStrWriter`]: ./struct.IsNotAStrWriter.html
184///
185#[allow(clippy::type_complexity)]
186pub struct IsAWriteMarker<K, T: ?Sized, R: ?Sized>(
187    PhantomData<(
188        PhantomData<fn() -> PhantomData<K>>,
189        PhantomData<fn() -> PhantomData<T>>,
190        PhantomData<fn() -> PhantomData<R>>,
191    )>,
192);
193
194impl<K, T: ?Sized, R: ?Sized> Copy for IsAWriteMarker<K, T, R> {}
195
196impl<K, T: ?Sized, R: ?Sized> Clone for IsAWriteMarker<K, T, R> {
197    fn clone(&self) -> Self {
198        *self
199    }
200}
201
202impl<R> IsAWriteMarker<R::Kind, R::This, R>
203where
204    R: ?Sized + WriteMarker,
205{
206    /// Constructs a `IsAWriteMarker`
207    pub const NEW: Self = Self(PhantomData);
208}
209
210/////////////////////////////////////////////////////////////////////////////
211
212impl<K, T: ?Sized, R: ?Sized> IsAWriteMarker<K, T, R> {
213    /// Infers the type parmaeters of this `IsAWriteMarker` with the passed reference.
214    #[inline(always)]
215    pub const fn infer_type(self, _: &R) -> Self {
216        self
217    }
218}
219
220/////////////////////////////////////////////////////////////////////////////
221
222impl<T: ?Sized, R: ?Sized> IsAWriteMarker<IsAStrWriter, StrWriter<T>, R> {
223    /// Converts the `&mut StrWriter` to a `StrWriterMut<'_>`.
224    #[inline(always)]
225    pub const fn coerce(self, mutref: &mut StrWriter) -> StrWriterMut<'_> {
226        mutref.as_mut()
227    }
228}
229
230impl<T: ?Sized, R: ?Sized> IsAWriteMarker<IsNotAStrWriter, T, R> {
231    /// An idntity function, just takes`mutref` and returns it.
232    #[inline(always)]
233    pub const fn coerce(self, mutref: &mut T) -> &mut T {
234        mutref
235    }
236}
237
238/////////////////////////////////////////////////////////////////////////////