Skip to main content

writeable/
concat.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5use crate::TryWriteable;
6use crate::Writeable;
7use core::fmt;
8
9/// A [`Writeable`] that efficiently concatenates two other [`Writeable`]s.
10///
11/// See the [`concat_writeable!`] macro for a convenient way to make one of these.
12///
13/// # Examples
14///
15/// ```
16/// use writeable::adapters::Concat;
17/// use writeable::assert_writeable_eq;
18///
19/// assert_writeable_eq!(Concat("Number: ", 25), "Number: 25");
20/// ```
21///
22/// With [`TryWriteable`]:
23///
24/// ```
25/// use writeable::adapters::Concat;
26/// use writeable::assert_try_writeable_eq;
27/// use writeable::TryWriteable;
28///
29/// struct AlwaysPanic;
30///
31/// impl TryWriteable for AlwaysPanic {
32///     type Error = &'static str;
33///     fn try_write_to_parts<W: writeable::PartsWrite + ?Sized>(
34///         &self,
35///         _sink: &mut W,
36///     ) -> Result<Result<(), Self::Error>, core::fmt::Error> {
37///         // Unreachable panic: the first Writeable errors,
38///         // so the second Writeable is not evaluated.
39///         panic!("this is a test to demonstrate unreachable code")
40///     }
41/// }
42///
43/// let writeable0: Result<&str, &str> = Err("error message");
44/// let writeable1 = AlwaysPanic;
45///
46/// assert_try_writeable_eq!(
47///     Concat(writeable0, writeable1),
48///     "error message",
49///     Err("error message"),
50/// )
51/// ```
52#[derive(#[automatically_derived]
#[allow(clippy::exhaustive_structs)]
impl<A: ::core::fmt::Debug, B: ::core::fmt::Debug> ::core::fmt::Debug for
    Concat<A, B> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field2_finish(f, "Concat",
            &self.0, &&self.1)
    }
}Debug)]
53#[allow(clippy::exhaustive_structs)] // designed for nesting
54pub struct Concat<A, B>(pub A, pub B);
55
56impl<A, B> Writeable for Concat<A, B>
57where
58    A: Writeable,
59    B: Writeable,
60{
61    #[inline]
62    fn write_to<W: fmt::Write + ?Sized>(&self, sink: &mut W) -> fmt::Result {
63        self.0.write_to(sink)?;
64        self.1.write_to(sink)
65    }
66    #[inline]
67    fn write_to_parts<S: crate::PartsWrite + ?Sized>(&self, sink: &mut S) -> fmt::Result {
68        self.0.write_to_parts(sink)?;
69        self.1.write_to_parts(sink)
70    }
71    #[inline]
72    fn writeable_length_hint(&self) -> crate::LengthHint {
73        self.0.writeable_length_hint() + self.1.writeable_length_hint()
74    }
75}
76
77impl<A, B, E> TryWriteable for Concat<A, B>
78where
79    A: TryWriteable<Error = E>,
80    B: TryWriteable<Error = E>,
81{
82    type Error = E;
83    #[inline]
84    fn try_write_to<W: fmt::Write + ?Sized>(
85        &self,
86        sink: &mut W,
87    ) -> Result<Result<(), Self::Error>, fmt::Error> {
88        if let Err(e) = self.0.try_write_to(sink)? {
89            return Ok(Err(e));
90        }
91        self.1.try_write_to(sink)
92    }
93    #[inline]
94    fn try_write_to_parts<S: crate::PartsWrite + ?Sized>(
95        &self,
96        sink: &mut S,
97    ) -> Result<Result<(), Self::Error>, fmt::Error> {
98        if let Err(e) = self.0.try_write_to_parts(sink)? {
99            return Ok(Err(e));
100        }
101        self.1.try_write_to_parts(sink)
102    }
103    #[inline]
104    fn writeable_length_hint(&self) -> crate::LengthHint {
105        self.0.writeable_length_hint() + self.1.writeable_length_hint()
106    }
107}
108
109impl<A, B> fmt::Display for Concat<A, B>
110where
111    A: Writeable,
112    B: Writeable,
113{
114    #[inline]
115    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116        self.0.write_to(f)?;
117        self.1.write_to(f)
118    }
119}
120
121/// Returns a [`Writeable`] concatenating any number of [`Writeable`]s.
122///
123/// The macro resolves to a nested [`Concat`].
124///
125/// # Examples
126///
127/// ```
128/// use writeable::assert_writeable_eq;
129///
130/// let concatenated = writeable::concat_writeable!("Health: ", 5, '/', 8);
131///
132/// assert_writeable_eq!(concatenated, "Health: 5/8");
133/// ```
134#[macro_export]
135#[doc(hidden)] // macro
136macro_rules! __concat_writeable {
137    // Base case:
138    ($x:expr) => ($x);
139    // `$x` followed by at least one `$y,`
140    ($x:expr, $($y:expr),+) => (
141        // Call `concat_writeable!` recursively on the tail `$y`
142        $crate::adapters::Concat($x, $crate::concat_writeable!($($y),+))
143    )
144}
145#[doc(inline)]
146pub use __concat_writeable as concat_writeable;