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