1//! I/O functions.
23#[cfg(feature = "std")]
4use std::io::{self, Write as _};
56use crate as rune;
7#[cfg(feature = "std")]
8use crate::alloc::fmt::TryWrite;
9use crate::compile;
10use crate::macros::{quote, FormatArgs, MacroContext, TokenStream};
11use crate::parse::Parser;
12#[cfg(feature = "std")]
13use crate::runtime::{Formatter, InstAddress, Memory, Output, Panic, VmResult};
14use crate::{ContextError, Module};
1516/// I/O functions.
17#[rune::module(::std::io)]
18pub fn module(
19#[cfg_attr(not(feature = "std"), allow(unused))] stdio: bool,
20) -> Result<Module, ContextError> {
21let mut module = Module::from_meta(self::module_meta)?.with_unique("std::io");
2223 module.item_mut().docs(docstring! {
24/// The std::io module contains a number of common things
25 /// you’ll need when doing input and output.
26 /// The most core parts of this module are the [print()], [println()],
27 /// and [dbg()] functions which are used to hook up printing for a Rune project.
28 ///
29 /// With complete names:
30 /// * `::std::io::print`
31 /// * `::std::io::println`
32 /// * `::std::io::dbg`
33 ///
34 /// Their definitions can be omitted from the built-in standard library, and
35 /// can then easily be defined by third party modules allowing for printing
36 /// to be hooked up to whatever system you want.
37})?;
3839#[cfg(feature = "std")]
40module.ty::<io::Error>()?;
41#[cfg(feature = "std")]
42module.function_meta(io_error_display_fmt)?;
43#[cfg(feature = "std")]
44module.function_meta(io_error_debug_fmt)?;
4546#[cfg(feature = "std")]
47if stdio {
48 module.function_meta(print_impl)?;
49 module.function_meta(println_impl)?;
5051 module
52 .raw_function("dbg", dbg_impl)
53 .build()?
54.docs(docstring! {
55/// Debug to output.
56 ///
57 /// This is the actual output hook, and if you install rune modules without
58 /// `I/O` enabled this will not be defined. It is then up to someone else to
59 /// provide an implementation.
60 ///
61 /// # Examples
62 ///
63 /// ```rune
64 /// let number = 10;
65 /// let number = number * 4;
66 ///
67 /// let who = "World";
68 /// let string = format!("Hello {who}");
69 ///
70 /// dbg(number, string);
71 /// ```
72})?;
73 }
7475// These are unconditionally included, but using them might cause a
76 // compilation error unless `::std::io::*` functions are provided somehow.
77module.macro_meta(dbg_macro)?;
78 module.macro_meta(print_macro)?;
79 module.macro_meta(println_macro)?;
80Ok(module)
81}
8283#[rune::function(instance, protocol = DISPLAY_FMT)]
84#[cfg(feature = "std")]
85fn io_error_display_fmt(error: &io::Error, f: &mut Formatter) -> VmResult<()> {
86vm_write!(f, "{error}")
87}
8889#[rune::function(instance, protocol = DEBUG_FMT)]
90#[cfg(feature = "std")]
91fn io_error_debug_fmt(error: &io::Error, f: &mut Formatter) -> VmResult<()> {
92vm_write!(f, "{error:?}")
93}
9495#[cfg(feature = "std")]
96fn dbg_impl(stack: &mut dyn Memory, addr: InstAddress, args: usize, out: Output) -> VmResult<()> {
97let stdout = io::stdout();
98let mut stdout = stdout.lock();
99100for value in vm_try!(stack.slice_at(addr, args)) {
101vm_try!(writeln!(stdout, "{:?}", value).map_err(Panic::custom));
102 }
103104vm_try!(out.store(stack, ()));
105 VmResult::Ok(())
106}
107108/// Debug print the given argument.
109///
110/// Everything in rune can be "debug printed" in one way or another. This is
111/// provided as a cheap an dirty way to introspect values.
112///
113/// See also the [`dbg!`] macro.
114///
115/// # Examples
116///
117/// ```rune
118/// let number = 10;
119/// let number = number * 4;
120///
121/// let who = "World";
122/// let string = format!("Hello {}", who);
123///
124/// dbg!(number, string);
125/// ```
126#[rune::macro_(path = dbg)]
127pub(crate) fn dbg_macro(
128 cx: &mut MacroContext<'_, '_, '_>,
129 stream: &TokenStream,
130) -> compile::Result<TokenStream> {
131Ok(quote!(::std::io::dbg(#stream)).into_token_stream(cx)?)
132}
133134/// Prints to output.
135///
136/// Output printing is performed by calling the [`print()`] function, this is
137/// just a convenience wrapper around it which allows for formatting.
138///
139/// # Examples
140///
141/// ```rune
142/// let who = "World";
143/// print!("Hello {}!", who);
144/// ```
145#[rune::macro_(path = print)]
146pub(crate) fn print_macro(
147 cx: &mut MacroContext<'_, '_, '_>,
148 stream: &TokenStream,
149) -> compile::Result<TokenStream> {
150let mut p = Parser::from_token_stream(stream, cx.input_span());
151let args = p.parse_all::<FormatArgs>()?;
152let expanded = args.expand(cx)?;
153Ok(quote!(::std::io::print(#expanded)).into_token_stream(cx)?)
154}
155156/// Prints to output.
157///
158/// This is the actual output hook, and if you install rune modules without
159/// `I/O` enabled this will not be defined. It is then up to someone else to
160/// provide an implementation.
161///
162/// See also the [`print!`] macro.
163///
164/// # Examples
165///
166/// ```rune
167/// print("Hi!");
168/// ```
169#[rune::function(path = print)]
170#[cfg(feature = "std")]
171fn print_impl(m: &str) -> VmResult<()> {
172let stdout = io::stdout();
173let mut stdout = stdout.lock();
174175if let Err(error) = write!(stdout, "{}", m) {
176return VmResult::err(Panic::custom(error));
177 }
178179 VmResult::Ok(())
180}
181182/// Prints to output, with a newline.
183///
184/// Output printing is performed by calling the [`println()`] function, this is
185/// just a convenience wrapper around it which allows for formatting.
186///
187/// # Examples
188///
189/// ```rune
190/// let who = "World";
191/// println!("Hello {}!", who);
192/// ```
193#[rune::macro_(path = println)]
194pub(crate) fn println_macro(
195 cx: &mut MacroContext<'_, '_, '_>,
196 stream: &TokenStream,
197) -> compile::Result<TokenStream> {
198let mut p = Parser::from_token_stream(stream, cx.input_span());
199let args = p.parse_all::<FormatArgs>()?;
200let expanded = args.expand(cx)?;
201Ok(quote!(::std::io::println(#expanded)).into_token_stream(cx)?)
202}
203204/// Prints to output, with a newline.
205///
206/// This is the actual output hook, and if you install rune modules without
207/// `I/O` enabled this will not be defined. It is then up to someone else to
208/// provide an implementation.
209///
210/// # Examples
211///
212/// ```rune
213/// println("Hi!");
214/// ```
215#[rune::function(path = println)]
216#[cfg(feature = "std")]
217fn println_impl(message: &str) -> VmResult<()> {
218let stdout = io::stdout();
219let mut stdout = stdout.lock();
220221if let Err(error) = writeln!(stdout, "{}", message) {
222return VmResult::err(Panic::custom(error));
223 }
224225 VmResult::Ok(())
226}