mirror of
https://github.com/FliegendeWurst/decimal-code.git
synced 2024-11-27 15:35:54 +00:00
Initial commit
This commit is contained in:
commit
55b870b7b1
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
target
|
23
Cargo.lock
generated
Normal file
23
Cargo.lock
generated
Normal file
@ -0,0 +1,23 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "decimal-code"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "decimal-code"
|
||||
version = "0.1.0"
|
||||
authors = ["FliegendeWurst <2012gdwu@web.de>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
itertools = "0.9.0"
|
166
src/main.rs
Normal file
166
src/main.rs
Normal file
@ -0,0 +1,166 @@
|
||||
use itertools::join;
|
||||
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::{convert::{TryInto, TryFrom}, io::{self, BufRead, stdin}, iter::once};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let args = env::args().skip(1).collect::<Vec<_>>();
|
||||
if args.is_empty() {
|
||||
// batch mode
|
||||
for line in stdin().lock().lines() {
|
||||
let line = line?;
|
||||
let mut parts = line.split_ascii_whitespace();
|
||||
let format = parts.next().ok_or(io::Error::new(io::ErrorKind::Other, "no encoding"))?;
|
||||
let value = parts.next().ok_or(io::Error::new(io::ErrorKind::Other, "no value"))?;
|
||||
let number = match format {
|
||||
"decimal" => parse_decimal(value)?,
|
||||
"bcd" => parse_bcd(value)?,
|
||||
"aiken" => parse_aiken(value)?,
|
||||
"stibitz" => parse_stibitz(value)?,
|
||||
_ => Err("unknown encoding")?
|
||||
};
|
||||
let x = convert(&number);
|
||||
println!("{}\t{}\t{}\t{}", x.0, x.1, x.2, x.3);
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err("too many arguments".into())
|
||||
}
|
||||
}
|
||||
|
||||
fn convert(number: &Decimal) -> (String, String, String, String) {
|
||||
(
|
||||
number.format_decimal(),
|
||||
number.format_bcd(),
|
||||
number.format_aiken(),
|
||||
number.format_stibitz()
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
struct Decimal {
|
||||
digits: Vec<Digit>,
|
||||
digits_fractional: Vec<Digit>
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
enum Digit {
|
||||
Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine
|
||||
}
|
||||
|
||||
use Digit::*;
|
||||
|
||||
impl TryFrom<char> for Digit {
|
||||
type Error = Box<dyn Error>;
|
||||
|
||||
fn try_from(x: char) -> Result<Self, Self::Error> {
|
||||
match x {
|
||||
'0' => Ok(Zero),
|
||||
'1' => Ok(One),
|
||||
'2' => Ok(Two),
|
||||
'3' => Ok(Three),
|
||||
'4' => Ok(Four),
|
||||
'5' => Ok(Five),
|
||||
'6' => Ok(Six),
|
||||
'7' => Ok(Seven),
|
||||
'8' => Ok(Eight),
|
||||
'9' => Ok(Nine),
|
||||
x => Err(format!("unknown digit {:?}", x).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Digit {
|
||||
fn value(&self) -> usize {
|
||||
match self {
|
||||
Zero => 0,
|
||||
One => 1,
|
||||
Two => 2,
|
||||
Three => 3,
|
||||
Four => 4,
|
||||
Five => 5,
|
||||
Six => 6,
|
||||
Seven => 7,
|
||||
Eight => 8,
|
||||
Nine => 9
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_decimal(value: &str) -> Result<Decimal, Box<dyn Error>> {
|
||||
let mut digits = Vec::new();
|
||||
let mut digits_fractional = Vec::new();
|
||||
|
||||
let mut fractional = false;
|
||||
for c in value.chars() {
|
||||
if !fractional && (c == '.' || c == ',') {
|
||||
fractional = true;
|
||||
continue;
|
||||
}
|
||||
let digit: Digit = c.try_into()?;
|
||||
if !fractional {
|
||||
digits.push(digit);
|
||||
} else {
|
||||
digits_fractional.push(digit);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Decimal {
|
||||
digits, digits_fractional
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_decimal_test() {
|
||||
assert_eq!(parse_decimal("42.35").unwrap(), Decimal { digits: vec![Four, Two], digits_fractional: vec![Three, Five] });
|
||||
}
|
||||
|
||||
fn parse_bcd(value: &str) -> Result<Decimal, Box<dyn Error>> {
|
||||
todo!("BCD parsing");
|
||||
}
|
||||
|
||||
fn parse_aiken(value: &str) -> Result<Decimal, Box<dyn Error>> {
|
||||
todo!("AIKEN parsing");
|
||||
}
|
||||
|
||||
fn parse_stibitz(value: &str) -> Result<Decimal, Box<dyn Error>> {
|
||||
todo!("STIBITZ parsing");
|
||||
}
|
||||
|
||||
impl Decimal {
|
||||
fn format_decimal(&self) -> String {
|
||||
self.format_specified(&["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"])
|
||||
}
|
||||
|
||||
fn format_bcd(&self) -> String {
|
||||
self.format_specified(&["0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001"])
|
||||
}
|
||||
|
||||
fn format_aiken(&self) -> String {
|
||||
self.format_specified(&["0000", "0001", "0010", "0011", "0100", "1011", "1100", "1101", "1110", "1111"])
|
||||
}
|
||||
|
||||
fn format_stibitz(&self) -> String {
|
||||
self.format_specified(&["0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100"])
|
||||
}
|
||||
|
||||
fn format_specified(&self, table: &[&str]) -> String {
|
||||
if self.digits_fractional.is_empty() {
|
||||
join(self.digits.iter().map(|x| table[x.value()]), " ")
|
||||
} else {
|
||||
join(
|
||||
self.digits.iter().map(|x| table[x.value()])
|
||||
.chain(once("."))
|
||||
.chain(self.digits_fractional.iter().map(|x| table[x.value()])),
|
||||
" "
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_decimal_test() {
|
||||
let number = Decimal { digits: vec![Four, Four], digits_fractional: vec![Five, One] };
|
||||
assert_eq!(convert(&number), ("4 4 . 5 1".into(), "0100 0100 . 0101 0001".into(), "0100 0100 . 1011 0001".into(), "0111 0111 . 1000 0100".into()));
|
||||
}
|
Loading…
Reference in New Issue
Block a user