1use core::fmt;
4use core::iter;
5use core::mem::take;
6use core::num::NonZeroUsize;
7use core::str;
8
9#[cfg(feature = "musli")]
10use musli_core::{Decode, Encode};
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14use crate as rune;
15use crate::alloc::clone::TryClone;
16use crate::alloc::fmt::TryWrite;
17use crate::alloc::{self, String};
18use crate::runtime::{Formatter, Inline, ProtocolCaller, Repr, Value, VmError, VmErrorKind};
19use crate::{Any, TypeHash};
20
21#[derive(Debug, Clone, Copy)]
23#[non_exhaustive]
24pub struct TypeFromStrError;
25
26impl fmt::Display for TypeFromStrError {
27 #[inline]
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 write!(f, "Bad type string")
30 }
31}
32
33#[derive(Debug, Clone, Copy)]
35pub struct AlignmentFromStrError;
36
37impl fmt::Display for AlignmentFromStrError {
38 #[inline]
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 write!(f, "Bad alignment string")
41 }
42}
43
44#[derive(Any, Debug, Clone, TryClone)]
46#[rune(item = ::std::fmt)]
47pub struct Format {
48 #[rune(dismantle)]
50 pub(crate) value: Value,
51 #[try_clone(copy)]
53 pub(crate) spec: FormatSpec,
54}
55
56#[derive(Debug, Clone, Copy, TryClone)]
58#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
59#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core))]
60#[try_clone(copy)]
61#[non_exhaustive]
62pub struct FormatSpec {
63 pub(crate) flags: Flags,
65 pub(crate) fill: char,
67 pub(crate) align: Alignment,
69 pub(crate) width: Option<NonZeroUsize>,
71 pub(crate) precision: Option<usize>,
73 pub(crate) format_type: Type,
75}
76
77#[derive(Clone, Copy)]
79struct Padding {
80 align: Alignment,
81 fill: char,
82 sign: Option<char>,
85 zero: bool,
91}
92
93impl FormatSpec {
94 pub fn new(
96 flags: Flags,
97 fill: char,
98 align: Alignment,
99 width: Option<NonZeroUsize>,
100 precision: Option<usize>,
101 format_type: Type,
102 ) -> Self {
103 Self {
104 flags,
105 fill,
106 align,
107 width,
108 precision,
109 format_type,
110 }
111 }
112
113 fn padding(&self) -> Padding {
115 Padding {
116 align: self.align,
117 fill: self.fill,
118 sign: None,
119 zero: false,
120 }
121 }
122
123 fn zero_padding(&self, sign: Option<char>) -> Padding {
125 Padding {
126 align: Alignment::Right,
127 fill: '0',
128 sign,
129 zero: true,
130 }
131 }
132
133 fn float_traits(&self, n: f64) -> (f64, Padding) {
135 if self.flags.test(Flag::SignAwareZeroPad) {
136 if n.is_sign_negative() {
137 (-n, self.zero_padding(Some('-')))
138 } else {
139 (n, self.zero_padding(self.zero_pad_sign()))
140 }
141 } else if self.flags.test(Flag::SignPlus) && n.is_sign_positive() {
142 (
143 n,
144 Padding {
145 sign: Some('+'),
146 ..self.padding()
147 },
148 )
149 } else {
150 (n, self.padding())
151 }
152 }
153
154 fn zero_pad_sign(&self) -> Option<char> {
160 if self.flags.test(Flag::SignPlus) {
161 return Some('+');
162 }
163
164 None
165 }
166
167 fn uint_traits(&self, n: u64) -> (u64, Padding) {
169 if self.flags.test(Flag::SignAwareZeroPad) {
170 (n, self.zero_padding(self.zero_pad_sign()))
171 } else if self.flags.test(Flag::SignPlus) {
172 (
173 n,
174 Padding {
175 sign: Some('+'),
176 ..self.padding()
177 },
178 )
179 } else {
180 (n, self.padding())
181 }
182 }
183
184 fn int_traits(&self, n: i64) -> (u64, Padding) {
190 let magnitude = n.unsigned_abs();
191
192 if self.flags.test(Flag::SignAwareZeroPad) {
193 if n < 0 {
194 (magnitude, self.zero_padding(Some('-')))
195 } else {
196 (magnitude, self.zero_padding(self.zero_pad_sign()))
197 }
198 } else if n < 0 {
199 (
200 magnitude,
201 Padding {
202 sign: Some('-'),
203 ..self.padding()
204 },
205 )
206 } else if self.flags.test(Flag::SignPlus) {
207 (
208 magnitude,
209 Padding {
210 sign: Some('+'),
211 ..self.padding()
212 },
213 )
214 } else {
215 (magnitude, self.padding())
216 }
217 }
218
219 fn format_unsigned(&self, buf: &mut String, n: u64) -> alloc::Result<()> {
221 let mut buffer = itoa::Buffer::new();
222 buf.try_push_str(buffer.format(n))?;
223 Ok(())
224 }
225
226 fn format_str(&self, buf: &mut String, s: &str) -> alloc::Result<()> {
228 let Some(precision) = self.precision else {
229 buf.try_push_str(s)?;
230 return Ok(());
231 };
232
233 for c in s.chars().take(precision) {
234 buf.try_push(c)?;
235 }
236
237 Ok(())
238 }
239
240 fn format_float(&self, buf: &mut String, n: f64) -> alloc::Result<()> {
242 if let Some(precision) = self.precision {
243 write!(buf, "{:.*}", precision, n)?;
244 } else {
245 let mut buffer = ryu::Buffer::new();
246 buf.try_push_str(buffer.format(n))?;
247 }
248
249 Ok(())
250 }
251
252 fn format_fill(&self, f: &mut Formatter, padding: Padding) -> alloc::Result<()> {
254 self.format_fill_with(f, padding, "")
255 }
256
257 fn format_fill_with(
265 &self,
266 f: &mut Formatter,
267 padding: Padding,
268 prefix: &str,
269 ) -> alloc::Result<()> {
270 let Padding {
271 align,
272 fill,
273 sign,
274 zero,
275 } = padding;
276
277 let (f, buf) = f.parts_mut();
278
279 let mut w = self.width.map(|n| n.get()).unwrap_or_default();
280
281 w = w
282 .saturating_sub(buf.chars().count())
283 .saturating_sub(prefix.chars().count())
284 .saturating_sub(sign.map(|_| 1).unwrap_or_default());
285
286 let head = |f: &mut dyn TryWrite| {
287 if let Some(sign) = sign {
288 f.try_write_char(sign)?;
289 }
290
291 f.try_write_str(prefix)
292 };
293
294 if w == 0 {
295 head(f)?;
296 f.try_write_str(buf)?;
297 return Ok(());
298 }
299
300 if zero {
301 head(f)?;
302
303 for c in iter::repeat_n(fill, w) {
304 f.try_write_char(c)?;
305 }
306
307 f.try_write_str(buf)?;
308 return Ok(());
309 }
310
311 let mut filler = iter::repeat_n(fill, w);
312
313 match align {
314 Alignment::Left => {
315 head(f)?;
316 f.try_write_str(buf)?;
317
318 for c in filler {
319 f.try_write_char(c)?;
320 }
321 }
322 Alignment::Center => {
323 for c in (&mut filler).take(w / 2) {
324 f.try_write_char(c)?;
325 }
326
327 head(f)?;
328 f.try_write_str(buf)?;
329
330 for c in filler {
331 f.try_write_char(c)?;
332 }
333 }
334 Alignment::Right => {
335 for c in filler {
336 f.try_write_char(c)?;
337 }
338
339 head(f)?;
340 f.try_write_str(buf)?;
341 }
342 }
343
344 Ok(())
345 }
346
347 fn format_display(
348 &self,
349 value: &Value,
350 f: &mut Formatter,
351 caller: &mut dyn ProtocolCaller,
352 ) -> Result<(), VmError> {
353 'fallback: {
354 match value.as_ref() {
355 Repr::Inline(value) => match value {
356 Inline::Char(c) => {
357 f.buf_mut().try_push(*c)?;
358 self.format_fill(f, self.padding())?;
359 }
360 Inline::Signed(n) => {
361 let (n, padding) = self.int_traits(*n);
362 self.format_unsigned(f.buf_mut(), n)?;
363 self.format_fill(f, padding)?;
364 }
365 Inline::Unsigned(n) => {
366 let (n, padding) = self.uint_traits(*n);
367 self.format_unsigned(f.buf_mut(), n)?;
368 self.format_fill(f, padding)?;
369 }
370 Inline::Bool(b) => {
371 f.buf_mut()
372 .try_push_str(if *b { "true" } else { "false" })?;
373 self.format_fill(f, self.padding())?;
374 }
375 Inline::Float(n) => {
376 let (n, padding) = self.float_traits(*n);
377 self.format_float(f.buf_mut(), n)?;
378 self.format_fill(f, padding)?;
379 }
380 _ => {
381 break 'fallback;
382 }
383 },
384 Repr::Dynamic(..) => {
385 break 'fallback;
386 }
387 Repr::Any(value) => match value.type_hash() {
388 String::HASH => {
389 let s = value.borrow_ref::<String>()?;
390 self.format_str(f.buf_mut(), &s)?;
391 self.format_fill(f, self.padding())?;
392 }
393 _ => {
394 break 'fallback;
395 }
396 },
397 }
398
399 return Ok(());
400 }
401
402 value.display_fmt_with(f, caller)
403 }
404
405 fn format_debug(
406 &self,
407 value: &Value,
408 f: &mut Formatter,
409 caller: &mut dyn ProtocolCaller,
410 ) -> Result<(), VmError> {
411 'fallback: {
412 match value.as_ref() {
413 Repr::Inline(value) => match value {
414 Inline::Signed(n) => {
415 let (n, padding) = self.int_traits(*n);
416 self.format_unsigned(f.buf_mut(), n)?;
417 self.format_fill(f, padding)?;
418 }
419 Inline::Unsigned(n) => {
420 let (n, padding) = self.uint_traits(*n);
421 self.format_unsigned(f.buf_mut(), n)?;
422 self.format_fill(f, padding)?;
423 }
424 Inline::Bool(b) => {
425 f.buf_mut()
426 .try_push_str(if *b { "true" } else { "false" })?;
427 self.format_fill(f, self.padding())?;
428 }
429 Inline::Float(n) => {
430 let (n, padding) = self.float_traits(*n);
431 self.format_float(f.buf_mut(), n)?;
432 self.format_fill(f, padding)?;
433 }
434 _ => {
435 break 'fallback;
436 }
437 },
438 Repr::Dynamic(..) => {
439 break 'fallback;
440 }
441 Repr::Any(value) => match value.type_hash() {
442 String::HASH => {
443 let s = value.borrow_ref::<String>()?;
444 write!(f, "{s:?}")?;
445 }
446 _ => {
447 break 'fallback;
448 }
449 },
450 }
451
452 return Ok(());
453 };
454
455 value.debug_fmt_with(f, caller)
456 }
457
458 fn radix_prefix(&self, prefix: &'static str) -> &'static str {
461 if self.flags.test(Flag::Alternate) {
462 prefix
463 } else {
464 ""
465 }
466 }
467
468 fn format_upper_hex(&self, value: &Value, f: &mut Formatter) -> Result<(), VmError> {
469 match value.as_inline() {
470 Some(Inline::Signed(n)) => {
471 let (n, padding) = self.uint_traits(*n as u64);
472 write!(f.buf_mut(), "{n:X}")?;
473 self.format_fill_with(f, padding, self.radix_prefix("0x"))?;
474 }
475 Some(Inline::Unsigned(n)) => {
476 let (n, padding) = self.uint_traits(*n);
477 write!(f.buf_mut(), "{n:X}")?;
478 self.format_fill_with(f, padding, self.radix_prefix("0x"))?;
479 }
480 _ => {
481 return Err(VmError::new(VmErrorKind::IllegalFormat));
482 }
483 }
484
485 Ok(())
486 }
487
488 fn format_lower_hex(&self, value: &Value, f: &mut Formatter) -> Result<(), VmError> {
489 match value.as_inline() {
490 Some(Inline::Signed(n)) => {
491 let (n, padding) = self.uint_traits(*n as u64);
492 write!(f.buf_mut(), "{n:x}")?;
493 self.format_fill_with(f, padding, self.radix_prefix("0x"))?;
494 }
495 Some(Inline::Unsigned(n)) => {
496 let (n, padding) = self.uint_traits(*n);
497 write!(f.buf_mut(), "{n:x}")?;
498 self.format_fill_with(f, padding, self.radix_prefix("0x"))?;
499 }
500 _ => {
501 return Err(VmError::new(VmErrorKind::IllegalFormat));
502 }
503 }
504
505 Ok(())
506 }
507
508 fn format_binary(&self, value: &Value, f: &mut Formatter) -> Result<(), VmError> {
509 match value.as_inline() {
510 Some(Inline::Signed(n)) => {
511 let (n, padding) = self.uint_traits(*n as u64);
512 write!(f.buf_mut(), "{n:b}")?;
513 self.format_fill_with(f, padding, self.radix_prefix("0b"))?;
514 }
515 Some(Inline::Unsigned(n)) => {
516 let (n, padding) = self.uint_traits(*n);
517 write!(f.buf_mut(), "{n:b}")?;
518 self.format_fill_with(f, padding, self.radix_prefix("0b"))?;
519 }
520 _ => {
521 return Err(VmError::new(VmErrorKind::IllegalFormat));
522 }
523 }
524
525 Ok(())
526 }
527
528 fn format_pointer(&self, value: &Value, f: &mut Formatter) -> Result<(), VmError> {
529 match value.as_inline() {
530 Some(Inline::Signed(n)) => {
531 let (n, padding) = self.uint_traits(*n as u64);
532 write!(f.buf_mut(), "{:p}", n as *const ())?;
533 self.format_fill(f, padding)?;
534 }
535 _ => {
536 return Err(VmError::new(VmErrorKind::IllegalFormat));
537 }
538 }
539
540 Ok(())
541 }
542
543 pub(crate) fn format(
546 &self,
547 value: &Value,
548 f: &mut Formatter,
549 caller: &mut dyn ProtocolCaller,
550 ) -> Result<(), VmError> {
551 f.buf_mut().clear();
552
553 match self.format_type {
554 Type::Display => self.format_display(value, f, caller)?,
555 Type::Debug => self.format_debug(value, f, caller)?,
556 Type::UpperHex => self.format_upper_hex(value, f)?,
557 Type::LowerHex => self.format_lower_hex(value, f)?,
558 Type::Binary => self.format_binary(value, f)?,
559 Type::Pointer => self.format_pointer(value, f)?,
560 }
561
562 Ok(())
563 }
564}
565
566impl fmt::Display for FormatSpec {
567 #[inline]
568 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
569 write!(
570 f,
571 "format(fill = {fill:?}, align = {align}, flags = {flags:?}, width = {width}, precision = {precision}, format_type = {format_type})",
572 fill = self.fill,
573 align = self.align,
574 flags = self.flags,
575 width = OptionDebug(self.width.as_ref()),
576 precision = OptionDebug(self.precision.as_ref()),
577 format_type = self.format_type
578 )
579 }
580}
581
582struct OptionDebug<'a, T>(Option<&'a T>);
583
584impl<T> fmt::Display for OptionDebug<'_, T>
585where
586 T: fmt::Display,
587{
588 #[inline]
589 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590 match self.0 {
591 Some(value) => write!(f, "{value}"),
592 None => write!(f, "?"),
593 }
594 }
595}
596
597#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
599#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
600#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core))]
601#[non_exhaustive]
602pub enum Type {
603 #[default]
605 Display,
606 Debug,
608 UpperHex,
610 LowerHex,
612 Binary,
614 Pointer,
616}
617
618impl str::FromStr for Type {
619 type Err = TypeFromStrError;
620
621 #[inline]
622 fn from_str(s: &str) -> Result<Self, Self::Err> {
623 match s {
624 "display" => Ok(Self::Display),
625 "debug" => Ok(Self::Debug),
626 "upper_hex" => Ok(Self::UpperHex),
627 "lower_hex" => Ok(Self::LowerHex),
628 "binary" => Ok(Self::Binary),
629 "pointer" => Ok(Self::Pointer),
630 _ => Err(TypeFromStrError),
631 }
632 }
633}
634
635impl fmt::Display for Type {
636 #[inline]
637 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
638 match self {
639 Self::Display => {
640 write!(f, "display")?;
641 }
642 Self::Debug => {
643 write!(f, "debug")?;
644 }
645 Self::UpperHex => {
646 write!(f, "upper_hex")?;
647 }
648 Self::LowerHex => {
649 write!(f, "lower_hex")?;
650 }
651 Self::Binary => {
652 write!(f, "binary")?;
653 }
654 Self::Pointer => {
655 write!(f, "pointer")?;
656 }
657 }
658
659 Ok(())
660 }
661}
662
663#[derive(Default, Debug, Clone, Copy, TryClone, PartialEq, Eq)]
665#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
666#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core))]
667#[try_clone(copy)]
668#[non_exhaustive]
669pub enum Alignment {
670 #[default]
672 Left,
673 Center,
675 Right,
677}
678
679impl str::FromStr for Alignment {
680 type Err = AlignmentFromStrError;
681
682 #[inline]
683 fn from_str(s: &str) -> Result<Self, Self::Err> {
684 match s {
685 "left" => Ok(Self::Left),
686 "center" => Ok(Self::Center),
687 "right" => Ok(Self::Right),
688 _ => Err(AlignmentFromStrError),
689 }
690 }
691}
692
693impl fmt::Display for Alignment {
694 #[inline]
695 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
696 match self {
697 Self::Left => {
698 write!(f, "left")?;
699 }
700 Self::Center => {
701 write!(f, "center")?;
702 }
703 Self::Right => {
704 write!(f, "right")?;
705 }
706 }
707
708 Ok(())
709 }
710}
711
712#[derive(Clone, Copy)]
714#[repr(u32)]
715#[non_exhaustive]
716pub enum Flag {
717 SignPlus,
719 SignMinus,
721 Alternate,
723 SignAwareZeroPad,
725}
726
727#[derive(Clone, Copy, TryClone, Default, PartialEq, Eq)]
729#[repr(transparent)]
730#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
731#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(crate = musli_core, transparent))]
732#[try_clone(copy)]
733pub struct Flags(u32);
734
735impl Flags {
736 #[inline]
738 pub fn is_empty(self) -> bool {
739 self.0 == 0
740 }
741
742 #[inline]
745 pub fn into_u32(self) -> u32 {
746 self.0
747 }
748
749 #[inline]
751 pub fn set(&mut self, flag: Flag) {
752 self.0 |= &(1 << flag as u32);
753 }
754
755 #[inline]
757 pub fn test(&self, flag: Flag) -> bool {
758 (self.0 & (1 << flag as u32)) != 0
759 }
760}
761
762impl From<u32> for Flags {
763 fn from(flags: u32) -> Self {
764 Self(flags)
765 }
766}
767
768impl fmt::Debug for Flags {
769 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
770 macro_rules! fmt_flag {
771 ($flag:ident, $o:ident, $spec:literal) => {
772 if self.test(Flag::$flag) {
773 if !take(&mut $o) {
774 write!(f, ", ")?;
775 }
776
777 write!(f, $spec)?;
778 }
779 };
780 }
781
782 let mut o = true;
783 write!(f, "Flags{{")?;
784 fmt_flag!(SignPlus, o, "+");
785 fmt_flag!(SignMinus, o, "-");
786 fmt_flag!(Alternate, o, "#");
787 fmt_flag!(SignAwareZeroPad, o, "0");
788 write!(f, "}}")?;
789 Ok(())
790 }
791}