1use crate::{Unit, Width};
2use core::fmt::{Display, Error, Formatter};
3use derive_more::{AsMut, AsRef, Deref, DerefMut, From};
4
5#[derive(Debug, Clone, Copy)]
9pub struct Excess<'a, Value, PadBlock = char>
10where
11 Value: Width,
12 PadBlock: Display,
13{
14 pub value: &'a Value,
16 pub pad_block: &'a PadBlock,
18 pub value_width: usize,
20 pub total_width: usize,
22}
23
24pub trait ExcessHandler<Value, PadBlock = char>
50where
51 Value: Width,
52 PadBlock: Display,
53{
54 fn handle_excess(
56 &self,
57 excess: Excess<Value, PadBlock>,
58 formatter: &mut Formatter<'_>,
59 ) -> Result<(), Error>;
60}
61
62type ExcessHandlingFunctionInner<Value, PadBlock> =
63 fn(Excess<Value, PadBlock>, &mut Formatter<'_>) -> Result<(), Error>;
64
65#[derive(Clone, Copy, AsMut, AsRef, Deref, DerefMut, From)]
88pub struct ExcessHandlingFunction<Value, PadBlock = char>(
89 pub ExcessHandlingFunctionInner<Value, PadBlock>,
90)
91where
92 Value: Width,
93 PadBlock: Display;
94
95impl<Value, PadBlock> ExcessHandler<Value, PadBlock> for ExcessHandlingFunction<Value, PadBlock>
96where
97 Value: Width,
98 PadBlock: Display,
99{
100 fn handle_excess(
101 &self,
102 excess: Excess<Value, PadBlock>,
103 formatter: &mut Formatter<'_>,
104 ) -> Result<(), Error> {
105 self.0(excess, formatter)
106 }
107}
108
109pub trait UnitExcessHandler<Value, PadBlock = char>: Unit + ExcessHandler<Value, PadBlock>
111where
112 Value: Width,
113 PadBlock: Display,
114{
115}
116
117macro_rules! preset {
118 (
119 impl $implementation:expr;
120 $(#[$struct_attr:meta])*
121 struct $struct_name:ident;
122 $(#[$fn_attr:meta])*
123 fn $fn_name:ident;
124 ) => {
125 $(#[$struct_attr])*
126 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
127 pub struct $struct_name;
128
129 impl Unit for $struct_name {
130 const VALUE: Self = $struct_name;
131 }
132
133 impl<Value: Width, PadBlock: Display> UnitExcessHandler<Value, PadBlock> for $struct_name {}
134
135 impl<Value, PadBlock> ExcessHandler<Value, PadBlock> for $struct_name
136 where
137 Value: Width,
138 PadBlock: Display,
139 {
140 fn handle_excess(
141 &self,
142 excess: Excess<Value, PadBlock>,
143 formatter: &mut Formatter<'_>,
144 ) -> Result<(), Error> {
145 let handle_excess: ExcessHandlingFunctionInner<Value, PadBlock> = $implementation;
146 handle_excess(excess, formatter)
147 }
148 }
149
150 impl<Value, PadBlock> From<$struct_name> for ExcessHandlingFunction<Value, PadBlock>
151 where
152 Value: Width,
153 PadBlock: Display,
154 {
155 fn from(_: $struct_name) -> Self {
156 ExcessHandlingFunction(|excess, formatter| {
157 $struct_name.handle_excess(excess, formatter)
158 })
159 }
160 }
161
162 $(#[$fn_attr])*
163 pub fn $fn_name<Value, PadBlock>() -> ExcessHandlingFunction<Value, PadBlock>
164 where
165 Value: Width,
166 PadBlock: Display,
167 {
168 ExcessHandlingFunction::from($struct_name)
169 }
170 };
171}
172
173preset! {
174 impl |excess, formatter| write!(formatter, "{}", excess.value);
175
176 #[doc = "Ignore excess, write `value` to `formatter` without padding."]
177 #[doc = ""]
178 #[doc = "**When `value.width()` is not greater than `total_width`,"]
179 #[doc = "add pads as usual:**"]
180 #[doc = "```"]
181 #[doc = "# use pretty_assertions::assert_eq;"]
182 #[doc = "use zero_copy_pads::{PaddedValue, AlignRight, IgnoreExcess};"]
183 #[doc = "let padded_value = PaddedValue {"]
184 #[doc = r#" handle_excess: IgnoreExcess,"#]
185 #[doc = r#" value: "abcdef","#]
186 #[doc = r#" pad_block: '-',"#]
187 #[doc = r#" total_width: 9,"#]
188 #[doc = r#" pad: AlignRight,"#]
189 #[doc = "};"]
190 #[doc = r#"assert_eq!(padded_value.to_string(), "---abcdef");"#]
191 #[doc = "```"]
192 #[doc = ""]
193 #[doc = "**When `value.width()` is greater than `total_width`,"]
194 #[doc = "display `value` as is:**"]
195 #[doc = "```"]
196 #[doc = "# use pretty_assertions::assert_eq;"]
197 #[doc = "use zero_copy_pads::{PaddedValue, AlignRight, IgnoreExcess};"]
198 #[doc = "let padded_value = PaddedValue {"]
199 #[doc = r#" handle_excess: IgnoreExcess,"#]
200 #[doc = r#" value: "abcdefghijkl","#]
201 #[doc = r#" pad_block: '-',"#]
202 #[doc = r#" total_width: 9,"#]
203 #[doc = r#" pad: AlignRight,"#]
204 #[doc = "};"]
205 #[doc = r#"assert_eq!(padded_value.to_string(), "abcdefghijkl");"#]
206 #[doc = "```"]
207 struct IgnoreExcess;
208
209 #[doc = "Create a [`ExcessHandlingFunction`] that ignores excesses."]
210 #[doc = ""]
211 #[doc = "see [`IgnoreExcess`]."]
212 fn ignore_excess;
213}
214
215preset! {
216 impl |_, _| Err(Error);
217
218 #[doc = "Forbid all excesses, raise `fmt::Error` once encounter one."]
219 #[doc = ""]
220 #[doc = "**When `value.width()` is not greater than `total_width`,"]
221 #[doc = "add pads as usual:**"]
222 #[doc = "```"]
223 #[doc = "# use pretty_assertions::assert_eq;"]
224 #[doc = "use zero_copy_pads::{PaddedValue, AlignRight, ErrorOnExcess};"]
225 #[doc = "let padded_value = PaddedValue {"]
226 #[doc = r#" handle_excess: ErrorOnExcess,"#]
227 #[doc = r#" value: "abcdef","#]
228 #[doc = r#" pad_block: '-',"#]
229 #[doc = r#" total_width: 9,"#]
230 #[doc = r#" pad: AlignRight,"#]
231 #[doc = "};"]
232 #[doc = r#"assert_eq!(padded_value.to_string(), "---abcdef");"#]
233 #[doc = "```"]
234 #[doc = ""]
235 #[doc = "**When `value.width()` is greater than `total_width`,"]
236 #[doc = "return an [`Err`] of [`fmt::Error`](Error):**"]
237 #[doc = "```"]
238 #[doc = "# use pretty_assertions::assert_eq;"]
239 #[doc = "use zero_copy_pads::{PaddedValue, AlignRight, ErrorOnExcess};"]
240 #[doc = "let padded_value = PaddedValue {"]
241 #[doc = r#" handle_excess: ErrorOnExcess,"#]
242 #[doc = r#" value: "abcdefghijkl","#]
243 #[doc = r#" pad_block: '-',"#]
244 #[doc = r#" total_width: 9,"#]
245 #[doc = r#" pad: AlignRight,"#]
246 #[doc = "};"]
247 #[doc = "let mut output = String::new();"]
248 #[doc = r#"std::fmt::write("#]
249 #[doc = r#" &mut output,"#]
250 #[doc = r#" format_args!("{}", padded_value),"#]
251 #[doc = r#").unwrap_err();"#]
252 #[doc = "```"]
253 struct ErrorOnExcess;
254
255 #[doc = "Create a [`ExcessHandlingFunction`] that forbids excesses."]
256 #[doc = ""]
257 #[doc = "see [`ErrorOnExcess`]."]
258 fn error_on_excess;
259}
260
261preset! {
262 impl |excess, _| panic!(
263 "value's width ({}) is greater than total_width ({})",
264 excess.value_width, excess.total_width,
265 );
266
267 #[doc = "Forbid all excesses, panic once encounter one."]
268 #[doc = ""]
269 #[doc = "**When `value.width()` is not greater than `total_width`,"]
270 #[doc = "add pads as usual:**"]
271 #[doc = "```"]
272 #[doc = "# use pretty_assertions::assert_eq;"]
273 #[doc = "use zero_copy_pads::{PaddedValue, AlignRight, PanicOnExcess};"]
274 #[doc = "let padded_value = PaddedValue {"]
275 #[doc = r#" handle_excess: PanicOnExcess,"#]
276 #[doc = r#" value: "abcdef","#]
277 #[doc = r#" pad_block: '-',"#]
278 #[doc = r#" total_width: 9,"#]
279 #[doc = r#" pad: AlignRight,"#]
280 #[doc = "};"]
281 #[doc = r#"assert_eq!(padded_value.to_string(), "---abcdef");"#]
282 #[doc = "```"]
283 #[doc = ""]
284 #[doc = "**When `value.width()` is greater than `total_width`, panic:**"]
285 #[doc = "```should_panic"]
286 #[doc = "# use pretty_assertions::assert_eq;"]
287 #[doc = "use zero_copy_pads::{PaddedValue, AlignRight, PanicOnExcess};"]
288 #[doc = "let padded_value = PaddedValue {"]
289 #[doc = r#" handle_excess: PanicOnExcess,"#]
290 #[doc = r#" value: "abcdefghijkl","#]
291 #[doc = r#" pad_block: '-',"#]
292 #[doc = r#" total_width: 9,"#]
293 #[doc = r#" pad: AlignRight,"#]
294 #[doc = "};"]
295 #[doc = r#"assert_eq!(padded_value.to_string(), "abcdefghijkl");"#]
296 #[doc = "```"]
297 struct PanicOnExcess;
298
299 #[doc = "Create a [`ExcessHandlingFunction`] that forbids excesses."]
300 #[doc = ""]
301 #[doc = "see [`PanicOnExcess`]."]
302 fn panic_on_excess;
303}