1use core::fmt;
4use core::iter;
5use core::mem::take;
6use core::num::NonZeroUsize;
7use core::str;
8
9#[cfg(feature = "musli")]
10use musli::{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 pub(crate) value: Value,
50 #[try_clone(copy)]
52 pub(crate) spec: FormatSpec,
53}
54
55#[derive(Debug, Clone, Copy, TryClone)]
57#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
58#[cfg_attr(feature = "musli", derive(Decode, Encode))]
59#[try_clone(copy)]
60#[non_exhaustive]
61pub struct FormatSpec {
62 pub(crate) flags: Flags,
64 pub(crate) fill: char,
66 pub(crate) align: Alignment,
68 pub(crate) width: Option<NonZeroUsize>,
70 pub(crate) precision: Option<NonZeroUsize>,
72 pub(crate) format_type: Type,
74}
75
76impl FormatSpec {
77 pub fn new(
79 flags: Flags,
80 fill: char,
81 align: Alignment,
82 width: Option<NonZeroUsize>,
83 precision: Option<NonZeroUsize>,
84 format_type: Type,
85 ) -> Self {
86 Self {
87 flags,
88 fill,
89 align,
90 width,
91 precision,
92 format_type,
93 }
94 }
95
96 fn float_traits(&self, n: f64) -> (f64, Alignment, char, Option<char>) {
98 if self.flags.test(Flag::SignAwareZeroPad) {
99 if n.is_sign_negative() {
100 (-n, Alignment::Right, '0', Some('-'))
101 } else {
102 (n, Alignment::Right, '0', None)
103 }
104 } else if self.flags.test(Flag::SignPlus) && n.is_sign_positive() {
105 (n, self.align, self.fill, Some('+'))
106 } else {
107 (n, self.align, self.fill, None)
108 }
109 }
110
111 fn int_traits(&self, n: i64) -> (i64, Alignment, char, Option<char>) {
113 if self.flags.test(Flag::SignAwareZeroPad) {
114 if n < 0 {
115 (-n, Alignment::Right, '0', Some('-'))
116 } else {
117 (n, Alignment::Right, '0', None)
118 }
119 } else if self.flags.test(Flag::SignPlus) && n >= 0 {
120 (n, self.align, self.fill, Some('+'))
121 } else {
122 (n, self.align, self.fill, None)
123 }
124 }
125
126 fn format_number(&self, buf: &mut String, n: i64) -> alloc::Result<()> {
128 let mut buffer = itoa::Buffer::new();
129 buf.try_push_str(buffer.format(n))?;
130 Ok(())
131 }
132
133 fn format_float(&self, buf: &mut String, n: f64) -> alloc::Result<()> {
135 if let Some(precision) = self.precision {
136 write!(buf, "{:.*}", precision.get(), n)?;
137 } else {
138 let mut buffer = ryu::Buffer::new();
139 buf.try_push_str(buffer.format(n))?;
140 }
141
142 Ok(())
143 }
144
145 fn format_fill(
147 &self,
148 f: &mut Formatter,
149 align: Alignment,
150 fill: char,
151 sign: Option<char>,
152 ) -> alloc::Result<()> {
153 let (f, buf) = f.parts_mut();
154
155 if let Some(sign) = sign {
156 f.try_write_char(sign)?;
157 }
158
159 let mut w = self.width.map(|n| n.get()).unwrap_or_default();
160
161 if w == 0 {
162 f.try_write_str(buf)?;
163 return Ok(());
164 }
165
166 w = w
167 .saturating_sub(buf.chars().count())
168 .saturating_sub(sign.map(|_| 1).unwrap_or_default());
169
170 if w == 0 {
171 f.try_write_str(buf)?;
172 return Ok(());
173 }
174
175 let mut filler = iter::repeat_n(fill, w);
176
177 match align {
178 Alignment::Left => {
179 f.try_write_str(buf)?;
180
181 for c in filler {
182 f.try_write_char(c)?;
183 }
184 }
185 Alignment::Center => {
186 for c in (&mut filler).take(w / 2) {
187 f.try_write_char(c)?;
188 }
189
190 f.try_write_str(buf)?;
191
192 for c in filler {
193 f.try_write_char(c)?;
194 }
195 }
196 Alignment::Right => {
197 for c in filler {
198 f.try_write_char(c)?;
199 }
200
201 f.try_write_str(buf)?;
202 }
203 }
204
205 Ok(())
206 }
207
208 fn format_display(
209 &self,
210 value: &Value,
211 f: &mut Formatter,
212 caller: &mut dyn ProtocolCaller,
213 ) -> Result<(), VmError> {
214 'fallback: {
215 match value.as_ref() {
216 Repr::Inline(value) => match value {
217 Inline::Char(c) => {
218 f.buf_mut().try_push(*c)?;
219 self.format_fill(f, self.align, self.fill, None)?;
220 }
221 Inline::Signed(n) => {
222 let (n, align, fill, sign) = self.int_traits(*n);
223 self.format_number(f.buf_mut(), n)?;
224 self.format_fill(f, align, fill, sign)?;
225 }
226 Inline::Float(n) => {
227 let (n, align, fill, sign) = self.float_traits(*n);
228 self.format_float(f.buf_mut(), n)?;
229 self.format_fill(f, align, fill, sign)?;
230 }
231 _ => {
232 break 'fallback;
233 }
234 },
235 Repr::Dynamic(..) => {
236 break 'fallback;
237 }
238 Repr::Any(value) => match value.type_hash() {
239 String::HASH => {
240 let s = value.borrow_ref::<String>()?;
241 f.buf_mut().try_push_str(&s)?;
242 self.format_fill(f, self.align, self.fill, None)?;
243 }
244 _ => {
245 break 'fallback;
246 }
247 },
248 }
249
250 return Ok(());
251 }
252
253 value.display_fmt_with(f, caller)
254 }
255
256 fn format_debug(
257 &self,
258 value: &Value,
259 f: &mut Formatter,
260 caller: &mut dyn ProtocolCaller,
261 ) -> Result<(), VmError> {
262 'fallback: {
263 match value.as_ref() {
264 Repr::Inline(value) => match value {
265 Inline::Signed(n) => {
266 let (n, align, fill, sign) = self.int_traits(*n);
267 self.format_number(f.buf_mut(), n)?;
268 self.format_fill(f, align, fill, sign)?;
269 }
270 Inline::Float(n) => {
271 let (n, align, fill, sign) = self.float_traits(*n);
272 self.format_float(f.buf_mut(), n)?;
273 self.format_fill(f, align, fill, sign)?;
274 }
275 _ => {
276 break 'fallback;
277 }
278 },
279 Repr::Dynamic(..) => {
280 break 'fallback;
281 }
282 Repr::Any(value) => match value.type_hash() {
283 String::HASH => {
284 let s = value.borrow_ref::<String>()?;
285 write!(f, "{s:?}")?;
286 }
287 _ => {
288 break 'fallback;
289 }
290 },
291 }
292
293 return Ok(());
294 };
295
296 value.debug_fmt_with(f, caller)
297 }
298
299 fn format_upper_hex(&self, value: &Value, f: &mut Formatter) -> Result<(), VmError> {
300 match value.as_inline() {
301 Some(Inline::Signed(n)) => {
302 let (n, align, fill, sign) = self.int_traits(*n);
303 write!(f.buf_mut(), "{n:X}")?;
304 self.format_fill(f, align, fill, sign)?;
305 }
306 _ => {
307 return Err(VmError::new(VmErrorKind::IllegalFormat));
308 }
309 }
310
311 Ok(())
312 }
313
314 fn format_lower_hex(&self, value: &Value, f: &mut Formatter) -> Result<(), VmError> {
315 match value.as_inline() {
316 Some(Inline::Signed(n)) => {
317 let (n, align, fill, sign) = self.int_traits(*n);
318 write!(f.buf_mut(), "{n:x}")?;
319 self.format_fill(f, align, fill, sign)?;
320 }
321 _ => {
322 return Err(VmError::new(VmErrorKind::IllegalFormat));
323 }
324 }
325
326 Ok(())
327 }
328
329 fn format_binary(&self, value: &Value, f: &mut Formatter) -> Result<(), VmError> {
330 match value.as_inline() {
331 Some(Inline::Signed(n)) => {
332 let (n, align, fill, sign) = self.int_traits(*n);
333 write!(f.buf_mut(), "{n:b}")?;
334 self.format_fill(f, align, fill, sign)?;
335 }
336 _ => {
337 return Err(VmError::new(VmErrorKind::IllegalFormat));
338 }
339 }
340
341 Ok(())
342 }
343
344 fn format_pointer(&self, value: &Value, f: &mut Formatter) -> Result<(), VmError> {
345 match value.as_inline() {
346 Some(Inline::Signed(n)) => {
347 let (n, align, fill, sign) = self.int_traits(*n);
348 write!(f.buf_mut(), "{:p}", n as *const ())?;
349 self.format_fill(f, align, fill, sign)?;
350 }
351 _ => {
352 return Err(VmError::new(VmErrorKind::IllegalFormat));
353 }
354 }
355
356 Ok(())
357 }
358
359 pub(crate) fn format(
362 &self,
363 value: &Value,
364 f: &mut Formatter,
365 caller: &mut dyn ProtocolCaller,
366 ) -> Result<(), VmError> {
367 f.buf_mut().clear();
368
369 match self.format_type {
370 Type::Display => self.format_display(value, f, caller)?,
371 Type::Debug => self.format_debug(value, f, caller)?,
372 Type::UpperHex => self.format_upper_hex(value, f)?,
373 Type::LowerHex => self.format_lower_hex(value, f)?,
374 Type::Binary => self.format_binary(value, f)?,
375 Type::Pointer => self.format_pointer(value, f)?,
376 }
377
378 Ok(())
379 }
380}
381
382impl fmt::Display for FormatSpec {
383 #[inline]
384 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
385 write!(
386 f,
387 "format(fill = {fill:?}, align = {align}, flags = {flags:?}, width = {width}, precision = {precision}, format_type = {format_type})",
388 fill = self.fill,
389 align = self.align,
390 flags = self.flags,
391 width = OptionDebug(self.width.as_ref()),
392 precision = OptionDebug(self.precision.as_ref()),
393 format_type = self.format_type
394 )
395 }
396}
397
398struct OptionDebug<'a, T>(Option<&'a T>);
399
400impl<T> fmt::Display for OptionDebug<'_, T>
401where
402 T: fmt::Display,
403{
404 #[inline]
405 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406 match self.0 {
407 Some(value) => write!(f, "{value}"),
408 None => write!(f, "?"),
409 }
410 }
411}
412
413#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
415#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
416#[cfg_attr(feature = "musli", derive(Decode, Encode))]
417#[non_exhaustive]
418pub enum Type {
419 #[default]
421 Display,
422 Debug,
424 UpperHex,
426 LowerHex,
428 Binary,
430 Pointer,
432}
433
434impl str::FromStr for Type {
435 type Err = TypeFromStrError;
436
437 #[inline]
438 fn from_str(s: &str) -> Result<Self, Self::Err> {
439 match s {
440 "display" => Ok(Self::Display),
441 "debug" => Ok(Self::Debug),
442 "upper_hex" => Ok(Self::UpperHex),
443 "lower_hex" => Ok(Self::LowerHex),
444 "binary" => Ok(Self::Binary),
445 "pointer" => Ok(Self::Pointer),
446 _ => Err(TypeFromStrError),
447 }
448 }
449}
450
451impl fmt::Display for Type {
452 #[inline]
453 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
454 match self {
455 Self::Display => {
456 write!(f, "display")?;
457 }
458 Self::Debug => {
459 write!(f, "debug")?;
460 }
461 Self::UpperHex => {
462 write!(f, "upper_hex")?;
463 }
464 Self::LowerHex => {
465 write!(f, "lower_hex")?;
466 }
467 Self::Binary => {
468 write!(f, "binary")?;
469 }
470 Self::Pointer => {
471 write!(f, "pointer")?;
472 }
473 }
474
475 Ok(())
476 }
477}
478
479#[derive(Debug, Clone, Copy, TryClone, PartialEq, Eq)]
481#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
482#[cfg_attr(feature = "musli", derive(Decode, Encode))]
483#[try_clone(copy)]
484#[non_exhaustive]
485pub enum Alignment {
486 Left,
488 Center,
490 Right,
492}
493
494impl Default for Alignment {
495 fn default() -> Self {
496 Self::Left
497 }
498}
499
500impl str::FromStr for Alignment {
501 type Err = AlignmentFromStrError;
502
503 #[inline]
504 fn from_str(s: &str) -> Result<Self, Self::Err> {
505 match s {
506 "left" => Ok(Self::Left),
507 "center" => Ok(Self::Center),
508 "right" => Ok(Self::Right),
509 _ => Err(AlignmentFromStrError),
510 }
511 }
512}
513
514impl fmt::Display for Alignment {
515 #[inline]
516 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
517 match self {
518 Self::Left => {
519 write!(f, "left")?;
520 }
521 Self::Center => {
522 write!(f, "center")?;
523 }
524 Self::Right => {
525 write!(f, "right")?;
526 }
527 }
528
529 Ok(())
530 }
531}
532
533#[derive(Clone, Copy)]
535#[repr(u32)]
536#[non_exhaustive]
537pub enum Flag {
538 SignPlus,
540 SignMinus,
542 Alternate,
544 SignAwareZeroPad,
546}
547
548#[derive(Clone, Copy, TryClone, Default, PartialEq, Eq)]
550#[repr(transparent)]
551#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
552#[cfg_attr(feature = "musli", derive(Decode, Encode), musli(transparent))]
553#[try_clone(copy)]
554pub struct Flags(u32);
555
556impl Flags {
557 #[inline]
559 pub fn is_empty(self) -> bool {
560 self.0 == 0
561 }
562
563 #[inline]
566 pub fn into_u32(self) -> u32 {
567 self.0
568 }
569
570 #[inline]
572 pub fn set(&mut self, flag: Flag) {
573 self.0 |= &(1 << flag as u32);
574 }
575
576 #[inline]
578 pub fn test(&self, flag: Flag) -> bool {
579 (self.0 & (1 << flag as u32)) != 0
580 }
581}
582
583impl From<u32> for Flags {
584 fn from(flags: u32) -> Self {
585 Self(flags)
586 }
587}
588
589impl fmt::Debug for Flags {
590 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
591 macro_rules! fmt_flag {
592 ($flag:ident, $o:ident, $spec:literal) => {
593 if self.test(Flag::$flag) {
594 if !take(&mut $o) {
595 write!(f, ", ")?;
596 }
597
598 write!(f, $spec)?;
599 }
600 };
601 }
602
603 let mut o = true;
604 write!(f, "Flags{{")?;
605 fmt_flag!(SignPlus, o, "+");
606 fmt_flag!(SignMinus, o, "-");
607 fmt_flag!(Alternate, o, "#");
608 fmt_flag!(SignAwareZeroPad, o, "0");
609 write!(f, "}}")?;
610 Ok(())
611 }
612}