rune/modules/
fmt.rs

1//! Formatting text.
2
3use core::fmt;
4
5use crate as rune;
6use crate::alloc;
7use crate::alloc::fmt::TryWrite;
8use crate::alloc::prelude::*;
9use crate::compile;
10use crate::macros::{FormatArgs, MacroContext, TokenStream};
11use crate::parse::Parser;
12use crate::runtime::{EnvProtocolCaller, Format, Formatter, VmError};
13use crate::{ContextError, Module};
14
15/// Formatting text.
16///
17/// This includes types, macros, and functions used to format text.
18///
19/// # Examples
20///
21/// ```rune
22/// let who = "World";
23/// let string = format!("Hello {}", who);
24/// assert_eq!(string, "Hello World");
25/// ```
26#[rune::module(::std::fmt)]
27pub fn module() -> Result<Module, ContextError> {
28    let mut m = Module::from_meta(self::module__meta)?.with_unique("std::fmt");
29
30    m.ty::<Formatter>()?;
31    m.ty::<fmt::Error>()?;
32    m.function_meta(fmt_error_display_fmt)?;
33    m.macro_meta(format)?;
34
35    m.ty::<Format>()?;
36    m.function_meta(format_display_fmt__meta)?;
37    m.function_meta(format_debug_fmt__meta)?;
38    m.function_meta(format_clone__meta)?;
39    m.implement_trait::<Format>(rune::item!(::std::clone::Clone))?;
40
41    Ok(m)
42}
43
44#[rune::function(instance, protocol = DISPLAY_FMT)]
45fn fmt_error_display_fmt(error: &fmt::Error, f: &mut Formatter) -> alloc::Result<()> {
46    write!(f, "{error}")
47}
48
49/// Format a string using a format specifier.
50///
51/// # Examples
52///
53/// ```rune
54/// let who = "World";
55/// let string = format!("Hello {}", who);
56/// assert_eq!(string, "Hello World");
57/// ```
58#[rune::macro_(path = format)]
59pub(crate) fn format(
60    cx: &mut MacroContext<'_, '_, '_>,
61    stream: &TokenStream,
62) -> compile::Result<TokenStream> {
63    let mut p = Parser::from_token_stream(stream, cx.input_span());
64    let args = p.parse::<FormatArgs>()?;
65    p.eof()?;
66    let expanded = args.expand(cx)?;
67    Ok(expanded.into_token_stream(cx)?)
68}
69
70/// Write a display representation of a format specification.
71///
72/// # Examples
73///
74/// ```rune
75/// let value = #[builtin] format!("Hello", fill = '0', width = 10);
76/// assert_eq!(format!("{value}"), "Hello00000");
77/// ```
78#[rune::function(keep, instance, protocol = DISPLAY_FMT)]
79fn format_display_fmt(format: &Format, f: &mut Formatter) -> Result<(), VmError> {
80    format
81        .spec
82        .format(&format.value, f, &mut EnvProtocolCaller)?;
83    Ok(())
84}
85
86/// Write a debug representation of a format specification.
87///
88/// # Examples
89///
90/// ```rune
91/// let value = #[builtin] format!("Hello", fill = '0', width = 10);
92/// let string = format!("{value:?}");
93/// assert!(string is String);
94/// ```
95#[rune::function(keep, instance, protocol = DEBUG_FMT)]
96fn format_debug_fmt(format: &Format, f: &mut Formatter) -> alloc::Result<()> {
97    write!(f, "{format:?}")
98}
99
100/// Clones a format specification.
101///
102/// # Examples
103///
104/// ```rune
105/// let value = #[builtin] format!("Hello", fill = '0', width = 10);
106/// let vlaue2 = value.clone();
107/// assert_eq!(format!("{value}"), "Hello00000");
108/// ```
109#[rune::function(keep, instance, protocol = CLONE)]
110fn format_clone(this: &Format) -> Result<Format, VmError> {
111    Ok(this.try_clone()?)
112}