custom_print/
write_fns.rs

1#[cfg(feature = "alloc")]
2use alloc::string::{String, ToString};
3#[cfg(feature = "std")]
4use std::ffi::{CStr, CString, NulError};
5#[cfg(feature = "std")]
6use std::os::raw::c_char;
7
8use crate::{WriteBytes, WriteStr, WriteStrAsBytes};
9
10macro_rules! with_docs {
11    ( docs: { $( $doc:expr ),* $(,)? }, item: { $item:item } ) => {
12        $( #[doc = $doc] )*
13        $item
14    };
15}
16
17macro_rules! define_write_fn {
18    (
19        $name:ident,
20        ($($params:ty),*),
21        $writes:literal,
22        $into_write_fns:literal
23    ) => {
24        with_docs!(
25            docs: {
26                ::core::concat!(
27                    "A wrapper for write functions `for<R> FnMut(",
28                    ::core::stringify!($($params),*),
29                    ") -> R`."
30                ),
31                "",
32                ::core::concat!(
33                    "It implements ",
34                    $writes,
35                    " and can be used in conjunction with ",
36                    $into_write_fns,
37                    " to simplify type inference."
38                ),
39                "",
40                "[`IntoWriteFn`]: trait.IntoWriteFn.html",
41                "[`IntoTryWriteFn`]: trait.IntoTryWriteFn.html"
42            },
43            item: {
44                #[derive(Clone, Copy, Debug, Eq, PartialEq)]
45                pub struct $name<F, R>(F)
46                where
47                    F: FnMut($($params),*) -> R;
48            }
49        );
50
51        impl<F, R> $name<F, R>
52        where
53            F: FnMut($($params),*) -> R,
54        {
55            with_docs!(
56                docs: {
57                    ::core::concat!(
58                        "Creates a new `",
59                        ::core::stringify!($name),
60                        "` containing the given closure or function."
61                    )
62                },
63                item: {
64                    pub fn new(closure: F) -> Self {
65                        Self(closure)
66                    }
67                }
68            );
69        }
70    };
71}
72
73macro_rules! define_write_str_fn {
74    ($name:ident, ($($params:ty),*), $buf:ident => ($($args:tt)*)) => {
75        define_write_fn!(
76            $name,
77            ($($params),*),
78            "[`WriteStr`] trait",
79            "[`IntoWriteFn`] and [`IntoTryWriteFn`] traits"
80        );
81
82        impl<F, R> WriteStr for $name<F, R>
83        where
84            F: FnMut($($params),*) -> R,
85        {
86            type Output = R;
87
88            fn write_str(&mut self, $buf: &str) -> Self::Output {
89                self.0($($args)*)
90            }
91        }
92    };
93}
94
95macro_rules! define_write_bytes_fn {
96    ($name:ident, ($($params:ty),*), $buf:ident => ($($args:tt)*)) => {
97        define_write_fn!(
98            $name,
99            ($($params),*),
100            "[`WriteBytes`] and [`WriteStr`] traits",
101            "[`IntoWriteFn`] and [`IntoTryWriteFn`] traits"
102        );
103
104        impl<F, R> WriteBytes for $name<F, R>
105        where
106            F: FnMut($($params),*) -> R,
107        {
108            type Output = R;
109
110            fn write_bytes(&mut self, $buf: &[u8]) -> Self::Output {
111                self.0($($args)*)
112            }
113        }
114
115        impl<F, R> WriteStrAsBytes for $name<F, R> where F: FnMut($($params),*) -> R {}
116    };
117}
118
119#[cfg(feature = "std")]
120macro_rules! define_write_cstr_fn {
121    ($name:ident, ($($params:ty),*), $cstr:ident => ($($args:tt)*)) => {
122        define_write_fn!(
123            $name,
124            ($($params),*),
125            "[`WriteBytes`] and [`WriteStr`] traits",
126            "[`IntoWriteFn`] trait"
127        );
128
129        impl<F, R> WriteBytes for $name<F, R>
130        where
131            F: FnMut($($params),*) -> R,
132        {
133            type Output = R;
134
135            fn write_bytes(&mut self, buf: &[u8]) -> Self::Output {
136                let $cstr = match CString::new(buf.as_ref()) {
137                    Ok(ok) => ok,
138                    Err(err) => panic!(
139                        "nul byte found in provided data at position: {}, buffer: {:?}",
140                        err.nul_position(),
141                        buf
142                    ),
143                };
144                self.0($($args)*)
145            }
146        }
147
148        impl<F, R> WriteStrAsBytes for $name<F, R> where F: FnMut($($params),*) -> R {}
149    };
150}
151
152#[cfg(feature = "std")]
153macro_rules! define_try_write_cstr_fn {
154    ($name:ident, ($($params:ty),*), $cstr:ident => ($($args:tt)*)) => {
155        define_write_fn!(
156            $name,
157            ($($params),*),
158            "[`WriteBytes`] and [`WriteStr`] traits",
159            "[`IntoTryWriteFn`] trait"
160        );
161
162        impl<F, R> WriteBytes for $name<F, R>
163        where
164            F: FnMut($($params),*) -> R,
165        {
166            type Output = Result<R, NulError>;
167
168            fn write_bytes(&mut self, buf: &[u8]) -> Self::Output {
169                CString::new(buf.as_ref()).map(|$cstr| self.0($($args)*))
170            }
171        }
172
173        impl<F, R> WriteStrAsBytes for $name<F, R>
174        where
175            F: FnMut($($params),*) -> R {}
176    };
177}
178
179define_write_bytes_fn!(WritePtrLenFn, (*const u8, usize), buf => (buf.as_ptr(), buf.len()));
180define_write_bytes_fn!(WriteLenPtrFn, (usize, *const u8), buf => (buf.len(), buf.as_ptr()));
181define_write_bytes_fn!(WriteBytesFn, (&[u8]), buf => (buf));
182
183define_write_str_fn!(WriteStrFn, (&str), buf => (buf));
184#[cfg(feature = "alloc")]
185define_write_str_fn!(WriteStringFn, (String), buf => (buf.to_string()));
186
187#[cfg(feature = "std")]
188define_write_cstr_fn!(WriteCStrFn, (&CStr), cstr => (cstr.as_c_str()));
189#[cfg(feature = "std")]
190define_write_cstr_fn!(WriteCStringFn, (CString), cstr => (cstr));
191#[cfg(feature = "std")]
192define_write_cstr_fn!(WriteCCharPtrFn, (*const c_char), cstr => (cstr.as_ptr()));
193
194#[cfg(feature = "std")]
195define_try_write_cstr_fn!(TryWriteCStrFn, (&CStr), cstr => (cstr.as_c_str()));
196#[cfg(feature = "std")]
197define_try_write_cstr_fn!(TryWriteCStringFn, (CString), cstr => (cstr));
198#[cfg(feature = "std")]
199define_try_write_cstr_fn!(TryWriteCCharPtrFn, (*const c_char), cstr => (cstr.as_ptr()));