1use crate as rune;
4use crate::alloc::{self, try_format, Vec};
5use crate::ast;
6use crate::compile;
7use crate::macros::{quote, FormatArgs, MacroContext, TokenStream};
8use crate::runtime::Function;
9use crate::{docstring, Any, ContextError, Module};
10
11#[rune::module(::std::test)]
13pub fn module() -> Result<Module, ContextError> {
14 let mut m = Module::from_meta(self::module__meta)?.with_unique("std::test");
15
16 m.macro_meta(assert)?;
17 m.macro_meta(assert_eq)?;
18 m.macro_meta(assert_ne)?;
19
20 m.ty::<Bencher>()?.docs(docstring! {
21 })?;
25
26 m.function_meta(Bencher::iter)?;
27 Ok(m)
28}
29
30#[derive(Default, Any)]
32#[rune(module = crate, item = ::std::test)]
33pub struct Bencher {
34 fns: Vec<Function>,
35}
36
37impl Bencher {
38 pub fn into_functions(self) -> Vec<Function> {
40 self.fns
41 }
42
43 #[rune::function]
45 fn iter(&mut self, f: Function) -> alloc::Result<()> {
46 self.fns.try_push(f)
47 }
48}
49
50#[rune::macro_]
65pub(crate) fn assert(
66 cx: &mut MacroContext<'_, '_, '_>,
67 stream: &TokenStream,
68) -> compile::Result<TokenStream> {
69 use crate as rune;
70
71 let mut p = cx.parser(stream, cx.input_span());
72 let expr = p.parse::<ast::Expr>()?;
73
74 let message = if p.parse::<Option<T![,]>>()?.is_some() {
75 p.parse_all::<Option<FormatArgs>>()?
76 } else {
77 None
78 };
79
80 let output = if let Some(message) = &message {
81 let expanded = message.expand(cx)?;
82
83 quote!(if !(#expr) {
84 ::std::panic("assertion failed: " + (#expanded));
85 })
86 } else {
87 let message = try_format!("assertion failed: {}", cx.stringify(&expr)?);
88 let message = cx.lit(&message)?;
89
90 quote!(if !(#expr) {
91 ::std::panic(#message);
92 })
93 };
94
95 Ok(output.into_token_stream(cx)?)
96}
97
98#[rune::macro_]
110pub(crate) fn assert_eq(
111 cx: &mut MacroContext<'_, '_, '_>,
112 stream: &TokenStream,
113) -> compile::Result<TokenStream> {
114 use crate as rune;
115
116 let mut p = cx.parser(stream, cx.input_span());
117 let left = p.parse::<ast::Expr>()?;
118 p.parse::<T![,]>()?;
119 let right = p.parse::<ast::Expr>()?;
120
121 let message = if p.parse::<Option<T![,]>>()?.is_some() {
122 p.parse_all::<Option<FormatArgs>>()?
123 } else {
124 None
125 };
126
127 let output = if let Some(message) = &message {
128 let message = message.expand(cx)?;
129
130 quote! {{
131 let left = #left;
132 let right = #right;
133
134 if !(left == right) {
135 let message = #message;
136 message += ::std::fmt::format!("\nleft: {:?}", left);
137 message += ::std::fmt::format!("\nright: {:?}", right);
138 ::std::panic("assertion failed (left == right): " + message);
139 }
140 }}
141 } else {
142 let message = cx.lit("assertion failed (left == right):")?;
143
144 quote! {{
145 let left = #left;
146 let right = #right;
147
148 if !(left == right) {
149 let message = ::std::string::String::from(#message);
150 message += ::std::fmt::format!("\nleft: {:?}", left);
151 message += ::std::fmt::format!("\nright: {:?}", right);
152 ::std::panic(message);
153 }
154 }}
155 };
156
157 Ok(output.into_token_stream(cx)?)
158}
159
160#[rune::macro_]
172pub(crate) fn assert_ne(
173 cx: &mut MacroContext<'_, '_, '_>,
174 stream: &TokenStream,
175) -> compile::Result<TokenStream> {
176 use crate as rune;
177
178 let mut p = cx.parser(stream, cx.input_span());
179 let left = p.parse::<ast::Expr>()?;
180 p.parse::<T![,]>()?;
181 let right = p.parse::<ast::Expr>()?;
182
183 let message = if p.parse::<Option<T![,]>>()?.is_some() {
184 p.parse_all::<Option<FormatArgs>>()?
185 } else {
186 None
187 };
188
189 let output = if let Some(message) = &message {
190 let message = message.expand(cx)?;
191
192 quote! {{
193 let left = #left;
194 let right = #right;
195
196 if !(left != right) {
197 let message = #message;
198 message += ::std::fmt::format!("\nleft: {:?}", left);
199 message += ::std::fmt::format!("\nright: {:?}", right);
200 ::std::panic("assertion failed (left != right): " + message);
201 }
202 }}
203 } else {
204 let message = cx.lit("assertion failed (left != right):")?;
205
206 quote! {{
207 let left = #left;
208 let right = #right;
209
210 if !(left != right) {
211 let message = ::std::string::String::from(#message);
212 message += ::std::fmt::format!("\nleft: {:?}", left);
213 message += ::std::fmt::format!("\nright: {:?}", right);
214 ::std::panic(message);
215 }
216 }}
217 };
218
219 Ok(output.into_token_stream(cx)?)
220}