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 pub(crate) const fn to_class(&self) -> (StrFmt, PanicClass<'_>) {
190 match &self.var {
191 &PanicVariant::Str(strfmt, Packed(str)) => {
192 let ranged = RangedBytes {
193 start: 0,
194 end: str.len(),
195 bytes: str.as_bytes(),
196 };
197
198 (strfmt, PanicClass::PreFmt(ranged))
199 }
200 #[cfg(feature = "non_basic")]
201 PanicVariant::ShortString(strfmt, str) => (*strfmt, PanicClass::PreFmt(str.ranged())),
202 PanicVariant::PreFmt(str) => (StrFmt::DISPLAY, PanicClass::PreFmt(str.ranged())),
203 PanicVariant::Int(int) => (StrFmt::DISPLAY, PanicClass::Int(*int)),
204 #[cfg(feature = "non_basic")]
205 PanicVariant::Slice(slice) => (
206 StrFmt::new(slice.fmtarg.unpack()),
207 PanicClass::Slice(*slice),
208 ),
209 }
210 }
211
212 pub(crate) const fn to_class_truncated(
213 &self,
214 mut truncate_to: usize,
215 ) -> (StrFmt, PanicClass<'_>, WasTruncated) {
216 let (mut strfmt, class) = self.to_class();
217
218 if strfmt.leftpad as usize > truncate_to {
219 return (
220 StrFmt {
221 leftpad: strfmt.leftpad - truncate_to as u8,
222 rightpad: 0,
223 fmt_kind: FmtKind::Display,
224 },
225 PanicClass::PreFmt(RangedBytes::EMPTY),
226 WasTruncated::Yes(0),
227 );
228 } else {
229 truncate_to -= strfmt.leftpad as usize;
230 };
231
232 let was_trunc: WasTruncated;
233 let orig_len: usize;
234
235 match class {
236 PanicClass::PreFmt(str) => {
237 was_trunc = if let PanicVariant::PreFmt(pfmt) = self.var {
238 if pfmt.len() <= truncate_to {
239 WasTruncated::No
240 } else {
241 WasTruncated::Yes(0)
242 }
243 } else {
244 if let FmtKind::Display = strfmt.fmt_kind {
245 crate::utils::truncated_str_len(str, truncate_to)
246 } else {
247 crate::utils::truncated_debug_str_len(str, truncate_to)
248 }
249 };
250 orig_len = str.len();
251 }
252 PanicClass::Int(int) => {
253 strfmt.fmt_kind = FmtKind::Display;
254 was_trunc = if int.len() <= truncate_to {
255 WasTruncated::No
256 } else {
257 WasTruncated::Yes(0)
258 };
259 orig_len = int.len();
260 }
261 #[cfg(feature = "non_basic")]
262 PanicClass::Slice(_) => {
263 was_trunc = WasTruncated::No;
264 orig_len = 0;
265 }
266 }
267 truncate_to -= was_trunc.get_length(orig_len);
268
269 strfmt.rightpad = crate::utils::min_usize(strfmt.rightpad as usize, truncate_to) as u8;
270
271 (strfmt, class, was_trunc)
272 }
273}
274
275#[derive(Copy, Clone)]
276pub(crate) struct IntVal {
277 sign: Sign,
278 number_fmt: NumberFmt,
279 is_alternate: bool,
280 bits: u8,
282 len: u8,
284
285 value: Packed<u128>,
286}
287
288impl IntVal {
289 pub(crate) const fn from_u128(n: u128, bits: u8, f: FmtArg) -> PanicVal<'static> {
290 Self::new(Sign::Positive, n, bits, f)
291 }
292 pub(crate) const fn from_i128(n: i128, bits: u8, f: FmtArg) -> PanicVal<'static> {
293 let is_neg = if n < 0 {
294 Sign::Negative
295 } else {
296 Sign::Positive
297 };
298 Self::new(is_neg, n.unsigned_abs(), bits, f)
299 }
300
301 const fn new(sign: Sign, n: u128, bits: u8, fmtarg: FmtArg) -> PanicVal<'static> {
302 use crate::int_formatting::compute_len;
303
304 let len = compute_len(sign, n, bits, fmtarg);
305
306 let this = IntVal {
307 sign,
308 number_fmt: fmtarg.number_fmt,
309 is_alternate: fmtarg.is_alternate,
310 bits,
311 len,
312 value: Packed(n),
313 };
314
315 let var = if len as usize <= string_cap::PREFMT {
316 PanicVariant::PreFmt(this.fmt::<{ string_cap::PREFMT }>())
317 } else {
318 PanicVariant::Int(this)
319 };
320 PanicVal { var }
321 }
322
323 pub(crate) const fn fmt<const N: usize>(self) -> TailShortString<N> {
324 use crate::int_formatting::{fmt_binary, fmt_decimal, fmt_hexadecimal};
325
326 let IntVal {
327 sign,
328 number_fmt,
329 is_alternate,
330 len: _,
331 bits,
332 value: Packed(n),
333 } = self;
334
335 match number_fmt {
336 NumberFmt::Decimal => fmt_decimal::<N>(sign, n),
337 NumberFmt::Binary => {
338 let masked = apply_mask(sign, n, bits);
339 fmt_binary::<N>(masked, is_alternate)
340 }
341 NumberFmt::Hexadecimal => {
342 let masked = apply_mask(sign, n, bits);
343 fmt_hexadecimal::<N>(masked, is_alternate)
344 }
345 }
346 }
347
348 pub(crate) const fn len(&self) -> usize {
349 self.len as usize
350 }
351}
352
353const fn apply_mask(sign: Sign, n: u128, bits: u8) -> u128 {
354 if let Sign::Negative = sign {
355 let mask: u128 = if bits == 128 { !0 } else { (1 << bits) - 1 };
356
357 (n as i128).wrapping_neg() as u128 & mask
358 } else {
359 n
360 }
361}
362
363impl crate::PanicFmt for PanicVal<'_> {
364 type This = Self;
365 type Kind = crate::fmt::IsCustomType;
366
367 const PV_COUNT: usize = 1;
368}
369
370impl<'a> PanicVal<'a> {
371 pub const fn to_panicvals(&self, _: FmtArg) -> [PanicVal<'a>; 1] {
373 [*self]
374 }
375 pub const fn to_panicval(&self, _: FmtArg) -> PanicVal<'a> {
377 *self
378 }
379}