rustgym 0.2.0

rustgym solutions
Documentation
struct Solution;
use std::fmt::{Display, Formatter, Result};

enum Tok {
    Op(char),
    Num(i32),
}

struct Fraction {
    sign: i32,
    numerator: i32,
    denominator: i32,
}

impl Fraction {
    fn new(sign: i32, numerator: i32, denominator: i32) -> Self {
        Fraction {
            sign,
            numerator,
            denominator,
        }
    }
    fn add(self, other: Self) -> Self {
        let mut numerator = self.sign * self.numerator * other.denominator
            + other.sign * other.numerator * self.denominator;
        let denominator = self.denominator * other.denominator;
        let mut sign = 1;
        if numerator < 0 {
            sign *= -1;
            numerator *= -1;
        }
        Fraction {
            sign,
            numerator,
            denominator,
        }
    }
    fn reduce(self) -> Self {
        let sign = self.sign;
        let mut denominator = self.denominator;
        let mut numerator = self.numerator;
        let gcd = gcd(denominator, numerator);
        denominator /= gcd;
        numerator /= gcd;
        Fraction {
            sign,
            numerator,
            denominator,
        }
    }
}

impl Display for Fraction {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        if self.sign > 0 {
            write!(f, "{}/{}", self.numerator, self.denominator)
        } else {
            write!(f, "-{}/{}", self.numerator, self.denominator)
        }
    }
}

fn gcd(mut m: i32, mut n: i32) -> i32 {
    while m != 0 {
        let temp = m;
        m = n % temp;
        n = temp;
    }
    n.abs()
}

impl Solution {
    fn fraction_addition(expression: String) -> String {
        let mut toks: Vec<Tok> = vec![];
        let mut c_it = expression.chars().peekable();
        while let Some(c) = c_it.next() {
            match c {
                '-' | '+' | '/' => {
                    toks.push(Tok::Op(c));
                }
                _ => {
                    let mut val = (c as u8 - b'0') as i32;
                    while let Some(p) = c_it.peek() {
                        if p.is_digit(10) {
                            val *= 10;
                            val += (c_it.next().unwrap() as u8 - b'0') as i32;
                        } else {
                            break;
                        }
                    }
                    toks.push(Tok::Num(val));
                }
            }
        }
        let mut t_it = toks.into_iter().peekable();
        let mut fractions: Vec<Fraction> = vec![];
        while t_it.peek().is_some() {
            let mut sign = 1;
            let numerator;
            let denominator;
            if let Some(Tok::Op('-')) = t_it.peek() {
                t_it.next().unwrap();
                sign = -1;
            }
            if let Some(Tok::Op('+')) = t_it.peek() {
                t_it.next().unwrap();
            }
            if let Tok::Num(x) = t_it.next().unwrap() {
                numerator = x;
            } else {
                panic!();
            }
            if let Tok::Op('/') = t_it.next().unwrap() {
            } else {
                panic!();
            }
            if let Tok::Num(y) = t_it.next().unwrap() {
                denominator = y;
            } else {
                panic!();
            }
            fractions.push(Fraction::new(sign, numerator, denominator));
        }
        while fractions.len() > 1 {
            let a = fractions.pop().unwrap();
            let b = fractions.pop().unwrap();
            let c = a.add(b);
            fractions.push(c);
        }
        let mut res = fractions.pop().unwrap();
        res = res.reduce();
        res.to_string()
    }
}

#[test]
fn test() {
    let expression = "-1/2+1/2".to_string();
    let res = "0/1".to_string();
    assert_eq!(Solution::fraction_addition(expression), res);
    let expression = "-1/2+1/2+1/3".to_string();
    let res = "1/3".to_string();
    assert_eq!(Solution::fraction_addition(expression), res);
    let expression = "1/3-1/2".to_string();
    let res = "-1/6".to_string();
    assert_eq!(Solution::fraction_addition(expression), res);
    let expression = "5/3+1/3".to_string();
    let res = "2/1".to_string();
    assert_eq!(Solution::fraction_addition(expression), res);
}