adds basic parser for complex numbers in Cartesian form

This commit is contained in:
Alan Liddell 2017-07-10 05:57:38 -04:00
parent 31fa9f626a
commit 3c490cdee4
1 changed files with 121 additions and 18 deletions

View File

@ -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};