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/////////////////////////////////////////////////////////////////////////////