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()));