From 42a6ae5353bda61664fed2bbe7520ac2b17a79c4 Mon Sep 17 00:00:00 2001 From: Isaac Carruthers Date: Tue, 22 Aug 2017 14:27:43 -0400 Subject: [PATCH] Extract common logic for from_str and from_str_radix for `Complex` --- complex/src/lib.rs | 264 ++++++++++++++++++--------------------------- 1 file changed, 103 insertions(+), 161 deletions(-) diff --git a/complex/src/lib.rs b/complex/src/lib.rs index e34b662..a61e420 100644 --- a/complex/src/lib.rs +++ b/complex/src/lib.rs @@ -963,6 +963,91 @@ impl fmt::Binary for Complex where } } +fn from_str_generic(s: &str, from: F) -> Result, ParseComplexError> + where F: Fn(&str) -> Result, T: Clone + Num +{ + let imag = match s.rfind('j') { + None => 'i', + _ => 'j' + }; + + let mut b = String::with_capacity(s.len()); + let mut first = true; + + let char_indices = s.char_indices(); + let mut pc = ' '; + let mut split_index = s.len(); + + for (i, cc) in char_indices { + if cc == '+' && pc != 'e' && pc != 'E' && i > 0 { + // ignore '+' if part of an exponent + if first { + split_index = i; + first = false; + } + // don't carry '+' over into b + pc = ' '; + continue; + } else if cc == '-' && pc != 'e' && pc != 'E' && i > 0 { + // ignore '-' if part of an exponent or begins the string + if first { + split_index = i; + first = false; + } + // DO carry '-' over into b + } + + if pc == '-' && cc == ' ' && !first { + // ignore whitespace between minus sign and next number + continue; + } + + if !first { + b.push(cc); + } + pc = cc; + } + + // split off real and imaginary parts, trim whitespace + let (a, _) = s.split_at(split_index); + let a = a.trim_right(); + let mut b = b.trim_left(); + // input was either pure real or pure imaginary + if b.is_empty() { + b = match a.ends_with(imag) { + false => "0i", + true => "0" + }; + } + + let re; + let im; + if a.ends_with(imag) { + im = a; re = b; + } else if b.ends_with(imag) { + re = a; im = b; + } else { + return Err(ParseComplexError::new()); + } + + // parse re + let re = try!(from(re).map_err(ParseComplexError::from_error)); + + // pop imaginary unit off + let mut im = &im[..im.len()-1]; + // handle im == "i" or im == "-i" + if im.is_empty() || im == "+" { + im = "1"; + } else if im == "-" { + im = "-1"; + } + + // parse im + let im = try!(from(im).map_err(ParseComplexError::from_error)); + + Ok(Complex::new(re, im)) +} + impl FromStr for Complex where T: FromStr + Num + Clone { @@ -971,86 +1056,7 @@ impl FromStr for Complex where /// Parses `a +/- bi`; `ai +/- b`; `a`; or `bi` where `a` and `b` are of type `T` fn from_str(s: &str) -> Result { - let imag = match s.rfind('j') { - None => 'i', - _ => 'j' - }; - - let mut b = String::with_capacity(s.len()); - let mut first = true; - - let char_indices = s.char_indices(); - let mut pc = ' '; - let mut split_index = s.len(); - - for (i, cc) in char_indices { - if cc == '+' && pc != 'e' && pc != 'E' && i > 0 { - // ignore '+' if part of an exponent - if first { - split_index = i; - first = false; - } - // don't carry '+' over into b - pc = ' '; - continue; - } else if cc == '-' && pc != 'e' && pc != 'E' && i > 0 { - // ignore '-' if part of an exponent or begins the string - if first { - split_index = i; - first = false; - } - // DO carry '-' over into b - } - - if pc == '-' && cc == ' ' && !first { - // ignore whitespace between minus sign and next number - continue; - } - - if !first { - b.push(cc); - } - pc = cc; - } - - // split off real and imaginary parts, trim whitespace - let (a, _) = s.split_at(split_index); - let a = a.trim_right(); - let mut b = b.trim_left(); - // input was either pure real or pure imaginary - if b.is_empty() { - b = match a.ends_with(imag) { - false => "0i", - true => "0" - }; - } - - let re; - let im; - if a.ends_with(imag) { - im = a; re = b; - } else if b.ends_with(imag) { - re = a; im = b; - } else { - return Err(ParseComplexError::new()); - } - - // parse re - let re = try!(T::from_str(re).map_err(ParseComplexError::from_error)); - - // pop imaginary unit off - let mut im = &im[..im.len()-1]; - // handle im == "i" or im == "-i" - if im.is_empty() || im == "+" { - im = "1"; - } else if im == "-" { - im = "-1"; - } - - // parse im - let im = try!(T::from_str(im).map_err(ParseComplexError::from_error)); - - Ok(Complex::new(re, im)) + from_str_generic(s, T::from_str) } } @@ -1060,86 +1066,8 @@ impl Num for Complex { /// Parses `a +/- bi`; `ai +/- b`; `a`; or `bi` where `a` and `b` are of type `T` fn from_str_radix(s: &str, radix: u32) -> Result { - let imag = match s.rfind('j') { - None => 'i', - _ => 'j' - }; - - let mut b = String::with_capacity(s.len()); - let mut first = true; - - let char_indices = s.char_indices(); - let mut pc = ' '; - let mut split_index = s.len(); - - for (i, cc) in char_indices { - if cc == '+' && pc != 'e' && pc != 'E' && i > 0 { - // ignore '+' if part of an exponent - if first { - split_index = i; - first = false; - } - // don't carry '+' over into b - pc = ' '; - continue; - } else if cc == '-' && pc != 'e' && pc != 'E' && i > 0 { - // ignore '-' if part of an exponent or begins the string - if first { - split_index = i; - first = false; - } - // DO carry '-' over into b - } - - if pc == '-' && cc == ' ' && !first { - // ignore whitespace between minus sign and next number - continue; - } - - if !first { - b.push(cc); - } - pc = cc; - } - - // split off real and imaginary parts, trim whitespace - let (a, _) = s.split_at(split_index); - let a = a.trim_right(); - let mut b = b.trim_left(); - // input was either pure real or pure imaginary - if b.is_empty() { - b = match a.ends_with(imag) { - false => "0i", - true => "0" - }; - } - - let re; - let im; - if a.ends_with(imag) { - im = a; re = b; - } else if b.ends_with(imag) { - re = a; im = b; - } else { - return Err(ParseComplexError::new()); - } - - // parse re - let re = try!(T::from_str_radix(re, radix).map_err(ParseComplexError::from_error)); - - // pop imaginary unit off - let mut im = &im[..im.len()-1]; - // handle im == "i" or im == "-i" - if im.is_empty() || im == "+" { - im = "1"; - } else if im == "-" { - im = "-1"; - } - - // parse im - let im = try!(T::from_str_radix(im, radix).map_err(ParseComplexError::from_error)); - - Ok(Complex::new(re, im)) + from_str_generic(s, |x| -> Result { + T::from_str_radix(x, radix) }) } } @@ -1228,7 +1156,7 @@ mod test { use std::f64; use std::str::FromStr; - use traits::{Zero, One, Float}; + use traits::{Zero, One, Float, Num}; pub const _0_0i : Complex64 = Complex { re: 0.0, im: 0.0 }; pub const _1_0i : Complex64 = Complex { re: 1.0, im: 0.0 }; @@ -1960,6 +1888,20 @@ mod test { test(_05_05i, "0.05e+1j + 50E-2"); } + #[test] + fn test_from_str_radix() { + fn test(z: Complex64, s: &str, radix: u32) { + let res: Result::FromStrRadixErr> + = Num::from_str_radix(s, radix); + assert_eq!(res.unwrap(), z) + } + test(_4_2i, "4+2i", 10); + test(Complex::new(15.0, 32.0), "F+20i", 16); + test(Complex::new(15.0, 32.0), "1111+100000i", 2); + test(Complex::new(-15.0, -32.0), "-F-20i", 16); + test(Complex::new(-15.0, -32.0), "-1111-100000i", 2); + } + #[test] fn test_from_str_fail() { fn test(s: &str) {