Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix number implementations are never used #24

Merged
merged 5 commits into from
Jul 28, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 145 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,64 @@ fmtint!(u8 i8 u16 i16 u32 i32 u64 i64 usize isize);
fmtfloat!(f32 f64);

/// Rust-style format a string given a `HashMap` of the variables.
pub fn strfmt<K, T: fmt::Display>(fmtstr: &str, vars: &HashMap<K, T>) -> Result<String>
vitiral marked this conversation as resolved.
Show resolved Hide resolved
where
K: Hash + Eq + FromStr,
/// # Arguments
///
/// * `fmtstr` - A string defining the format
/// * `vars` - A `HashMap` holding the variables to use
///
/// # Exceptions
///
/// * [FmtError::Invalid] - The format string is structured incorrectly
/// * [FmtError::KeyError] - `vars` contains an invalid key
/// * [FmtError::TypeError] - the given format code for a section contains an unexpected option
///
/// # Examples
///
/// ```
/// use std::collections::HashMap;
/// use std::f64::consts::PI;
/// use strfmt::strfmt;
///
/// let mut my_vars: HashMap<String, f64> = HashMap::new();
/// my_vars.insert("Alpha".to_string(),42.0);
/// my_vars.insert("Beta".to_string(),PI);
///
/// let result = strfmt("{Alpha} {Beta:<5.2}",&my_vars);
///
/// if let Ok(text) = result {
/// println!("{}",text);
/// }else {
/// println!("{}","woops?");
/// }
/// ```
pub fn strfmt<'a, K, T: DisplayStr>(fmtstr: &str, vars: &HashMap<K, T>) -> Result<String>
where
K: Hash + Eq + FromStr
{
let formatter = |mut fmt: Formatter| {
let k: K = match fmt.key.parse() {
Ok(k) => k,
Err(_) => {
return Err(new_key_error(fmt.key));
}
};
let v = match vars.get(&k) {
Some(v) => v,
None => {
return Err(new_key_error(fmt.key));
}
};
v.display_str(&mut fmt)
};
strfmt_map(fmtstr, &formatter)
}

/// Rust-style format a string given a `HashMap` of the variables.
/// see [strfmt] for details
#[deprecated(since = "0.2.0", note = "This function contains a bug when formatting numbers. Use strfmt instead")]
pub fn strfmt_display<'a, K, T: fmt::Display>(fmtstr: &str, vars: &HashMap<K, T>) -> Result<String>
where
K: Hash + Eq + FromStr
{
let formatter = |mut fmt: Formatter| {
let k: K = match fmt.key.parse() {
Expand All @@ -47,28 +102,106 @@ where
strfmt_map(fmtstr, &formatter)
}

macro_rules! display_str_impl {
($($t:ident)*) => ($(
impl DisplayStr for $t {
fn display_str(&self,f:&mut Formatter) -> Result<()> {
f.$t(*self)
}
}
)*)
}

display_str_impl!(u8 i8 u16 i16 u32 i32 u64 i64 usize isize);
display_str_impl!(f32 f64);

impl DisplayStr for String{
fn display_str(&self, f: &mut Formatter) -> Result<()> {
f.str(self.as_str())
}
}

impl DisplayStr for &str{
fn display_str(&self, f: &mut Formatter) -> Result<()> {
f.str(self)
}
}
/// This trait is effectively an re-implementation for [std::fmt::Display]
/// It is used to disguise between the value types that should be formatted
pub trait DisplayStr {
fn display_str(&self, f:&mut Formatter) -> Result<()>;
}

/// This trait is a shortcut for [strfmt]
/// for an example see [Format::format]
pub trait Format {
Copy link
Contributor Author

@Nebdir Nebdir Jul 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'll make this as clear as I can explain with my limited English.
The marked trait (line 96) is defining functions for str and String where usage would be "{Zero}".format(&vars).
By adding a legacy function here named strfmt_display it would make sense to add a similar extension to allow a usage like "{Zero}".format_display(&vars) as either the original signature would change from format<K, D: fmt::Display>(&self, vars: &HashMap<K, D>) -> Result<String> to format<K, D: DisplayStr>(&self, vars: &HashMap<K, D>) -> Result<String> or the body would change and default to use the legacy code.

Don't hesitate to ask, sometimes I think way too complicated and by reading these lines I wrote I'm not sure if it gets clear what problem ist the cause for this..

Copy link
Owner

@vitiral vitiral Jul 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying. I agree with you, there should be two functioned defined by Format:

trait Format {
  fn format<K, D: DisplayStr>(&self, vars: &HashMap<K, D>) -> Result<String>

  fn format_display<K, D: Display>(&self, vars: &HashMap<K, D>) -> Result<String>
}

fn format<K, D: fmt::Display>(&self, vars: &HashMap<K, D>) -> Result<String>
where
K: Hash + Eq + FromStr;
/// format a string using strfmt
/// # Arguments
///
/// * `vars` - A `HashMap` holding the variables to use
///
/// # Errors
/// Errors are passed directly from strfmt, for details see [strfmt]
///
/// # Examples
///
/// ```
/// use std::collections::HashMap;
/// use std::f64::consts::PI;
/// use strfmt::Format;
///
/// let mut my_vars: HashMap<String, f64> = HashMap::new();
/// my_vars.insert("Alpha".to_string(),42.0);
/// my_vars.insert("Beta".to_string(),PI);
///
/// let result = "|{Alpha}|{Beta:<5.2}|".format(&my_vars);
vitiral marked this conversation as resolved.
Show resolved Hide resolved
///
/// if let Ok(text) = result {
/// println!("{}",text);
/// }else {
/// println!("{}","woops?");
/// }
/// ```
fn format<K, D: DisplayStr>(&self, vars: &HashMap<K, D>) -> Result<String>
where
K: Hash + Eq + FromStr;

/// format a string using strfmt_display
/// see [Format::format] for usage
#[deprecated(since = "0.2.0", note = "This function contains a bug when formatting numbers. Use format instead")]
fn format_display<K, D: fmt::Display>(&self, vars: &HashMap<K, D>) -> Result<String>
where
K: Hash + Eq + FromStr;
}

impl Format for String {
fn format<'a, K, D: fmt::Display>(&self, vars: &HashMap<K, D>) -> Result<String>
where
K: Hash + Eq + FromStr,
fn format<'a, K, D: DisplayStr>(&self, vars: &HashMap<K, D>) -> Result<String>
where
K: Hash + Eq + FromStr,
{
strfmt(self.as_str(), vars)
}
fn format_display<'a, K, D: fmt::Display>(&self, vars: &HashMap<K, D>) -> Result<String>
where
K: Hash + Eq + FromStr,
{
strfmt_display(self.as_str(), vars)
}
}

impl Format for str {
fn format<K, D: fmt::Display>(&self, vars: &HashMap<K, D>) -> Result<String>
where
K: Hash + Eq + FromStr,
fn format<K, D: DisplayStr>(&self, vars: &HashMap<K, D>) -> Result<String>
where
K: Hash + Eq + FromStr,
{
strfmt(self, vars)
}
fn format_display<'a, K, D: fmt::Display>(&self, vars: &HashMap<K, D>) -> Result<String>
where
K: Hash + Eq + FromStr,
{
strfmt_display(self, vars)
}
}

fn new_key_error(key: &str) -> FmtError {
Expand Down
34 changes: 34 additions & 0 deletions src/tests/float.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use std::collections::HashMap;
use ::{FmtError, Format};

#[test]
fn test_fmt_float64() -> Result<(),FmtError> {
let mut vars: HashMap<String, f64> = HashMap::new();
vars.insert("Zero".to_string(), 0.0);
vars.insert("One".to_string(), 10.0 / 3.0);
Nebdir marked this conversation as resolved.
Show resolved Hide resolved
vars.insert("Two".to_string(), 2.0);

assert_eq!("0".to_string(),"{Zero}".format(&vars)?);
assert_eq!("0.00".to_string(),"{Zero:.2}".format(&vars)?);
assert_eq!("3.33333".to_string(),"{One:.5}".format(&vars)?);
assert_eq!("2".to_string(),"{Two}".format(&vars)?);
assert_eq!("0.00 ".to_string(),"{Zero:<5.2}".format(&vars)?);

Ok(())
}

#[test]
fn test_fmt_float32() -> Result<(),FmtError> {
let mut vars: HashMap<String, f32> = HashMap::new();
vars.insert("Zero".to_string(), 0.0);
vars.insert("One".to_string(), 10.0 / 3.0);
Nebdir marked this conversation as resolved.
Show resolved Hide resolved
vars.insert("Two".to_string(), 2.0);

assert_eq!("0".to_string(),"{Zero}".format(&vars)?);
assert_eq!("0.00".to_string(),"{Zero:.2}".format(&vars)?);
assert_eq!("3.33333".to_string(),"{One:.5}".format(&vars)?);
assert_eq!("2".to_string(),"{Two}".format(&vars)?);
assert_eq!("0.00 ".to_string(),"{Zero:<5.2}".format(&vars)?);

Ok(())
}
20 changes: 20 additions & 0 deletions src/tests/legacy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use std::collections::HashMap;
use ::{FmtError, Format};

/// cautione here, this test just checks if the old float formatting behaviour is still present,
/// as this was changed in 0.2.0
#[test]
fn test_legacy() -> Result<(),FmtError> {
let mut vars: HashMap<String, f64> = HashMap::new();
vars.insert("Zero".to_string(), 0.0);
vars.insert("One".to_string(), 10.0 / 3.0);
vars.insert("Two".to_string(), 2.0);

assert_eq!("0".to_string(),"{Zero}".format_display(&vars)?);
assert_eq!("0".to_string(),"{Zero:.2}".format_display(&vars)?);
assert_eq!("3.333".to_string(),"{One:.5}".format_display(&vars)?);
assert_eq!("2".to_string(),"{Two}".format_display(&vars)?);
assert_eq!("0 ".to_string(),"{Zero:<5.2}".format_display(&vars)?);

Ok(())
}
2 changes: 2 additions & 0 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ mod fmt;
mod key;
mod strfmt;
mod test_trait;
mod float;
mod legacy;

use super::FmtError;

Expand Down