1use division;
27use fraction::{GenericFraction, Sign};
28use generic::GenericInteger;
29
30use std::fmt;
31
32pub struct Format {
35 flags: u8,
36 fill: char,
37 width: Option<usize>,
38 precision: Option<usize>,
39 align: Option<fmt::Alignment>,
40}
41
42const SIGN_PLUS: u8 = 1;
43const SIGN_MINUS: u8 = 2;
44const ALTERNATE: u8 = 4;
45const SIGAZEPAD: u8 = 8;
46
47impl Format {
48 pub const fn empty() -> Self {
49 Format {
50 fill: ' ',
51 align: None,
52 width: None,
53 precision: None,
54 flags: 0,
55 }
56 }
57
58 pub fn new(formatter: &fmt::Formatter) -> Self {
59 let sign_plus = if formatter.sign_plus() { SIGN_PLUS } else { 0 };
60 let sign_minus = if formatter.sign_minus() {
61 SIGN_MINUS
62 } else {
63 0
64 };
65 let alternate = if formatter.alternate() { ALTERNATE } else { 0 };
66 let sigazepad = if formatter.sign_aware_zero_pad() {
67 SIGAZEPAD
68 } else {
69 0
70 };
71
72 let flags = sign_plus | sign_minus | alternate | sigazepad;
73
74 Format {
75 fill: formatter.fill(),
76 align: formatter.align(),
77 width: formatter.width(),
78 precision: formatter.precision(),
79 flags,
80 }
81 }
82
83 pub const fn fill(&self) -> char {
84 self.fill
85 }
86
87 pub const fn cloned_align(&self) -> Option<fmt::Alignment> {
88 match self.align {
89 Some(ref align) => match *align {
90 fmt::Alignment::Left => Some(fmt::Alignment::Left),
91 fmt::Alignment::Right => Some(fmt::Alignment::Right),
92 fmt::Alignment::Center => Some(fmt::Alignment::Center),
93 },
94 None => None,
95 }
96 }
97
98 pub const fn align(&self) -> &Option<fmt::Alignment> {
99 &self.align
100 }
101
102 pub const fn set_align(mut self, align: Option<fmt::Alignment>) -> Self {
103 self.align = align;
104 self
105 }
106
107 pub const fn width(&self) -> &Option<usize> {
108 &self.width
109 }
110
111 pub const fn set_width(mut self, width: Option<usize>) -> Self {
112 self.width = width;
113 self
114 }
115
116 pub const fn precision(&self) -> &Option<usize> {
117 &self.precision
118 }
119
120 pub const fn set_precision(mut self, precision: Option<usize>) -> Self {
121 self.precision = precision;
122 self
123 }
124
125 pub const fn sign_plus(&self) -> bool {
126 self.flags & SIGN_PLUS > 0
127 }
128
129 pub const fn set_sign_plus(mut self, flag: bool) -> Self {
130 if flag {
131 self.flags |= SIGN_PLUS;
132 } else {
133 self.flags &= !SIGN_PLUS;
134 }
135
136 self
137 }
138
139 pub const fn sign_minus(&self) -> bool {
140 self.flags & SIGN_MINUS > 0
141 }
142
143 pub const fn set_sign_minus(mut self, flag: bool) -> Self {
144 if flag {
145 self.flags |= SIGN_MINUS;
146 } else {
147 self.flags &= !SIGN_MINUS;
148 }
149
150 self
151 }
152
153 pub const fn alternate(&self) -> bool {
154 self.flags & ALTERNATE > 0
155 }
156
157 pub const fn set_alternate(mut self, flag: bool) -> Self {
158 if flag {
159 self.flags |= ALTERNATE;
160 } else {
161 self.flags &= !ALTERNATE;
162 }
163
164 self
165 }
166
167 pub const fn sign_aware_zero_pad(&self) -> bool {
168 self.flags & SIGAZEPAD > 0
169 }
170
171 pub const fn set_sign_aware_zero_pad(mut self, flag: bool) -> Self {
172 if flag {
173 self.flags |= SIGAZEPAD;
174 } else {
175 self.flags &= !SIGAZEPAD;
176 }
177
178 self
179 }
180}
181
182impl Clone for Format {
183 fn clone(&self) -> Self {
184 Format {
185 fill: self.fill(),
186 align: self.cloned_align(),
187 width: *self.width(),
188 precision: *self.precision(),
189 flags: self.flags,
190 }
191 }
192}
193
194pub fn format_sign(sign: Sign, buffer: &mut dyn fmt::Write, format: &Format) -> fmt::Result {
195 if format.sign_plus() || (!format.sign_minus() && sign.is_negative()) {
196 if format.sign_aware_zero_pad() {
197 let format = format.clone().set_sign_aware_zero_pad(false);
198 format_value(
199 buffer,
200 &format,
201 None,
202 |_| 1,
203 |b, _| {
204 b.write_char(sign.into())?;
205 Ok(1)
206 },
207 )
208 } else {
209 format_value(
210 buffer,
211 format,
212 None,
213 |_| 1,
214 |b, _| {
215 b.write_char(sign.into())?;
216 Ok(1)
217 },
218 )
219 }
220 } else {
221 Ok(())
222 }
223}
224
225pub fn format_fraction<T>(
226 fraction: &GenericFraction<T>,
227 buffer: &mut dyn fmt::Write,
228 format: &Format,
229) -> fmt::Result
230where
231 T: Clone + GenericInteger,
232{
233 match *fraction {
234 GenericFraction::NaN => format_value(
235 buffer,
236 format,
237 None,
238 |_| 3,
239 |b, _| {
240 b.write_str("NaN")?;
241 Ok(3)
242 },
243 ),
244 GenericFraction::Infinity(sign) => format_value(
245 buffer,
246 format,
247 Some(sign),
248 |_| 3,
249 |b, _| {
250 b.write_str("inf")?;
251 Ok(3)
252 },
253 ),
254 GenericFraction::Rational(sign, ref ratio) => format_value(
255 buffer,
256 format,
257 Some(sign),
258 |format| {
259 let numer = ratio.numer().clone();
260 let denom = ratio.denom().clone();
261
262 let mut length = 0;
263
264 if let Some(precision) = format.precision() {
265 division::divide_to_callback(
266 numer,
267 denom,
268 *precision,
269 format.alternate(),
270 |_| {
271 length += 1;
272 Ok(true)
273 },
274 )
275 .ok();
276 } else {
277 division::divide_to_callback(numer, T::one(), 0, false, |_| {
278 length += 1;
279 Ok(true)
280 })
281 .ok();
282
283 if !ratio.numer().is_zero() && !ratio.denom().is_one() {
284 length += 1;
285 division::divide_to_callback(denom, T::one(), 0, false, |_| {
286 length += 1;
287 Ok(true)
288 })
289 .ok();
290 }
291 }
292
293 length
294 },
295 |buffer, format| {
296 let numer = ratio.numer().clone();
297 let denom = ratio.denom().clone();
298
299 let mut length = 0;
300
301 if let Some(precision) = format.precision() {
302 let callback = |digit| {
303 length += 1;
304 division::write_digit(buffer, digit)
305 };
306
307 if division::divide_to_callback(
308 numer,
309 denom,
310 *precision,
311 format.alternate(),
312 callback,
313 )
314 .is_err()
315 {
316 return Err(fmt::Error);
317 }
318 } else {
319 let callback = |digit| {
320 length += 1;
321 division::write_digit(buffer, digit)
322 };
323
324 if division::divide_to_callback(numer, T::one(), 0, false, callback).is_err() {
325 return Err(fmt::Error);
326 }
327
328 if !ratio.numer().is_zero() && !ratio.denom().is_one() {
329 length += 1;
330 buffer.write_char('/')?;
331
332 let callback = |digit| {
333 length += 1;
334 division::write_digit(buffer, digit)
335 };
336
337 if division::divide_to_callback(denom, T::one(), 0, false, callback)
338 .is_err()
339 {
340 return Err(fmt::Error);
341 };
342 }
343 }
344
345 Ok(length)
346 },
347 ),
348 }
349}
350
351fn format_value<L, V>(
352 buffer: &mut dyn fmt::Write,
353 format: &Format,
354 sign: Option<Sign>,
355 value_length: L,
356 value: V,
357) -> fmt::Result
358where
359 L: Fn(&Format) -> usize,
360 V: FnOnce(&mut dyn fmt::Write, &Format) -> Result<usize, fmt::Error>,
361{
362 if let Some(width) = format.width() {
363 let width = *width;
364 let sign_len = if let Some(sign) = sign {
365 usize::from(format.sign_plus() || (!format.sign_minus() && sign.is_negative()))
366 } else {
367 0
368 };
369
370 if format.sign_aware_zero_pad() {
371 let value_len = value_length(format);
372
373 if sign_len > 0 {
374 buffer.write_char(sign.unwrap().into())?;
375 }
376
377 if width > sign_len + value_len {
378 for _ in sign_len + value_len..width {
379 buffer.write_char('0')?;
380 }
381 }
382 value(buffer, format)?;
383 } else {
384 match format.align() {
385 Some(fmt::Alignment::Center) => {
386 let value_len = value_length(format) + sign_len;
387 let mut prefix_len = 0;
388 let mut excess = 0;
389
390 if width > value_len {
391 excess = width - value_len;
392 prefix_len = excess / 2;
393 for _ in 0..prefix_len {
394 buffer.write_char(format.fill())?;
395 }
396 };
397
398 if sign_len > 0 {
399 buffer.write_char(sign.unwrap().into())?;
400 }
401 value(buffer, format)?;
402
403 if width > value_len {
404 for _ in 0..excess - prefix_len {
405 buffer.write_char(format.fill())?;
406 }
407 }
408 }
409 None | Some(fmt::Alignment::Right) => {
410 let value_len = value_length(format);
411
412 for _ in sign_len + value_len..width {
413 buffer.write_char(format.fill())?;
414 }
415
416 if sign_len > 0 {
417 buffer.write_char(sign.unwrap().into())?;
418 }
419 value(buffer, format)?;
420 }
421 Some(fmt::Alignment::Left) => {
422 if sign_len > 0 {
423 buffer.write_char(sign.unwrap().into())?;
424 }
425 let value_len = value(buffer, format)?;
426
427 if width > sign_len + value_len {
428 for _ in sign_len + value_len..width {
429 buffer.write_char(format.fill())?;
430 }
431 }
432 }
433 }
434 }
435 } else {
436 if let Some(sign) = sign {
437 if format.sign_plus() || (!format.sign_minus() && sign.is_negative()) {
438 buffer.write_char(sign.into())?;
439 }
440 }
441 value(buffer, format)?;
442 }
443
444 Ok(())
445}
446
447#[cfg(test)]
448mod tests {
449 #[cfg(feature = "with-bigint")]
450 use prelude::{BigFraction, BigUint};
451
452 use super::super::super::{One, Zero};
453 use prelude::GenericFraction;
454
455 type F32 = GenericFraction<i32>;
456 type F64 = GenericFraction<u64>;
457
458 #[test]
459 fn display() {
460 assert_eq!("NaN", format!("{}", F32::nan()));
461 assert_eq!(format!("{}", ::std::f64::NAN), format!("{}", F32::nan()));
462
463 assert_eq!("NaN", format!("{:+}", F32::nan()));
464 assert_eq!(
465 format!("{:+}", ::std::f64::NAN),
466 format!("{:+}", F32::nan())
467 );
468 assert_eq!("==NaN==", format!("{:=^7}", F32::nan()));
469 assert_eq!("=NaN==", format!("{:=^6}", F32::nan()));
470 assert_eq!("NaN====", format!("{:=<7}", F32::nan()));
471 assert_eq!("====NaN", format!("{:=>7}", F32::nan()));
472 assert_eq!("0000NaN", format!("{:=>07}", F32::nan()));
473 assert_eq!("0000NaN", format!("{:07}", F32::nan()));
474 assert_eq!("0000NaN", format!("{:+07}", F32::nan()));
475
476 assert_eq!("inf", format!("{}", F32::infinity()));
477 assert_eq!(
478 format!("{}", ::std::f64::INFINITY),
479 format!("{}", F32::infinity())
480 );
481 assert_eq!("==inf==", format!("{:=^7}", F32::infinity()));
482 assert_eq!("inf====", format!("{:=<7}", F32::infinity()));
483 assert_eq!("====inf", format!("{:=>7}", F32::infinity()));
484 assert_eq!("0000inf", format!("{:=<07}", F32::infinity()));
485 assert_eq!("+000inf", format!("{:=<+07}", F32::infinity()));
486
487 assert_eq!("+inf", format!("{:+}", F32::infinity()));
488 assert_eq!(
489 format!("{:+}", ::std::f64::INFINITY),
490 format!("{:+}", F32::infinity())
491 );
492 assert_eq!("=+inf==", format!("{:=^+7}", F32::infinity()));
493
494 assert_eq!("-inf", format!("{}", F32::neg_infinity()));
495 assert_eq!(
496 format!("{}", ::std::f64::NEG_INFINITY),
497 format!("{}", F32::neg_infinity())
498 );
499 assert_eq!("=-inf==", format!("{:=^7}", F32::neg_infinity()));
500
501 assert_eq!("-inf", format!("{:+}", F32::neg_infinity()));
502 assert_eq!(
503 format!("{:+}", ::std::f64::NEG_INFINITY),
504 format!("{:+}", F32::neg_infinity())
505 );
506 assert_eq!("=-inf==", format!("{:=^+7}", F32::neg_infinity()));
507
508 assert_eq!("0", format!("{}", F32::zero()));
510 assert_eq!(format!("{}", 0.0f64), format!("{}", F32::zero()));
511
512 assert_eq!("+0", format!("{:+}", F32::zero()));
513 assert_eq!(format!("{:+}", 0.0f64), format!("{:+}", F32::zero()));
514
515 assert_eq!("0", format!("{:.2}", F32::zero()));
516 assert_eq!("+0", format!("{:+.2}", F32::zero()));
517 assert_eq!("0", format!("{:-.2}", F32::zero()));
518
519 assert_eq!("0.00", format!("{:#.2}", F32::zero()));
520 assert_eq!("+0.00", format!("{:+#.2}", F32::zero()));
521 assert_eq!("0.00", format!("{:-#.2}", F32::zero()));
522
523 assert_eq!("-0", format!("{}", F32::neg_zero()));
525 assert_eq!("-0", format!("{:+}", F32::neg_zero()));
526 assert_eq!("0", format!("{:-}", F32::neg_zero()));
527
528 assert_eq!("-0", format!("{:.2}", F32::neg_zero()));
529 assert_eq!("-0", format!("{:+.2}", F32::neg_zero()));
530 assert_eq!("0", format!("{:-.2}", F32::neg_zero()));
531
532 assert_eq!("1", format!("{}", F32::one()));
534 assert_eq!("+1", format!("{:+}", F32::one()));
535 assert_eq!("1", format!("{:-}", F32::one()));
536
537 assert_eq!("0001", format!("{:04}", F32::one()));
538 assert_eq!("+001", format!("{:+04}", F32::one()));
539
540 assert_eq!("=1==", format!("{:=^4}", F32::one()));
541 assert_eq!("===1", format!("{:=>4}", F32::one()));
542 assert_eq!("1===", format!("{:=<4}", F32::one()));
543 assert_eq!("=+1=", format!("{:=^+4}", F32::one()));
544
545 assert_eq!("-1", format!("{}", -F32::one()));
547 assert_eq!("-1", format!("{:+}", -F32::one()));
548 assert_eq!("1", format!("{:-}", -F32::one()));
549
550 assert_eq!("=-1=", format!("{:=^4}", -F32::one()));
551 assert_eq!("=1==", format!("{:=^-4}", -F32::one()));
552 assert_eq!("=-1=", format!("{:=^+4}", -F32::one()));
553
554 assert_eq!("00.5", format!("{:04.1}", F32::new(1, 2)));
556 assert_eq!("+0.5", format!("{:+04.1}", F32::new(1, 2)));
557 assert_eq!("00.5", format!("{:-04.1}", F32::new(1, 2)));
558
559 assert_eq!("0.5", format!("{:.16}", F32::new(1, 2)));
560 assert_eq!("+0.5", format!("{:+.16}", F32::new(1, 2)));
561 assert_eq!("+1.75", format!("{:=^+.4}", F32::new(7, 4)));
562 assert_eq!("=+1.75==", format!("{:=^+8.4}", F32::new(7, 4)));
563 assert_eq!(" +1.75", format!("{:+8.4}", F32::new(7, 4)));
564 assert_eq!(" +1.75", format!("{:>+8.4}", F32::new(7, 4)));
565 assert_eq!("+1.75 ", format!("{:<+8.4}", F32::new(7, 4)));
566 assert_eq!("+0001.75", format!("{:<+08.4}", F32::new(7, 4)));
567
568 assert_eq!("-00.5", format!("{:05.2}", -F32::new(1, 2)));
570 assert_eq!("-00.5", format!("{:05.2}", -F32::new(1, 2)));
571 assert_eq!("-00.5", format!("{:+05.2}", -F32::new(1, 2)));
572 assert_eq!("000.5", format!("{:-05.2}", -F32::new(1, 2)));
573
574 assert_eq!("-0.5", format!("{:.16}", -F32::new(1, 2)));
575 assert_eq!("0.5", format!("{:-.16}", -F32::new(1, 2)));
576 assert_eq!("-0.5", format!("{:+.16}", -F32::new(1, 2)));
577
578 assert_eq!("-1.75", format!("{:=^+.4}", -F32::new(7, 4)));
579 assert_eq!("=-1.75==", format!("{:=^+8.4}", -F32::new(7, 4)));
580 assert_eq!(" -1.75", format!("{:+8.4}", -F32::new(7, 4)));
581 assert_eq!(" -1.75", format!("{:>+8.4}", -F32::new(7, 4)));
582 assert_eq!("-1.75 ", format!("{:<+8.4}", -F32::new(7, 4)));
583 assert_eq!("-0001.75", format!("{:<+08.4}", -F32::new(7, 4)));
584
585 assert_eq!("-1.75", format!("{:=^.4}", -F32::new(7, 4)));
586 assert_eq!("=-1.75==", format!("{:=^8.4}", -F32::new(7, 4)));
587 assert_eq!(" -1.75", format!("{:8.4}", -F32::new(7, 4)));
588 assert_eq!(" -1.75", format!("{:>8.4}", -F32::new(7, 4)));
589 assert_eq!("-1.75 ", format!("{:<8.4}", -F32::new(7, 4)));
590 assert_eq!("-0001.75", format!("{:<08.4}", -F32::new(7, 4)));
591
592 assert_eq!("-01.7500", format!("{:<#08.4}", -F32::new(7, 4)));
593
594 assert_eq!("1.75", format!("{:=^-.4}", -F32::new(7, 4)));
595 assert_eq!("==1.75==", format!("{:=^-8.4}", -F32::new(7, 4)));
596 assert_eq!(" 1.75", format!("{:-8.4}", -F32::new(7, 4)));
597 assert_eq!(" 1.75", format!("{:>-8.4}", -F32::new(7, 4)));
598 assert_eq!("1.75 ", format!("{:<-8.4}", -F32::new(7, 4)));
599 assert_eq!("00001.75", format!("{:<-08.4}", -F32::new(7, 4)));
600
601 assert_eq!("7/4", format!("{}", F32::new(7, 4)));
603 assert_eq!("7/4", format!("{:-}", F32::new(7, 4)));
604 assert_eq!("+7/4", format!("{:+}", F32::new(7, 4)));
605
606 assert_eq!("-7/4", format!("{}", -F32::new(7, 4)));
607 assert_eq!("7/4", format!("{:-}", -F32::new(7, 4)));
608 assert_eq!("-7/4", format!("{:+}", -F32::new(7, 4)));
609
610 assert_eq!("07/4", format!("{:04}", F32::new(7, 4)));
611 assert_eq!("-7/4", format!("{:+04}", -F32::new(7, 4)));
612
613 assert_eq!("==7/4==", format!("{:=^7}", F32::new(7, 4)));
614 assert_eq!("=-7/4==", format!("{:=^7}", -F32::new(7, 4)));
615 assert_eq!(" 7/4", format!("{:7}", F32::new(7, 4)));
616 assert_eq!("7/4 ", format!("{:<7}", F32::new(7, 4)));
617 assert_eq!("-7/4 ", format!("{:<7}", -F32::new(7, 4)));
618 assert_eq!("+7/4 ", format!("{:<+7}", F32::new(7, 4)));
619 assert_eq!("+0007/4", format!("{:<+07}", F32::new(7, 4)));
620
621 assert_eq!("NaN", format!("{:.64}", F32::from(::std::f32::NAN)));
623 assert_eq!("inf", format!("{:.64}", F32::from(::std::f32::INFINITY)));
624 assert_eq!(
625 "-inf",
626 format!("{:.64}", F32::from(::std::f32::NEG_INFINITY))
627 );
628
629 assert_eq!("0.75", format!("{:.64}", F32::from(0.75)));
630 assert_eq!("-0.75", format!("{:.64}", F32::from(-0.75)));
631 assert_eq!("0.33", format!("{:.64}", F32::from((33, 100))));
632 assert_eq!(
633 "0.0000000456",
634 format!("{:.64}", F64::new(456u64, 10000000000u64))
635 );
636
637 #[cfg(feature = "with-bigint")]
638 {
639 let fra = BigFraction::new(
640 BigUint::from(42u8),
641 BigUint::from(1000000000000000u64)
642 * BigUint::from(1000000000000000u64)
643 * BigUint::from(1000000000000000u64),
644 );
645
646 assert_eq!(
647 "0.000000000000000000000000000000000000000000042",
648 format!("{:.64}", fra)
649 );
650 }
651 }
652}