mirror of
https://github.com/Noratrieb/mono-fmt.git
synced 2026-01-17 00:35:05 +01:00
Only eval args once
This commit is contained in:
parent
58e90857d2
commit
b5f6318fce
3 changed files with 65 additions and 15 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
|
||||||
use proc_macro2::{Ident, TokenStream};
|
use proc_macro2::{Ident, Span, TokenStream};
|
||||||
use quote::{quote, ToTokens};
|
use quote::{quote, ToTokens};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -17,6 +17,14 @@ pub(crate) struct Scoped<'a, T> {
|
||||||
inner: &'a T,
|
inner: &'a T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pos_arg_ident(idx: usize) -> Ident {
|
||||||
|
Ident::new(&format!("__pos_arg_{idx}"), Span::mixed_site())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn named_arg_ident(name: impl std::fmt::Display) -> Ident {
|
||||||
|
Ident::new(&format!("__named_arg_{name}"), Span::mixed_site())
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, T> Scoped<'a, T> {
|
impl<'a, T> Scoped<'a, T> {
|
||||||
pub fn new(input: &'a Input, inner: &'a T, current_position: &'a Cell<usize>) -> Self {
|
pub fn new(input: &'a Input, inner: &'a T, current_position: &'a Cell<usize>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -46,10 +54,33 @@ impl ToTokens for Scoped<'_, Format<'_>> {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let parts = self.inner.pieces.iter().map(|piece| self.scope(piece));
|
let parts = self.inner.pieces.iter().map(|piece| self.scope(piece));
|
||||||
|
|
||||||
|
let input = &self.input;
|
||||||
|
|
||||||
|
let pos_args = input.positional_args.iter();
|
||||||
|
let named_args = input.named_args.iter().map(|(_, expr)| expr);
|
||||||
|
|
||||||
|
let args = pos_args.chain(named_args);
|
||||||
|
|
||||||
|
let pos_idents = input
|
||||||
|
.positional_args
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, _)| pos_arg_ident(idx));
|
||||||
|
|
||||||
|
let named_idents = input
|
||||||
|
.named_args
|
||||||
|
.iter()
|
||||||
|
.map(|(name, _)| named_arg_ident(name));
|
||||||
|
|
||||||
|
let idents = pos_idents.chain(named_idents);
|
||||||
|
|
||||||
tokens.extend(quote! {
|
tokens.extend(quote! {
|
||||||
(
|
#[allow(unused_parens)]
|
||||||
|
match (#(#args),*) {
|
||||||
|
(#(#idents),*) => (
|
||||||
#(#parts),*
|
#(#parts),*
|
||||||
)
|
)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -80,20 +111,16 @@ impl ToTokens for Scoped<'_, FormatArg<'_>> {
|
||||||
let current_position = self.current_position.get();
|
let current_position = self.current_position.get();
|
||||||
self.current_position.set(current_position + 1);
|
self.current_position.set(current_position + 1);
|
||||||
|
|
||||||
self.input.positional_args[current_position].to_token_stream()
|
pos_arg_ident(current_position)
|
||||||
}
|
|
||||||
Some(FormatArgRef::Positional(idx)) => {
|
|
||||||
self.input.positional_args[idx].to_token_stream()
|
|
||||||
}
|
}
|
||||||
|
Some(FormatArgRef::Positional(idx)) => pos_arg_ident(idx),
|
||||||
Some(FormatArgRef::Named(name)) => self
|
Some(FormatArgRef::Named(name)) => self
|
||||||
.input
|
.input
|
||||||
.named_args
|
.named_args
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(arg, _)| arg == name)
|
.find(|(arg, _)| arg == name)
|
||||||
.map(|(_, expr)| expr.to_token_stream())
|
.map(|(name, _)| named_arg_ident(name))
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| Ident::new(name, self.input.format_str.span())),
|
||||||
Ident::new(name, self.input.format_str.span()).to_token_stream()
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let opt_ty = opt_ty_tokens(self.scope(&self.inner.format_spec.formatter_args));
|
let opt_ty = opt_ty_tokens(self.scope(&self.inner.format_spec.formatter_args));
|
||||||
|
|
|
||||||
17
src/lib.rs
17
src/lib.rs
|
|
@ -116,8 +116,19 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod uwu {
|
pub mod uwu {
|
||||||
fn test_format_debug_hex() {
|
use std::cell::Cell;
|
||||||
assert_eq!(format!("{:02x?}", b"Foo\0"), "[46, 6f, 6f, 00]");
|
|
||||||
assert_eq!(format!("{:02X?}", b"Foo\0"), "[46, 6F, 6F, 00]");
|
fn test_expansion() {
|
||||||
|
let evil = Cell::new(0);
|
||||||
|
format!(
|
||||||
|
"{0}{0}{1}{owo}",
|
||||||
|
{
|
||||||
|
evil.set(evil.get() + 1);
|
||||||
|
0
|
||||||
|
},
|
||||||
|
5,
|
||||||
|
owo = "owo",
|
||||||
|
);
|
||||||
|
// assert_eq!(evil.get(), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate mono_fmt;
|
extern crate mono_fmt;
|
||||||
|
|
||||||
|
|
@ -17,3 +19,13 @@ fn test_pointer_formats_data_pointer() {
|
||||||
assert_eq!(format!("{s:p}"), format!("{:p}", s.as_ptr()));
|
assert_eq!(format!("{s:p}"), format!("{:p}", s.as_ptr()));
|
||||||
assert_eq!(format!("{b:p}"), format!("{:p}", b.as_ptr()));
|
assert_eq!(format!("{b:p}"), format!("{:p}", b.as_ptr()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn only_eval_once() {
|
||||||
|
let evil = Cell::new(0);
|
||||||
|
let _ = format!("{0} {0}", {
|
||||||
|
evil.set(evil.get() + 1);
|
||||||
|
0
|
||||||
|
});
|
||||||
|
assert_eq!(evil.get(), 1);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue