1use std::convert::{TryFrom, TryInto};
2use std::ffi::{CStr, CString};
3
4use crate::{
5 parser::{ConversionSpecifier, ConversionType, NumericParam},
6 PrintfError, Result,
7};
8
9pub trait Printf {
14 fn format(&self, spec: &ConversionSpecifier) -> Result<String>;
16 fn as_int(&self) -> Option<i32>;
18}
19
20impl Printf for u64 {
21 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
22 let mut base = 10;
23 let mut digits: Vec<char> = "0123456789".chars().collect();
24 let mut alt_prefix = "";
25 match spec.conversion_type {
26 ConversionType::DecInt => {}
27 ConversionType::HexIntLower => {
28 base = 16;
29 digits = "0123456789abcdef".chars().collect();
30 alt_prefix = "0x";
31 }
32 ConversionType::HexIntUpper => {
33 base = 16;
34 digits = "0123456789ABCDEF".chars().collect();
35 alt_prefix = "0X";
36 }
37 ConversionType::OctInt => {
38 base = 8;
39 digits = "01234567".chars().collect();
40 alt_prefix = "0";
41 }
42 _ => {
43 return Err(PrintfError::WrongType);
44 }
45 }
46 let prefix = if spec.alt_form {
47 alt_prefix.to_owned()
48 } else {
49 String::new()
50 };
51
52 let mut rev_num = String::new();
54 let mut n = *self;
55 while n > 0 {
56 let digit = n % base;
57 n /= base;
58 rev_num.push(digits[digit as usize]);
59 }
60 if rev_num.is_empty() {
61 rev_num.push('0');
62 }
63
64 let width: usize = match spec.width {
66 NumericParam::Literal(w) => w,
67 _ => {
68 return Err(PrintfError::Unknown); }
70 }
71 .try_into()
72 .unwrap_or_default();
73 let formatted = if spec.left_adj {
74 let mut num_str = prefix + &rev_num.chars().rev().collect::<String>();
75 while num_str.len() < width {
76 num_str.push(' ');
77 }
78 num_str
79 } else if spec.zero_pad {
80 while prefix.len() + rev_num.len() < width {
81 rev_num.push('0');
82 }
83 prefix + &rev_num.chars().rev().collect::<String>()
84 } else {
85 let mut num_str = prefix + &rev_num.chars().rev().collect::<String>();
86 while num_str.len() < width {
87 num_str = " ".to_owned() + &num_str;
88 }
89 num_str
90 };
91
92 Ok(formatted)
93 }
94 fn as_int(&self) -> Option<i32> {
95 i32::try_from(*self).ok()
96 }
97}
98
99impl Printf for i64 {
100 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
101 match spec.conversion_type {
102 ConversionType::DecInt => {
104 let negative = *self < 0;
106 let abs_val = self.abs();
107 let sign_prefix = if negative {
108 "-"
109 } else if spec.force_sign {
110 "+"
111 } else if spec.space_sign {
112 " "
113 } else {
114 ""
115 }
116 .to_owned();
117 let mut mod_spec = *spec;
118 mod_spec.width = match spec.width {
119 NumericParam::Literal(w) => NumericParam::Literal(w - sign_prefix.len() as i32),
120 _ => {
121 return Err(PrintfError::Unknown);
122 }
123 };
124
125 let formatted = (abs_val as u64).format(&mod_spec)?;
126 let mut actual_number = &formatted[0..];
128 let mut leading_spaces = &formatted[0..0];
129 if let Some(first_non_space) = formatted.find(|c| c != ' ') {
130 actual_number = &formatted[first_non_space..];
131 leading_spaces = &formatted[0..first_non_space];
132 }
133 Ok(leading_spaces.to_owned() + &sign_prefix + actual_number)
134 }
135 ConversionType::HexIntLower | ConversionType::HexIntUpper | ConversionType::OctInt => {
137 (*self as u64).format(spec)
138 }
139 _ => Err(PrintfError::WrongType),
140 }
141 }
142 fn as_int(&self) -> Option<i32> {
143 i32::try_from(*self).ok()
144 }
145}
146
147impl Printf for i32 {
148 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
149 match spec.conversion_type {
150 ConversionType::DecInt => (*self as i64).format(spec),
152 ConversionType::HexIntLower | ConversionType::HexIntUpper | ConversionType::OctInt => {
154 (*self as u32).format(spec)
155 }
156 _ => Err(PrintfError::WrongType),
157 }
158 }
159 fn as_int(&self) -> Option<i32> {
160 Some(*self)
161 }
162}
163
164impl Printf for u32 {
165 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
166 match spec.conversion_type {
167 ConversionType::Char => {
168 if let Some(c) = char::from_u32(*self) {
169 c.format(spec)
170 } else {
171 Err(PrintfError::WrongType)
172 }
173 }
174 _ => (*self as u64).format(spec),
175 }
176 }
177 fn as_int(&self) -> Option<i32> {
178 i32::try_from(*self).ok()
179 }
180}
181
182impl Printf for i16 {
183 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
184 match spec.conversion_type {
185 ConversionType::DecInt => (*self as i64).format(spec),
187 ConversionType::HexIntLower | ConversionType::HexIntUpper | ConversionType::OctInt => {
189 (*self as u16).format(spec)
190 }
191 _ => Err(PrintfError::WrongType),
192 }
193 }
194 fn as_int(&self) -> Option<i32> {
195 Some(*self as i32)
196 }
197}
198
199impl Printf for u16 {
200 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
201 match spec.conversion_type {
202 ConversionType::Char => {
203 if let Some(Ok(c)) = char::decode_utf16([*self]).next() {
204 c.format(spec)
205 } else {
206 Err(PrintfError::WrongType)
207 }
208 }
209 _ => (*self as u64).format(spec),
210 }
211 }
212 fn as_int(&self) -> Option<i32> {
213 Some(*self as i32)
214 }
215}
216
217impl Printf for i8 {
218 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
219 match spec.conversion_type {
220 ConversionType::DecInt => (*self as i64).format(spec),
222 ConversionType::HexIntLower | ConversionType::HexIntUpper | ConversionType::OctInt => {
224 (*self as u8).format(spec)
225 }
226 ConversionType::Char => (*self as u8).format(spec),
228 _ => Err(PrintfError::WrongType),
229 }
230 }
231 fn as_int(&self) -> Option<i32> {
232 Some(*self as i32)
233 }
234}
235
236impl Printf for u8 {
237 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
238 match spec.conversion_type {
239 ConversionType::Char => {
240 if self.is_ascii() {
241 char::from(*self).format(spec)
242 } else {
243 Err(PrintfError::WrongType)
244 }
245 }
246 _ => (*self as u64).format(spec),
247 }
248 }
249 fn as_int(&self) -> Option<i32> {
250 Some(*self as i32)
251 }
252}
253
254impl Printf for usize {
255 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
256 (*self as u64).format(spec)
257 }
258 fn as_int(&self) -> Option<i32> {
259 i32::try_from(*self).ok()
260 }
261}
262
263impl Printf for isize {
264 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
265 (*self as u64).format(spec)
266 }
267 fn as_int(&self) -> Option<i32> {
268 i32::try_from(*self).ok()
269 }
270}
271
272impl Printf for f64 {
273 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
274 let mut prefix = String::new();
275 let mut number = String::new();
276
277 if self.is_sign_negative() {
279 prefix.push('-');
280 } else if spec.space_sign {
281 prefix.push(' ');
282 } else if spec.force_sign {
283 prefix.push('+');
284 }
285
286 if self.is_finite() {
287 let mut use_scientific = false;
288 let mut exp_symb = 'e';
289 let mut strip_trailing_0s = false;
290 let mut abs = self.abs();
291 let mut exponent = abs.log10().floor() as i32;
292 let mut precision = match spec.precision {
293 NumericParam::Literal(p) => p,
294 _ => {
295 return Err(PrintfError::Unknown);
296 }
297 };
298 if precision <= 0 {
299 precision = 0;
300 }
301 match spec.conversion_type {
302 ConversionType::DecFloatLower | ConversionType::DecFloatUpper => {
303 }
305 ConversionType::SciFloatLower => {
306 use_scientific = true;
307 }
308 ConversionType::SciFloatUpper => {
309 use_scientific = true;
310 exp_symb = 'E';
311 }
312 ConversionType::CompactFloatLower | ConversionType::CompactFloatUpper => {
313 if spec.conversion_type == ConversionType::CompactFloatUpper {
314 exp_symb = 'E'
315 }
316 strip_trailing_0s = true;
317 if precision == 0 {
318 precision = 1;
319 }
320 let rounding_factor = 10.0_f64.powf((precision - 1 - exponent) as f64);
323 let rounded_fixed = (abs * rounding_factor).round();
324 abs = rounded_fixed / rounding_factor;
325 exponent = abs.log10().floor() as i32;
326 if exponent < -4 || exponent >= precision {
327 use_scientific = true;
328 precision -= 1;
329 } else {
330 precision -= 1 + exponent;
332 }
333 }
334 _ => {
335 return Err(PrintfError::WrongType);
336 }
337 }
338
339 if use_scientific {
340 let mut normal = abs / 10.0_f64.powf(exponent as f64);
341
342 if precision > 0 {
343 let mut int_part = normal.trunc();
344 let mut exp_factor = 10.0_f64.powf(precision as f64);
345 let mut tail = ((normal - int_part) * exp_factor).round() as u64;
346 while tail >= exp_factor as u64 {
347 int_part += 1.0;
349 tail -= exp_factor as u64;
350 if int_part >= 10.0 {
351 exponent += 1;
353 exp_factor /= 10.0;
354 normal /= 10.0;
355 int_part = normal.trunc();
356 tail = ((normal - int_part) * exp_factor).round() as u64;
357 }
358 }
359
360 let mut rev_tail_str = String::new();
361 for _ in 0..precision {
362 rev_tail_str.push((b'0' + (tail % 10) as u8) as char);
363 tail /= 10;
364 }
365 number.push_str(&format!("{}", int_part));
366 number.push('.');
367 number.push_str(&rev_tail_str.chars().rev().collect::<String>());
368 if strip_trailing_0s {
369 number = number.trim_end_matches('0').to_owned();
370 }
371 } else {
372 number.push_str(&format!("{}", normal.round()));
373 }
374 number.push(exp_symb);
375 number.push_str(&format!("{:+03}", exponent));
376 } else {
377 if precision > 0 {
378 let mut int_part = abs.trunc();
379 let exp_factor = 10.0_f64.powf(precision as f64);
380 let mut tail = ((abs - int_part) * exp_factor).round() as u64;
381 let mut rev_tail_str = String::new();
382 if tail >= exp_factor as u64 {
383 int_part += 1.0;
385 tail -= exp_factor as u64;
386 }
389 for _ in 0..precision {
390 rev_tail_str.push((b'0' + (tail % 10) as u8) as char);
391 tail /= 10;
392 }
393 number.push_str(&format!("{}", int_part));
394 number.push('.');
395 number.push_str(&rev_tail_str.chars().rev().collect::<String>());
396 if strip_trailing_0s {
397 number = number.trim_end_matches('0').to_owned();
398 }
399 } else {
400 number.push_str(&format!("{}", abs.round()));
401 }
402 }
403 } else {
404 match spec.conversion_type {
406 ConversionType::DecFloatLower
407 | ConversionType::SciFloatLower
408 | ConversionType::CompactFloatLower => {
409 if self.is_infinite() {
410 number.push_str("inf")
411 } else {
412 number.push_str("nan")
413 }
414 }
415 ConversionType::DecFloatUpper
416 | ConversionType::SciFloatUpper
417 | ConversionType::CompactFloatUpper => {
418 if self.is_infinite() {
419 number.push_str("INF")
420 } else {
421 number.push_str("NAN")
422 }
423 }
424 _ => {
425 return Err(PrintfError::WrongType);
426 }
427 }
428 }
429 let width: usize = match spec.width {
431 NumericParam::Literal(w) => w,
432 _ => {
433 return Err(PrintfError::Unknown); }
435 }
436 .try_into()
437 .unwrap_or_default();
438 let formatted = if spec.left_adj {
439 let mut full_num = prefix + &number;
440 while full_num.len() < width {
441 full_num.push(' ');
442 }
443 full_num
444 } else if spec.zero_pad && self.is_finite() {
445 while prefix.len() + number.len() < width {
446 prefix.push('0');
447 }
448 prefix + &number
449 } else {
450 let mut full_num = prefix + &number;
451 while full_num.len() < width {
452 full_num = " ".to_owned() + &full_num;
453 }
454 full_num
455 };
456 Ok(formatted)
457 }
458 fn as_int(&self) -> Option<i32> {
459 None
460 }
461}
462
463impl Printf for f32 {
464 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
465 (*self as f64).format(spec)
466 }
467 fn as_int(&self) -> Option<i32> {
468 None
469 }
470}
471
472impl Printf for &str {
473 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
474 if spec.conversion_type == ConversionType::String {
475 let mut s = String::new();
476
477 let precision: usize = match spec.precision {
479 NumericParam::Literal(p) => p,
480 _ => {
481 return Err(PrintfError::Unknown); }
483 }
484 .try_into()
485 .unwrap_or_default();
486 let content_len = {
487 let mut content_len = precision.min(self.len());
488 while !self.is_char_boundary(content_len) {
489 content_len -= 1;
490 }
491 content_len
492 };
493 let content = &self[..content_len];
494
495 let width: usize = match spec.width {
497 NumericParam::Literal(w) => w,
498 _ => {
499 return Err(PrintfError::Unknown); }
501 }
502 .try_into()
503 .unwrap_or_default();
504 if spec.left_adj {
505 s.push_str(content);
506 while s.len() < width {
507 s.push(' ');
508 }
509 } else {
510 while s.len() + content.len() < width {
511 s.push(' ');
512 }
513 s.push_str(content);
514 }
515
516 Ok(s)
517 } else {
518 Err(PrintfError::WrongType)
519 }
520 }
521 fn as_int(&self) -> Option<i32> {
522 None
523 }
524}
525
526impl Printf for char {
527 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
528 if spec.conversion_type == ConversionType::Char {
529 let mut s = String::new();
530
531 let width: usize = match spec.width {
532 NumericParam::Literal(w) => w,
533 _ => {
534 return Err(PrintfError::Unknown); }
536 }
537 .try_into()
538 .unwrap_or_default();
539
540 if spec.left_adj {
541 s.push(*self);
542 while s.len() < width {
543 s.push(' ');
544 }
545 } else {
546 while s.len() + self.len_utf8() < width {
547 s.push(' ');
548 }
549 s.push(*self);
550 }
551 Ok(s)
552 } else {
553 Err(PrintfError::WrongType)
554 }
555 }
556 fn as_int(&self) -> Option<i32> {
557 None
558 }
559}
560
561impl Printf for String {
562 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
563 (self as &str).format(spec)
564 }
565 fn as_int(&self) -> Option<i32> {
566 None
567 }
568}
569
570impl Printf for &CStr {
571 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
572 if let Ok(s) = self.to_str() {
573 s.format(spec)
574 } else {
575 Err(PrintfError::WrongType)
576 }
577 }
578 fn as_int(&self) -> Option<i32> {
579 None
580 }
581}
582
583impl Printf for CString {
584 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
585 self.as_c_str().format(spec)
586 }
587 fn as_int(&self) -> Option<i32> {
588 None
589 }
590}
591
592impl<T> Printf for *const T {
593 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
594 (*self as usize).format(spec)
595 }
596 fn as_int(&self) -> Option<i32> {
597 None
598 }
599}
600
601impl<T> Printf for *mut T {
602 fn format(&self, spec: &ConversionSpecifier) -> Result<String> {
603 (*self as usize).format(spec)
604 }
605 fn as_int(&self) -> Option<i32> {
606 None
607 }
608}