1use crate::{
15 error::panic_invalid_radix,
16 ibig::IBig,
17 radix::{self, Digit, DigitCase},
18 repr::TypedReprRef,
19 ubig::UBig,
20 Sign::{self, *},
21};
22use core::fmt::{
23 self, Alignment, Binary, Debug, Display, Formatter, LowerHex, Octal, UpperHex, Write,
24};
25use digit_writer::DigitWriter;
26
27mod digit_writer;
28mod non_power_two;
29mod power_two;
30
31pub use radix::{MAX_RADIX, MIN_RADIX};
32
33impl Display for UBig {
34 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
35 InRadixWriter {
36 sign: Positive,
37 magnitude: self.repr(),
38 radix: 10,
39 prefix: "",
40 digit_case: DigitCase::NoLetters,
41 }
42 .fmt(f)
43 }
44}
45
46impl Debug for UBig {
47 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
48 DoubleEnd {
49 sign: Positive,
50 magnitude: self.repr(),
51 verbose: f.alternate(),
52 }
53 .fmt(f)
54 }
55}
56
57impl Binary for UBig {
58 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
59 InRadixWriter {
60 sign: Positive,
61 magnitude: self.repr(),
62 radix: 2,
63 prefix: if f.alternate() { "0b" } else { "" },
64 digit_case: DigitCase::NoLetters,
65 }
66 .fmt(f)
67 }
68}
69
70impl Octal for UBig {
71 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
72 InRadixWriter {
73 sign: Positive,
74 magnitude: self.repr(),
75 radix: 8,
76 prefix: if f.alternate() { "0o" } else { "" },
77 digit_case: DigitCase::NoLetters,
78 }
79 .fmt(f)
80 }
81}
82
83impl LowerHex for UBig {
84 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
85 InRadixWriter {
86 sign: Positive,
87 magnitude: self.repr(),
88 radix: 16,
89 prefix: if f.alternate() { "0x" } else { "" },
90 digit_case: DigitCase::Lower,
91 }
92 .fmt(f)
93 }
94}
95
96impl UpperHex for UBig {
97 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
98 InRadixWriter {
99 sign: Positive,
100 magnitude: self.repr(),
101 radix: 16,
102 prefix: if f.alternate() { "0x" } else { "" },
103 digit_case: DigitCase::Upper,
104 }
105 .fmt(f)
106 }
107}
108
109impl Display for IBig {
110 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
111 let (sign, magnitude) = self.as_sign_repr();
112 InRadixWriter {
113 sign,
114 magnitude,
115 radix: 10,
116 prefix: "",
117 digit_case: DigitCase::NoLetters,
118 }
119 .fmt(f)
120 }
121}
122
123impl Debug for IBig {
124 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
125 let (sign, magnitude) = self.as_sign_repr();
126 DoubleEnd {
127 sign,
128 magnitude,
129 verbose: f.alternate(),
130 }
131 .fmt(f)
132 }
133}
134
135impl Binary for IBig {
136 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
137 let (sign, magnitude) = self.as_sign_repr();
138 InRadixWriter {
139 sign,
140 magnitude,
141 radix: 2,
142 prefix: if f.alternate() { "0b" } else { "" },
143 digit_case: DigitCase::NoLetters,
144 }
145 .fmt(f)
146 }
147}
148
149impl Octal for IBig {
150 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
151 let (sign, magnitude) = self.as_sign_repr();
152 InRadixWriter {
153 sign,
154 magnitude,
155 radix: 8,
156 prefix: if f.alternate() { "0o" } else { "" },
157 digit_case: DigitCase::NoLetters,
158 }
159 .fmt(f)
160 }
161}
162
163impl LowerHex for IBig {
164 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
165 let (sign, magnitude) = self.as_sign_repr();
166 InRadixWriter {
167 sign,
168 magnitude,
169 radix: 16,
170 prefix: if f.alternate() { "0x" } else { "" },
171 digit_case: DigitCase::Lower,
172 }
173 .fmt(f)
174 }
175}
176
177impl UpperHex for IBig {
178 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
179 let (sign, magnitude) = self.as_sign_repr();
180 InRadixWriter {
181 sign,
182 magnitude,
183 radix: 16,
184 prefix: if f.alternate() { "0x" } else { "" },
185 digit_case: DigitCase::Upper,
186 }
187 .fmt(f)
188 }
189}
190
191impl UBig {
192 #[inline]
206 pub fn in_radix(&self, radix: u32) -> InRadix {
207 if !radix::is_radix_valid(radix) {
208 panic_invalid_radix(radix);
209 }
210
211 InRadix {
212 sign: Positive,
213 magnitude: self.repr(),
214 radix,
215 }
216 }
217}
218
219impl IBig {
220 #[inline]
234 pub fn in_radix(&self, radix: u32) -> InRadix {
235 if !radix::is_radix_valid(radix) {
236 panic_invalid_radix(radix);
237 }
238
239 let (sign, magnitude) = self.as_sign_repr();
240 InRadix {
241 sign,
242 magnitude,
243 radix,
244 }
245 }
246}
247
248pub struct InRadix<'a> {
266 sign: Sign,
267 magnitude: TypedReprRef<'a>,
268 radix: Digit,
269}
270
271impl Display for InRadix<'_> {
272 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
273 let digit_case = if self.radix <= 10 {
274 DigitCase::NoLetters
275 } else if f.alternate() {
276 DigitCase::Upper
277 } else {
278 DigitCase::Lower
279 };
280
281 InRadixWriter {
282 sign: self.sign,
283 magnitude: self.magnitude,
284 radix: self.radix,
285 prefix: "",
286 digit_case,
287 }
288 .fmt(f)
289 }
290}
291
292struct InRadixWriter<'a> {
294 sign: Sign,
295 magnitude: TypedReprRef<'a>,
296 radix: Digit,
297 prefix: &'static str,
298 digit_case: DigitCase,
299}
300
301struct DoubleEnd<'a> {
303 sign: Sign,
304 magnitude: TypedReprRef<'a>,
305 verbose: bool,
306}
307
308impl InRadixWriter<'_> {
309 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
310 if self.radix.is_power_of_two() {
311 self.fmt_power_two(f)
312 } else {
313 self.fmt_non_power_two(f)
314 }
315 }
316
317 fn format_prepared(
319 &self,
320 f: &mut Formatter,
321 prepared: &mut dyn PreparedForFormatting,
322 ) -> fmt::Result {
323 let mut width = prepared.width();
324
325 let sign = if self.sign == Negative {
328 "-"
329 } else if f.sign_plus() {
330 "+"
331 } else {
332 ""
333 };
334 width += sign.len() + self.prefix.len();
336
337 let mut write_digits = |f| {
338 let mut digit_writer = DigitWriter::new(f, self.digit_case);
339 prepared.write(&mut digit_writer)?;
340 digit_writer.flush()
341 };
342
343 match f.width() {
344 None => {
345 f.write_str(sign)?;
346 f.write_str(self.prefix)?;
347 write_digits(f)?
348 }
349 Some(min_width) => {
350 if width >= min_width {
351 f.write_str(sign)?;
352 f.write_str(self.prefix)?;
353 write_digits(f)?;
354 } else if f.sign_aware_zero_pad() {
355 f.write_str(sign)?;
356 f.write_str(self.prefix)?;
357 for _ in 0..min_width - width {
358 f.write_char('0')?;
359 }
360 write_digits(f)?;
361 } else {
362 let left_pad = match f.align() {
363 Some(Alignment::Left) => 0,
364 Some(Alignment::Right) | None => min_width - width,
365 Some(Alignment::Center) => (min_width - width) / 2,
366 };
367 let fill = f.fill();
368 for _ in 0..left_pad {
369 f.write_char(fill)?;
370 }
371 f.write_str(sign)?;
372 f.write_str(self.prefix)?;
373 write_digits(f)?;
374 for _ in left_pad..min_width - width {
375 f.write_char(fill)?;
376 }
377 }
378 }
379 }
380
381 Ok(())
382 }
383}
384
385impl DoubleEnd<'_> {
386 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
387 self.fmt_non_power_two(f)
388 }
389
390 fn format_prepared(
392 &self,
393 f: &mut Formatter,
394 digits: usize,
395 prepared_high: &mut dyn PreparedForFormatting,
396 prepared_low: Option<&mut dyn PreparedForFormatting>,
397 ) -> fmt::Result {
398 let sign = if self.sign == Negative {
399 "-"
400 } else if f.sign_plus() {
401 "+"
402 } else {
403 ""
404 };
405 f.write_str(sign)?;
406
407 let mut digit_writer = DigitWriter::new(f, DigitCase::NoLetters);
408 prepared_high.write(&mut digit_writer)?;
409 digit_writer.flush()?;
410
411 if let Some(low) = prepared_low {
412 f.write_str("..")?;
413
414 let mut digit_writer = DigitWriter::new(f, DigitCase::NoLetters);
415 low.write(&mut digit_writer)?;
416 digit_writer.flush()?;
417 }
418
419 if self.verbose {
420 f.write_str(" (")?;
421 non_power_two::write_usize_decimals(f, digits)?;
422 f.write_str(" digits, ")?;
423 non_power_two::write_usize_decimals(f, self.magnitude.bit_len())?;
424 f.write_str(" bits)")?;
425 }
426
427 Ok(())
428 }
429}
430
431trait PreparedForFormatting {
435 fn width(&self) -> usize;
437
438 fn write(&mut self, digit_writer: &mut DigitWriter) -> fmt::Result;
440}