commit f16bf876e254e166e5ebcbb80b68e865aa5f8c8e Author: Avril Date: Tue Dec 29 23:40:43 2020 +0000 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e2a3069 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +*~ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..a671b8e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,14 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "units" +version = "0.1.0" +dependencies = [ + "lazy_static", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..571d149 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "units" +version = "0.1.0" +authors = ["Avril "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +lazy_static = "1.4.0" diff --git a/src/arg.rs b/src/arg.rs new file mode 100644 index 0000000..8d20390 --- /dev/null +++ b/src/arg.rs @@ -0,0 +1,62 @@ +use std::{fmt, error}; + +pub fn prog_name() -> &'static str +{ + lazy_static! { + static ref NAME: String = std::env::args().next().unwrap(); + } + + &NAME[..] +} + +/// Print usage then exit with error code `0`. +pub fn usage() -> ! +{ + println!("Unit conversion v{}", env!("CARGO_PKG_VERSION")); + println!(" by {} with <3 (license GPL3+)", env!("CARGO_PKG_AUTHORS")); + println!(); + println!("usage: {} ", prog_name()); + println!("usage: {} --help", prog_name()); + println!(); + //TODO: generalise units + println!(r#"Units: + BYTES\t\tConvert byte unit into single bytes"#); + std::process::exit(0) +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum Operation +{ + Help, + Convert(String, String), +} + +#[inline] pub fn parse_args() -> Result +{ + parse(std::env::args().skip(1)) +} + +fn parse>(from: impl IntoIterator) -> Result +{ + let mut from = from.into_iter().map(Into::into); + + let first = from.next().ok_or(ArgParseError)?; + match first.to_lowercase().trim() { + "--help" => Ok(Operation::Help), + _ => { + Ok(Operation::Convert(first, from.next().ok_or(ArgParseError)?)) + }, + } +} + +#[derive(Debug)] +pub struct ArgParseError; + +impl error::Error for ArgParseError{} +impl fmt::Display for ArgParseError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "Failed to parse args. Try passing `--help`.") + } +} diff --git a/src/conv/bytes.rs b/src/conv/bytes.rs new file mode 100644 index 0000000..040cf9d --- /dev/null +++ b/src/conv/bytes.rs @@ -0,0 +1,16 @@ +use super::*; + +#[derive(Debug)] +pub struct Bytes; + +impl Conversion for Bytes +{ + const UNIT: &'static str = "bytes"; + + type Output = u64; + + fn convert(&self, input: &str) -> Result + { + + } +} diff --git a/src/conv/mod.rs b/src/conv/mod.rs new file mode 100644 index 0000000..fc7c2e5 --- /dev/null +++ b/src/conv/mod.rs @@ -0,0 +1,46 @@ +use std::error; +use std::fmt; +use std::convert::Infallible; + +pub mod bytes; + +pub trait Conversion +{ + const UNIT: &'static str; + + type Output: fmt::Display; + type Error: Into = ConversionError; + + fn convert(&self, input: &str) -> Result; +} + +#[derive(Debug)] +pub struct ConversionError(String); + +impl error::Error for ConversionError{} +impl fmt::Display for ConversionError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "conversion failed: {}", self.0) + } +} + +impl From for ConversionError +{ + fn from(from: Infallible) -> Self + { + match from {} + } +} + +/// Dispatch a conversion of `value` for type `unit` and print the result to stdout. +pub fn dispatch_out(unit: impl AsRef, value: impl AsRef) -> Result<(), ConversionError> +{ + match unit.as_ref() { + bytes::Bytes::UNIT => println!("{}", bytes::Bytes.convert(value.as_ref())?), + name => return Err(ConversionError(format!("Unknown unit {}", name))), + } + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..3951461 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,29 @@ +#![feature(associated_type_defaults)] + +#[macro_use] extern crate lazy_static; + +#[macro_export] macro_rules! unwrap { + ($err:expr) => { + match $err { + Ok(v) => v, + Err(e) => { + eprintln!("Error: {}", e); + std::process::exit(1); + } + } + }; +} + +mod arg; + +mod conv; + +fn main() { + use arg::Operation; + match unwrap!(arg::parse_args()) { + Operation::Help => arg::usage(), + Operation::Convert(unit, from) => { + unwrap!(conv::dispatch(unit, from)); + }, + } +}