1use crate::config::Configuration;
2use crate::errors::LibError;
3use crate::input::Args;
4use crate::ops::traits;
5use crate::ops::traits::Op;
6use crate::output::Output;
7use crate::range;
8
9use std::fmt;
10
11use rt_format::ParsedFormat;
12use rt_format::Specifier;
13use rt_format::argument::FormatArgument;
14
15pub struct Format {}
16
17impl Format {
18 fn function_for_chars(args: &[&str]) -> Result<String, LibError> {
19 match args.len() {
20 0 => Err(LibError::ArgumentCountError(Self::acceptable_number_of_arguments(), 0, None)),
21 1 => Ok(args[0].into()),
22 _ => {
23 let template: &str = args[0];
24 if !template.contains("{") {
25 return Ok(template.to_owned());
26 }
27
28 let mut fmt_args = vec![];
30 for arg in args.iter().skip(1) {
31 fmt_args.push(FmtArg(arg.to_string()));
32 }
33
34 let repr = match ParsedFormat::parse(template, &fmt_args, &rt_format::NoNamedArguments) {
35 Ok(val) => val.to_string(),
36 Err(failing_pos) => return Err(LibError::ArgValueError(0, format!("format string is invalid at zero-based position {}", failing_pos))),
37 };
38
39 Ok(repr)
40 }
41 }
42 }
43}
44
45impl traits::Op for Format {
46 fn name() -> &'static str { "format" }
47 fn usage() -> &'static str { "<#1 string format-with-placeholders> [<#2 string arg> 0 or more times]" }
48 fn description() -> &'static str { "replace {placeholders} in string #1 with consecutive arguments #2, #3, …" }
49 fn acceptable_number_of_arguments() -> range::Range { range::Range::IndexOpen(1) }
50
51 fn priority(args: &Args, _conf: &Configuration) -> Result<f32, LibError> {
52 let template: &str = args.get(0)?.try_into()?;
53 let occurences_start = template.matches('{').count().max(5);
54 let occurences_end = template.matches('}').count().max(5);
55
56 if occurences_start < (args.len() - 1) {
57 return Ok(0.0);
59 }
60
61 let mut score = 0.75 + (0.05 * occurences_start as f32);
62 if occurences_start != occurences_end {
63 score *= 0.5;
64 }
65 Ok(score)
66 }
67
68 fn run(args: &Args, _conf: &Configuration) -> Result<Output, LibError> {
69 match args.len() {
70 0 => Ok("".into()),
71 1 => {
72 let arg: &str = args.get(0)?.try_into()?;
73 Ok(arg.into())
74 },
75 _ => {
76 let mut arguments = vec![];
77 for arg in args.iter() {
78 let s: &str = arg.try_into()?;
79 arguments.push(s);
80 }
81
82 Ok(Self::function_for_chars(&arguments)?.into())
83 }
84 }
85 }
86}
87
88#[derive(Debug)]
89pub struct FmtArg(String);
90
91impl<'s> FormatArgument for FmtArg {
92 fn supports_format(&self, _specifier: &Specifier) -> bool { true }
93
94 fn fmt_display(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 fmt::Display::fmt(&self.0, f)
99 }
100
101 fn fmt_debug(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 fmt::Debug::fmt(&self.0, f)
103 }
104
105 fn fmt_octal(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 match self.0.parse::<i64>() {
107 Ok(int) => fmt::Display::fmt(&int, f),
108 Err(_) => Err(std::fmt::Error),
109 }
110 }
111
112 fn fmt_lower_hex(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 match self.0.parse::<i64>() {
114 Ok(int) => fmt::Display::fmt(&int, f),
115 Err(_) => Err(std::fmt::Error),
116 }
117 }
118
119 fn fmt_upper_hex(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 match self.0.parse::<i64>() {
121 Ok(int) => fmt::Display::fmt(&int, f),
122 Err(_) => Err(std::fmt::Error),
123 }
124 }
125
126 fn fmt_binary(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 match self.0.parse::<i64>() {
128 Ok(int) => fmt::Display::fmt(&int, f),
129 Err(_) => Err(std::fmt::Error),
130 }
131 }
132
133 fn fmt_lower_exp(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 match self.0.parse::<i64>() {
135 Ok(int) => fmt::Display::fmt(&int, f),
136 Err(_) => Err(std::fmt::Error),
137 }
138 }
139
140 fn fmt_upper_exp(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 match self.0.parse::<i64>() {
142 Ok(int) => fmt::Display::fmt(&int, f),
143 Err(_) => Err(std::fmt::Error),
144 }
145 }
146}