bullet 0.1.2

Supersonic Math
Documentation
use node::Node;
use poly::{Poly, cmp_base};
use itertools::Itertools;
use std::fmt::{self, Display};

fn int_super(i: i64) -> String {
    i.to_string().chars().map(|c| {
        match c {
            '-' => '',
            '0' => '',
            '1' => '¹',
            '2' => '²',
            '3' => '³',
            '4' => '',
            '5' => '',
            '6' => '',
            '7' => '',
            '8' => '',
            '9' => '',
            _ => unreachable!()
        }
    }).collect()
}

pub struct Tokens {
    content: Vec<String>
}
impl Display for Tokens {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut iter = self.content.iter();
        if let Some(first) = iter.next() {
            f.write_str(&first)?;
            for s in iter {
                f.write_str(" ")?;
                f.write_str(&s)?;
            }
        }
        Ok(())
    }
}
fn wrap_poly(p: &Poly) -> String {
    let tokens = Tokens::poly(p);
    if tokens.len() > 1 {
        format!("({})", tokens)
    } else {
        tokens.to_string()
    }
}

impl Tokens {
    pub fn new() -> Tokens {
        Tokens { content: vec![] }
    }
    pub fn len(&self) -> usize {
        self.content.len()
    }
    pub fn push<T: fmt::Display>(&mut self, t: T) {
        self.content.push(t.to_string());
    }
    pub fn poly(p: &Poly) -> Tokens {
        let mut tokens = Tokens::new();
        let mut elements: Vec<_> = p.factors().collect();
        elements.sort_by(|a, b| cmp_base(&a.0, &b.0));

        for (n, &(base, fac)) in elements.iter().enumerate() {
            let (nom, denom) = fac.frac();

            if nom < 0 {
                tokens.push("-");
            } else if n != 0 {
                tokens.push("+");
            }
            if nom.abs() != 1 || base.len() == 0 {
                tokens.push(nom.abs());
            }

            for &(ref v, n) in base.iter() {
                let v = match **v {
                    Node::Poly(ref p) => wrap_poly(p),
                    ref n => Tokens::node(n).to_string()
                };
                if n == 1 {
                    tokens.push(v);
                } else {
                    tokens.push(format!("{}{}", v, int_super(n)));
                }
            }

            match denom {
                1 => {},
                d => {
                    tokens.push("/");
                    tokens.push(d);
                }
            }
        }
        if tokens.len() == 0 {
            tokens.push("0");
        }
        tokens
    }
    pub fn node(n: &Node) -> Tokens {
        let mut tokens = Tokens::new();
        match *n {
            Node::Op(ref f) => tokens.push(f),
            Node::Apply(ref f, ref g) => tokens.push(format!("{}({})", Tokens::node(f), Tokens::node(g))),
            Node::Poly(ref p) => {
                match p.factorize() {
                    Some((p, q)) => {
                        tokens.push(wrap_poly(&p));
                        tokens.push(wrap_poly(&q));
                    },
                    None => tokens.push(Tokens::poly(p))
                }
            }
            Node::Var(ref name) => tokens.push(name),
            Node::Tuple(ref parts) => tokens.push(format!("({})", parts.iter().map(|n| Tokens::node(n)).join(", "))),
        }
        tokens
    }
}