1use crate::{
2 fmt::{FmtArg, FmtKind, NumberFmt},
3 utils::{string_cap, Packed, PreFmtString, RangedBytes, Sign, TailShortString, WasTruncated},
4};
5
6#[cfg(feature = "non_basic")]
7use crate::{
8 array_string::TinyString,
9 fmt::{IsLast, ShortString},
10};
11
12#[derive(Copy, Clone)]
24pub struct PanicVal<'a> {
25 pub(crate) var: PanicVariant<'a>,
26}
27
28#[derive(Copy, Clone)]
29pub(crate) enum PanicVariant<'a> {
30 Str(StrFmt, Packed<&'a str>),
31 #[cfg(feature = "non_basic")]
32 ShortString(StrFmt, TinyString<{ string_cap::TINY }>),
33 PreFmt(PreFmtString),
34 Int(IntVal),
35 #[cfg(feature = "non_basic")]
36 Slice(crate::slice_stuff::Slice<'a>),
37}
38
39pub(crate) enum PanicClass<'a> {
40 PreFmt(RangedBytes<&'a [u8]>),
41 Int(IntVal),
42 #[cfg(feature = "non_basic")]
43 Slice(crate::slice_stuff::Slice<'a>),
44}
45
46#[derive(Copy, Clone)]
47pub(crate) struct StrFmt {
48 pub(crate) leftpad: u8,
49 pub(crate) rightpad: u8,
50 pub(crate) fmt_kind: FmtKind,
51}
52
53impl StrFmt {
54 const DISPLAY: Self = Self {
55 leftpad: 0,
56 rightpad: 0,
57 fmt_kind: FmtKind::Display,
58 };
59
60 pub const fn new(fmtarg: FmtArg) -> Self {
61 Self {
62 leftpad: 0,
63 rightpad: 0,
64 fmt_kind: fmtarg.fmt_kind,
65 }
66 }
67}
68
69impl<'a> PanicVal<'a> {
70 pub const EMPTY: Self = PanicVal::write_str("");
72
73 pub const fn leftpad(&self) -> u8 {
75 use self::PanicVariant as PV;
76
77 match self.var {
78 PV::Str(strfmt, ..) => strfmt.leftpad,
79 #[cfg(feature = "non_basic")]
80 PV::ShortString(strfmt, ..) => strfmt.leftpad,
81 _ => 0,
82 }
83 }
84 pub const fn rightpad(&self) -> u8 {
86 use self::PanicVariant as PV;
87
88 match self.var {
89 PV::Str(strfmt, ..) => strfmt.rightpad,
90 #[cfg(feature = "non_basic")]
91 PV::ShortString(strfmt, ..) => strfmt.rightpad,
92 _ => 0,
93 }
94 }
95}
96
97macro_rules! mutate_strfmt {
98 ($self:ident, |$strfmt:ident| $mutator:expr) => {
99 match $self.var {
100 PanicVariant::Str(mut $strfmt, str) => {
101 $mutator;
102 PanicVal {
103 var: PanicVariant::Str($strfmt, str),
104 }
105 }
106 #[cfg(feature = "non_basic")]
107 PanicVariant::ShortString(mut $strfmt, str) => {
108 $mutator;
109 PanicVal {
110 var: PanicVariant::ShortString($strfmt, str),
111 }
112 }
113 var => PanicVal { var },
114 }
115 };
116}
117
118impl<'a> PanicVal<'a> {
119 pub const fn with_leftpad(self, fmtarg: FmtArg) -> Self {
123 mutate_strfmt! {self, |strfmt| strfmt.leftpad = fmtarg.indentation}
124 }
125
126 pub const fn with_rightpad(self, fmtarg: FmtArg) -> Self {
130 mutate_strfmt! {self, |strfmt| strfmt.rightpad = fmtarg.indentation}
131 }
132
133 pub const fn write_str(string: &'a str) -> Self {
137 PanicVal {
138 var: PanicVariant::Str(StrFmt::DISPLAY, Packed(string)),
139 }
140 }
141
142 #[cfg(feature = "non_basic")]
144 pub const fn write_short_str(string: ShortString) -> Self {
145 Self {
146 var: PanicVariant::ShortString(StrFmt::DISPLAY, string.to_compact()),
147 }
148 }
149
150 #[cfg(feature = "non_basic")]
162 pub const fn from_element_separator(
163 separator: &str,
164 is_last_field: IsLast,
165 fmtarg: FmtArg,
166 ) -> Self {
167 let (concat, rightpad) = match (is_last_field, fmtarg.is_alternate) {
168 (IsLast::No, false) => (ShortString::concat(&[separator, " "]), 0),
169 (IsLast::Yes, false) => (ShortString::new(""), 0),
170 (IsLast::No, true) => (ShortString::concat(&[separator, "\n"]), fmtarg.indentation),
171 (IsLast::Yes, true) => (ShortString::concat(&[separator, "\n"]), 0),
172 };
173
174 let strfmt = StrFmt {
175 leftpad: 0,
176 rightpad,
177 fmt_kind: FmtKind::Display,
178 };
179 Self {
180 var: PanicVariant::ShortString(strfmt, concat.to_compact()),
181 }
182 }
183
184 #[inline(always)]
185 pub(crate) const fn __new(var: PanicVariant<'a>) -> Self {
186 Self { var }
187 }
188
189 #[allow(clippy::wrong_self_convention)]
190 pub(crate) const fn to_class(&self) -> (StrFmt, PanicClass<'_>) {
191 match &self.var {
192 &PanicVariant::Str(strfmt, Packed(str)) => {
193 let ranged = RangedBytes {
194 start: 0,
195 end: str.len(),
196 bytes: str.as_bytes(),
197 };
198
199 (strfmt, PanicClass::PreFmt(ranged))
200 }
201 #[cfg(feature = "non_basic")]
202 PanicVariant::ShortString(strfmt, str) => (*strfmt, PanicClass::PreFmt(str.ranged())),
203 PanicVariant::PreFmt(str) => (StrFmt::DISPLAY, PanicClass::PreFmt(str.ranged())),
204 PanicVariant::Int(int) => (StrFmt::DISPLAY, PanicClass::Int(*int)),
205 #[cfg(feature = "non_basic")]
206 PanicVariant::Slice(slice) => (
207 StrFmt::new(slice.fmtarg.unpack()),
208 PanicClass::Slice(*slice),
209 ),
210 }
211 }
212
213 #[allow(clippy::wrong_self_convention)]
214 pub(crate) const fn to_class_truncated(
215 &self,
216 mut truncate_to: usize,
217 ) -> (StrFmt, PanicClass<'_>, WasTruncated) {
218 let (mut strfmt, class) = self.to_class();
219
220 if strfmt.leftpad as usize > truncate_to {
221 return (
222 StrFmt {
223 leftpad: strfmt.leftpad - truncate_to as u8,
224 rightpad: 0,
225 fmt_kind: FmtKind::Display,
226 },
227 PanicClass::PreFmt(RangedBytes::EMPTY),
228 WasTruncated::Yes(0),
229 );
230 } else {
231 truncate_to -= strfmt.leftpad as usize;
232 };
233
234 let was_trunc: WasTruncated;
235 let orig_len: usize;
236
237 match class {
238 PanicClass::PreFmt(str) => {
239 was_trunc = if let PanicVariant::PreFmt(pfmt) = self.var {
240 if pfmt.len() <= truncate_to {
241 WasTruncated::No
242 } else {
243 WasTruncated::Yes(0)
244 }
245 } else {
246 if let FmtKind::Display = strfmt.fmt_kind {
247 crate::utils::truncated_str_len(str, truncate_to)
248 } else {
249 crate::utils::truncated_debug_str_len(str, truncate_to)
250 }
251 };
252 orig_len = str.len();
253 }
254 PanicClass::Int(int) => {
255 strfmt.fmt_kind = FmtKind::Display;
256 was_trunc = if int.len() <= truncate_to {
257 WasTruncated::No
258 } else {
259 WasTruncated::Yes(0)
260 };
261 orig_len = int.len();
262 }
263 #[cfg(feature = "non_basic")]
264 PanicClass::Slice(_) => {
265 was_trunc = WasTruncated::No;
266 orig_len = 0;
267 }
268 }
269 truncate_to -= was_trunc.get_length(orig_len);
270
271 strfmt.rightpad = crate::utils::min_usize(strfmt.rightpad as usize, truncate_to) as u8;
272
273 (strfmt, class, was_trunc)
274 }
275}
276
277#[derive(Copy, Clone)]
278pub(crate) struct IntVal {
279 sign: Sign,
280 number_fmt: NumberFmt,
281 is_alternate: bool,
282 bits: u8,
284 len: u8,
286
287 value: Packed<u128>,
288}
289
290impl IntVal {
291 pub(crate) const fn from_u128(n: u128, bits: u8, f: FmtArg) -> PanicVal<'static> {
292 Self::new_pv(Sign::Positive, n, bits, f)
293 }
294 pub(crate) const fn from_i128(n: i128, bits: u8, f: FmtArg) -> PanicVal<'static> {
295 let is_neg = if n < 0 {
296 Sign::Negative
297 } else {
298 Sign::Positive
299 };
300 Self::new_pv(is_neg, n.unsigned_abs(), bits, f)
301 }
302
303 const fn new_pv(sign: Sign, n: u128, bits: u8, fmtarg: FmtArg) -> PanicVal<'static> {
304 use crate::int_formatting::compute_len;
305
306 let len = compute_len(sign, n, bits, fmtarg);
307
308 let this = IntVal {
309 sign,
310 number_fmt: fmtarg.number_fmt,
311 is_alternate: fmtarg.is_alternate,
312 bits,
313 len,
314 value: Packed(n),
315 };
316
317 let var = if len as usize <= string_cap::PREFMT {
318 PanicVariant::PreFmt(this.fmt::<{ string_cap::PREFMT }>())
319 } else {
320 PanicVariant::Int(this)
321 };
322 PanicVal { var }
323 }
324
325 pub(crate) const fn fmt<const N: usize>(self) -> TailShortString<N> {
326 use crate::int_formatting::{fmt_binary, fmt_decimal, fmt_hexadecimal};
327
328 let IntVal {
329 sign,
330 number_fmt,
331 is_alternate,
332 len: _,
333 bits,
334 value: Packed(n),
335 } = self;
336
337 match number_fmt {
338 NumberFmt::Decimal => fmt_decimal::<N>(sign, n),
339 NumberFmt::Binary => {
340 let masked = apply_mask(sign, n, bits);
341 fmt_binary::<N>(masked, is_alternate)
342 }
343 NumberFmt::Hexadecimal => {
344 let masked = apply_mask(sign, n, bits);
345 fmt_hexadecimal::<N>(masked, is_alternate)
346 }
347 }
348 }
349
350 pub(crate) const fn len(&self) -> usize {
351 self.len as usize
352 }
353}
354
355const fn apply_mask(sign: Sign, n: u128, bits: u8) -> u128 {
356 if let Sign::Negative = sign {
357 let mask: u128 = if bits == 128 { !0 } else { (1 << bits) - 1 };
358
359 (n as i128).wrapping_neg() as u128 & mask
360 } else {
361 n
362 }
363}
364
365impl crate::PanicFmt for PanicVal<'_> {
366 type This = Self;
367 type Kind = crate::fmt::IsCustomType;
368
369 const PV_COUNT: usize = 1;
370}
371
372impl<'a> PanicVal<'a> {
373 pub const fn to_panicvals(&self, _: FmtArg) -> [PanicVal<'a>; 1] {
375 [*self]
376 }
377 pub const fn to_panicval(&self, _: FmtArg) -> PanicVal<'a> {
379 *self
380 }
381}