diff --git a/examples/full-derive/src/main.rs b/examples/full-derive/src/main.rs index be04abc..0907880 100644 --- a/examples/full-derive/src/main.rs +++ b/examples/full-derive/src/main.rs @@ -6,7 +6,7 @@ use error_iter::ErrorIter as _; use onlyargs::{CliError, OnlyArgs as _}; use onlyargs_derive::OnlyArgs; use onlyerror::Error; -use std::{path::PathBuf, process::ExitCode}; +use std::{fmt::Write as _, path::PathBuf, process::ExitCode}; /// A basic argument parsing example with `onlyargs_derive`. /// Sums a list of numbers and writes the result to a file or standard output. @@ -45,11 +45,10 @@ fn run() -> Result<(), Error> { println!("The width is {}.", args.width); // Do some work. - let numbers = &args - .numbers - .iter() - .map(|num| format!(" + {num}")) - .collect::(); + let numbers = &args.numbers.iter().fold(String::new(), |mut numbers, num| { + write!(numbers, " + {num}").unwrap(); + numbers + }); if let Some(numbers) = numbers.strip_prefix(" + ") { let sum: i32 = args.numbers.iter().sum(); diff --git a/examples/full/src/main.rs b/examples/full/src/main.rs index 1046ec0..326db88 100644 --- a/examples/full/src/main.rs +++ b/examples/full/src/main.rs @@ -1,6 +1,6 @@ use error_iter::ErrorIter as _; use onlyargs::{traits::*, CliError, OnlyArgs}; -use std::{ffi::OsString, path::PathBuf, process::ExitCode}; +use std::{ffi::OsString, fmt::Write as _, path::PathBuf, process::ExitCode}; #[derive(Debug)] struct Args { @@ -127,11 +127,10 @@ fn run() -> Result<(), Error> { println!("The width is {}.", args.width); // Do some work. - let numbers = &args - .numbers - .iter() - .map(|num| format!(" + {num}")) - .collect::(); + let numbers = &args.numbers.iter().fold(String::new(), |mut numbers, num| { + write!(numbers, " + {num}").unwrap(); + numbers + }); if let Some(numbers) = numbers.strip_prefix(" + ") { let sum: i32 = args.numbers.iter().sum(); diff --git a/onlyargs_derive/src/lib.rs b/onlyargs_derive/src/lib.rs index 76ae143..fdacfe5 100644 --- a/onlyargs_derive/src/lib.rs +++ b/onlyargs_derive/src/lib.rs @@ -105,7 +105,7 @@ use crate::parser::{ArgFlag, ArgOption, ArgType, ArgView, ArgumentStruct}; use myn::utils::spanned_error; use proc_macro::{Ident, Span, TokenStream}; -use std::{collections::HashMap, str::FromStr as _}; +use std::{collections::HashMap, fmt::Write as _, str::FromStr as _}; mod parser; @@ -132,7 +132,7 @@ pub fn derive_parser(input: TokenStream) -> TokenStream { output: false, }, ]; - flags.extend(ast.flags.into_iter()); + flags.extend(ast.flags); // De-dupe short args. let mut dupes = HashMap::new(); @@ -173,15 +173,14 @@ pub fn derive_parser(input: TokenStream) -> TokenStream { .unwrap_or_default(); // Produce variables for argument parser state. - let flags_vars = flags - .iter() - .filter_map(|flag| { - flag.output.then(|| { - let name = &flag.name; - format!("let mut {name} = false;") - }) - }) - .collect::(); + let flags_vars = + flags + .iter() + .filter(|&flag| flag.output) + .fold(String::new(), |mut flags, flag| { + write!(flags, "let mut {name} = false;", name = &flag.name).unwrap(); + flags + }); let options_vars = ast .options .iter() @@ -204,54 +203,55 @@ pub fn derive_parser(input: TokenStream) -> TokenStream { .unwrap_or_default(); // Produce matchers for parser. - let flags_matchers = flags - .iter() - .filter_map(|flag| { - flag.output.then(|| { + let flags_matchers = + flags + .iter() + .filter(|&flag| flag.output) + .fold(String::new(), |mut matchers, flag| { let name = &flag.name; let short = flag .short .map(|ch| format!(r#"| Some("-{ch}")"#)) .unwrap_or_default(); - format!( + write!( + matchers, r#"Some("--{arg}") {short} => {name} = true,"#, arg = to_arg_name(name) ) - }) - }) - .collect::(); - let options_matchers = ast - .options - .iter() - .map(|opt| { - let name = &opt.name; - let short = opt - .short - .map(|ch| format!(r#"| Some(name @ "-{ch}")"#)) - .unwrap_or_default(); - let value = if opt.default.is_some() { - match opt.ty_help { - ArgType::Number => "args.next().parse_int(name)?", - ArgType::OsString => "args.next().parse_osstr(name)?", - ArgType::Path => "args.next().parse_path(name)?", - ArgType::String => "args.next().parse_str(name)?", - } - } else { - match opt.ty_help { - ArgType::Number => "Some(args.next().parse_int(name)?)", - ArgType::OsString => "Some(args.next().parse_osstr(name)?)", - ArgType::Path => "Some(args.next().parse_path(name)?)", - ArgType::String => "Some(args.next().parse_str(name)?)", - } - }; + .unwrap(); + matchers + }); + let options_matchers = ast.options.iter().fold(String::new(), |mut matchers, opt| { + let name = &opt.name; + let short = opt + .short + .map(|ch| format!(r#"| Some(name @ "-{ch}")"#)) + .unwrap_or_default(); + let value = if opt.default.is_some() { + match opt.ty_help { + ArgType::Number => "args.next().parse_int(name)?", + ArgType::OsString => "args.next().parse_osstr(name)?", + ArgType::Path => "args.next().parse_path(name)?", + ArgType::String => "args.next().parse_str(name)?", + } + } else { + match opt.ty_help { + ArgType::Number => "Some(args.next().parse_int(name)?)", + ArgType::OsString => "Some(args.next().parse_osstr(name)?)", + ArgType::Path => "Some(args.next().parse_path(name)?)", + ArgType::String => "Some(args.next().parse_str(name)?)", + } + }; - format!( - r#"Some(name @ "--{arg}") {short} => {name} = {value},"#, - arg = to_arg_name(name) - ) - }) - .collect::(); + write!( + matchers, + r#"Some(name @ "--{arg}") {short} => {name} = {value},"#, + arg = to_arg_name(name) + ) + .unwrap(); + matchers + }); let positional_matcher = match ast.positional.as_ref() { Some(opt) => { let name = &opt.name; diff --git a/onlyargs_derive/src/parser.rs b/onlyargs_derive/src/parser.rs index cd4dc6d..6aa783e 100644 --- a/onlyargs_derive/src/parser.rs +++ b/onlyargs_derive/src/parser.rs @@ -147,7 +147,7 @@ impl Argument { if path == "bool" { args.push(Self::Flag(ArgFlag::new(name, short, doc))); } else { - let mut opt = ArgOption::new(name, short, doc, &path).map_err(|_| { + let mut opt = ArgOption::new(name, short, doc, &path).map_err(|()| { spanned_error( "Expected bool, PathBuf, String, OsString, integer, or float", span,