This is a Rust port of JS-quantities.
use std::fmt;
use std::io;
use Temperature::*;

#[derive(Debug, PartialEq, Copy, Clone)]
/**
  An enum representing the different Temperature scales.
  These are the available temperature scales to be converted with this script.
  */

pub enum Temperature {
    Kelvin(f64),
    Celsius(f64),
    Fahrenheit(f64),
    Rankine(f64),
}

impl fmt::Display for Temperature {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Kelvin(k)     => write!(fmtr, "{}K", k),
            Celsius(c)    => write!(fmtr, "{}°C", c),
            Fahrenheit(f) => write!(fmtr, "{}°F", f),
            Rankine(r)    => write!(fmtr, "{}°R", r),
        }
    }
}

impl Temperature {
    /// Convert the Temperature unit into Celsius
    pub fn to_celsius(self) -> Temperature {
        match self {
            Kelvin(k)      => Celsius(k - 273.15),
            c @ Celsius(_) => c,
            Fahrenheit(f)  => Celsius((f - 32.0) * (5.0 / 9.0)),
            Rankine(r)     => Celsius((r - 491.67) * 5.0 / 9.0),
        }
    }

    /// Convert the Temperature unit into Fahrenheit
    pub fn to_fahrenheit(self) -> Temperature {
        match self {
            Kelvin(k)         => Fahrenheit((k * (9.0 / 5.0)) - 459.67),
            Celsius(c)        => Fahrenheit((c * (9.0 / 5.0)) + 32.0),
            f @ Fahrenheit(_) => f,
            Rankine(r)        => Fahrenheit(r - 459.67),
        }
    }

    /// Convert the Temperature unit into Kelvin
    pub fn to_kelvin(self) -> Temperature {
        match self {
            k @ Kelvin(_) => k,
            Celsius(c)    => Kelvin(c + 273.15),
            Fahrenheit(f) => Kelvin((f + 459.67) * (5.0 / 9.0)),
            Rankine(r)    => Kelvin(r * 5.0 / 9.0),
        }
    }

    /// Convert the Temperature unit into Rankine
    pub fn to_rankine(self) -> Temperature {
        match self {
            r @ Rankine(_) => r,
            Celsius(c)     => Rankine((c + 273.15) * 9.0 / 5.0),
            Fahrenheit(f)  => Rankine(f + 459.67),
            Kelvin(k)      => Rankine(k * 9.0 / 5.0),
        }
    }
}

/**
# Temperature Conversion Formulas.
These are the formulas used in the crate for temperature conversions.

| From       | To         | Formula                      | Notes |
| ---------- | ---------- | ---------------------------- | ----- |
| Celsius    | Rankine    | R = (C + 273.15) * 9.0 / 5.0 |       |
| Celsius    | Kelvin     | K = C + 273.15               |       |
| Celsius    | Fahrenheit | F = (C * 9.0 / 5.0) + 32.0   |       |
| Fahrenheit | Rankine    | R = F + 459.67               |       |
| Fahrenheit | Kelvin     | K = (F + 459.67) * 5.0 / 9.0 |       |
| Fahrenheit | Celsius    | C = (F - 32.0) * 5.0 / 9.0   |       |
| Kelvin     | Rankine    | R = K * 9.0 / 5.0            |       |
| Kelvin     | Fahrenheit | F = K * 9.0 / 5.0 - 459.67   |       |
| Kelvin     | Celsius    | C = K - 273.15               |       |
| Rankine    | Kelvin     | K = R * 5.0 / 9.0            |       |
| Rankine    | Fahrenheit | F = R - 459.67               |       |
| Rankine    | Celsius    | C = (R - 491.67) * 5.0 / 9.0 |       |

# Memo:
The only temperature where the Kelvin and Fahrenheit values are equal is at 574.59.
The only temperature where the Celsius and Fahrenheit values are equal is at -40.
*/

pub fn convert_temp(temperature: &Temperature) -> f64 {
    match *temperature {
        Fahrenheit(degrees) => {
            (degrees - 32.0) / 1.8
        },
        Fahrenheit(degrees) => {
            ((degrees - 32.0) / 1.8) + 273.15
        },
        Fahrenheit(degrees) => {
            degrees + 456.67
        },
        Celsius(degrees)    => {
            (degrees * 1.8) + 32.0
        },
        Celsius(degrees)    => {
            degrees + 273.15
        },
        Celsius(degrees)    => {
            (degrees + 273.15) * 9.0 / 5.0
        },
        Kelvin(degrees)     => {
            degrees - 273.15
        },
        Kelvin(degrees)     => {
            ((degrees - 273.15) * 1.8) + 32.0
        },
        Kelvin(degrees)     => {
            degrees * 9.0 / 5.0
        },
        Rankine(degrees)    => {
            (degrees - 491.67) * 5.0 / 9.0
        },
        Rankine(degrees)    => {
            degrees * 9.0 / 5.0 - 459.67
        },
        Rankine(degrees)    => {
            degrees * 5.0 / 9.0
        },
    }
}

/**
# Print the final converted temp scale
This will print the converted temperature into the temperature scale the user has requested.
*/
pub fn print_temp(temperature: &Temperature) {
    match *temperature {
        Fahrenheit(degrees) => {
            println!("{}F = {}C", degrees, convert_temp(temperature))
        }
        Fahrenheit(degrees) => {
            println!("{}F = {}K", degrees, convert_temp(temperature))
        }
        Fahrenheit(degrees) => {
            println!("{}F = {}R", degrees, convert_temp(temperature))
        }
        Celsius(degrees) => {
            println!("{}C = {}F", degrees, convert_temp(temperature))
        },
        Celsius(degrees) => {
            println!("{}C = {}K", degrees, convert_temp(temperature))
        },
        Celsius(degrees) => {
            println!("{}C = {}R", degrees, convert_temp(temperature))
        },
        Kelvin(degrees)  => {
            println!("{}K = {}C", degrees, convert_temp(temperature))
        },
        Kelvin(degrees)  => {
            println!("{}K = {}F", degrees, convert_temp(temperature))
        },
        Kelvin(degrees)  => {
            println!("{}K = {}R", degrees, convert_temp(temperature))
        },
        Rankine(degrees) => {
            println!("{}R = {}C", degrees, convert_temp(temperature))
        },
        Rankine(degrees) => {
            println!("{}R = {}F", degrees, convert_temp(temperature))
        },
        Rankine(degrees) => {
            println!("{}R = {}K", degrees, convert_temp(temperature))
        },
    }
}

/**
# Get the user input
Add a question to allow the user to specify which scale the temperature should be converted
into.
*/

pub fn get_user_temp() {
    println!("\nType \"exit\" to exit the program");

    loop {
        let mut temp_input = String::new();

        println!(
            "\nPlease input a temperature you want to convert (Example: 10R, 10F, 10K, or \
            -10C):"
            );

        io::stdin()
            .read_line(&mut temp_input)
            .expect("Failed to read line");

        let trimmed = temp_input.trim();

        if trimmed == "exit" {
            break;
        }

        let (temp, scale) = trimmed.split_at(trimmed.len() - 1);

        let temp: f64 = match temp.parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        let temp: Temperature = match scale {
            "C" => Celsius(temp),
            "F" => Fahrenheit(temp),
            "K" => Kelvin(temp),
            "R" => Rankine(temp),
            _ => continue,
        };

        print_temp(&temp);
    }
}

fn main() {
    println!("This is a temperature converter!\n");

    get_user_temp();
}