adds basic parser for complex numbers in Cartesian form
This commit is contained in:
parent
31fa9f626a
commit
3c490cdee4
|
@ -22,10 +22,12 @@ extern crate rustc_serialize;
|
|||
#[cfg(feature = "serde")]
|
||||
extern crate serde;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
#[cfg(test)]
|
||||
use std::hash;
|
||||
use std::ops::{Add, Div, Mul, Neg, Sub};
|
||||
use std::str::FromStr;
|
||||
|
||||
use traits::{Zero, One, Num, Float};
|
||||
|
||||
|
@ -740,6 +742,77 @@ impl<T> fmt::Binary for Complex<T> where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> FromStr for Complex<T> where
|
||||
T: FromStr + Num + PartialOrd + Clone
|
||||
{
|
||||
type Err = ParseComplexError;
|
||||
|
||||
/// Parses `a +/- bi`; `ai +/- b`; `a`; or `bi` where `a` and `b` are of type `T`
|
||||
fn from_str(s: &str) -> Result<Complex<T>, ParseComplexError>
|
||||
{
|
||||
// first try to split on " + "
|
||||
let mut split_p = s.splitn(2, " + ");
|
||||
|
||||
let mut a = match split_p.next() {
|
||||
None => return Err(ParseComplexError { kind: ComplexErrorKind::ParseError }),
|
||||
Some(s) => s.to_string()
|
||||
};
|
||||
|
||||
let mut b = match split_p.next() {
|
||||
// no second item could mean we need to split on " - " instead
|
||||
None => {
|
||||
let mut split_m = s.splitn(2, " - ");
|
||||
|
||||
a = match split_m.next() {
|
||||
None => return Err(ParseComplexError { kind: ComplexErrorKind::ParseError }),
|
||||
Some(s) => s.to_string()
|
||||
};
|
||||
|
||||
let c = match split_m.next() {
|
||||
None => {
|
||||
// if `a` is imaginary, let `b` be real (and vice versa)
|
||||
match a.rfind('i') {
|
||||
None => "0i".to_string(),
|
||||
Some(u) => "0".to_string()
|
||||
}
|
||||
}
|
||||
Some(s) => {
|
||||
"-".to_string() + s
|
||||
}
|
||||
};
|
||||
c
|
||||
},
|
||||
Some(s) => s.to_string()
|
||||
};
|
||||
|
||||
let re = match a.rfind('i') {
|
||||
None => {
|
||||
try!(T::from_str(&a)
|
||||
.map_err(|_| ParseComplexError { kind: ComplexErrorKind::ParseError }))
|
||||
},
|
||||
Some(u) => {
|
||||
try!(T::from_str(&b)
|
||||
.map_err(|_| ParseComplexError { kind: ComplexErrorKind::ParseError }))
|
||||
}
|
||||
};
|
||||
|
||||
let im = match a.rfind('i') {
|
||||
None => {
|
||||
b.pop();
|
||||
try!(T::from_str(&b)
|
||||
.map_err(|_| ParseComplexError { kind: ComplexErrorKind::ParseError }))
|
||||
},
|
||||
Some(u) => {
|
||||
a.pop();
|
||||
try!(T::from_str(&a)
|
||||
.map_err(|_| ParseComplexError { kind: ComplexErrorKind::ParseError }))
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Complex::new(re, im))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<T> serde::Serialize for Complex<T>
|
||||
where T: serde::Serialize
|
||||
|
@ -763,6 +836,36 @@ impl<T> serde::Deserialize for Complex<T> where
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct ParseComplexError {
|
||||
kind: ComplexErrorKind,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
enum ComplexErrorKind {
|
||||
ParseError,
|
||||
}
|
||||
|
||||
impl Error for ParseComplexError {
|
||||
fn description(&self) -> &str {
|
||||
self.kind.description()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ParseComplexError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.description().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl ComplexErrorKind {
|
||||
fn description(&self) -> &'static str {
|
||||
match *self {
|
||||
ComplexErrorKind::ParseError => "failed to parse complex number",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn hash<T: hash::Hash>(x: &T) -> u64 {
|
||||
use std::hash::{BuildHasher, Hasher};
|
||||
|
|
Loading…
Reference in New Issue