Skip to main content

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