commit 86cd00512ab43cd9879bd81ae747d25259bfcac5 Author: Wroclaw Date: Mon Jul 22 23:08:18 2024 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4ecd467 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,96 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "binary_braillie" +version = "0.1.0" +dependencies = [ + "hex", + "num", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e22b480 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "binary_braillie" +version = "0.1.0" +edition = "2021" + +[dependencies] +hex = "0.4.3" +num = "0.4.3" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..67f22f4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Rafał (Wroclaw) F. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d85b0ba --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# Binary braillie + +Command line tool and API to convert bytes to binary represented in unicode braillie + +it supports how bits should be placed in character, and command line tool supports reversing the input. diff --git a/package.nix b/package.nix new file mode 100644 index 0000000..bbcff35 --- /dev/null +++ b/package.nix @@ -0,0 +1,7 @@ +{ rustPackages }: + +rustPackages.rustPlatform.buildRustPackage { + name = "binary-braillie"; + src = ./.; + cargoSha256 = "sha256-7sbI+bgsI8tTYrV/IZa69eHEc19Mbrk/qh3+9SJ3sGU="; +} diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..870a039 --- /dev/null +++ b/shell.nix @@ -0,0 +1,12 @@ +{ pkgs ? import {} }: + +pkgs.mkShell { + buildInputs = with pkgs; [ + cargo + rustc + rustfmt + ]; + + RUST_BACKTRACE = 1; + RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}"; +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..25149a1 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,148 @@ +/* + 0 3 + 1 4 + 2 5 + 6 7 +*/ + +use std::u32; +use std::convert::TryFrom; + + +#[derive(Clone, Copy)] +#[repr(u8)] +pub enum EncodeOrientation { + // reverse - points in line ordered backwards (direction) + // Backwards - major lines ordered backwards (wrap) + Rows = 0b00000000, + RowsBackwards = 0b00000001, + RowsReverse = 0b00000010, + RowsBackwardsReverse = 0b00000011, + Columns = 0b00000100, + ColumnsBackwards = 0b00000101, + ColumnsReverse = 0b00000110, + ColumnsBackwardsReverse = 0b00000111, +} + +impl TryFrom for EncodeOrientation { + + type Error = (); + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(EncodeOrientation::Rows), + 1 => Ok(EncodeOrientation::RowsBackwards), + 2 => Ok(EncodeOrientation::RowsReverse), + 3 => Ok(EncodeOrientation::RowsBackwardsReverse), + 4 => Ok(EncodeOrientation::Columns), + 5 => Ok(EncodeOrientation::ColumnsBackwards), + 6 => Ok(EncodeOrientation::ColumnsReverse), + 7 => Ok(EncodeOrientation::ColumnsBackwardsReverse), + _ => panic!("Unknown encode orientation provided") + } + } +} + + +const MAPPINGS: [[u8; 8]; 8] = [ + [0, 3, 1, 4, 2, 5, 6, 7], + [6, 7, 2, 5, 1, 4, 0, 3], + [3, 0, 4, 1, 5, 2, 7, 6], + [7, 6, 5, 2, 4, 1, 3, 0], + [0, 1, 2, 6, 3, 4, 5, 7], + [3, 4, 5, 7, 0, 1, 2, 6], + [6, 2, 1, 0, 7, 5, 4, 3], + [7, 5, 4, 3, 6, 2, 1, 0] +]; + +pub fn index_to_braillie_char(_index: u8, mode: EncodeOrientation) -> char { + let mapping = MAPPINGS[mode as usize]; + let index: u8 = + ((_index >> 7) & 1) << mapping[0] + | ((_index >> 6) & 1) << mapping[1] + | ((_index >> 5) & 1) << mapping[2] + | ((_index >> 4) & 1) << mapping[3] + | ((_index >> 3) & 1) << mapping[4] + | ((_index >> 2) & 1) << mapping[5] + | ((_index >> 1) & 1) << mapping[6] + | ((_index >> 0) & 1) << mapping[7]; + return char::from_u32(0x2800 + index as u32).unwrap(); +} + +pub fn to_binary_braillie(input: &[u8], length: usize, mode: EncodeOrientation) -> String { + let mut rvalue = String::with_capacity(length); + for i in 0..length { + rvalue.push(index_to_braillie_char(input[i], mode)); + } + return rvalue; +} + +pub fn to_binary_braillie_str(input: impl AsRef, mode: EncodeOrientation) -> String { + return to_binary_braillie(input.as_ref().as_bytes(), input.as_ref().len(), mode); +} + + +#[cfg(test)] +mod test_lib { + use crate::{index_to_braillie_char, to_binary_braillie_str, EncodeOrientation}; + + #[test] + fn check_characters_in_range() { + for i in 0..0xff { + let char = index_to_braillie_char(i, EncodeOrientation::Rows); + assert!(0x2800 <= char as u32 && char as u32 <= 0x28ff); + } + } + + #[test] + fn check_individual_bits() { + assert_eq!( + index_to_braillie_char(0b10000000, EncodeOrientation::Rows), + char::from_u32(0x2800 + 0b00000001).unwrap() + ); + assert_eq!( + index_to_braillie_char(0b01000000, EncodeOrientation::Rows), + char::from_u32(0x2800 + 0b00001000).unwrap() + ); + assert_eq!( + index_to_braillie_char(0b00100000, EncodeOrientation::Rows), + char::from_u32(0x2800 + 0b00000010).unwrap() + ); + assert_eq!( + index_to_braillie_char(0b00010000, EncodeOrientation::Rows), + char::from_u32(0x2800 + 0b00010000).unwrap() + ); + assert_eq!( + index_to_braillie_char(0b00001000, EncodeOrientation::Rows), + char::from_u32(0x2800 + 0b00000100).unwrap() + ); + assert_eq!( + index_to_braillie_char(0b00000100, EncodeOrientation::Rows), + char::from_u32(0x2800 + 0b00100000).unwrap() + ); + assert_eq!( + index_to_braillie_char(0b00000010, EncodeOrientation::Rows), + char::from_u32(0x2800 + 0b01000000).unwrap() + ); + assert_eq!( + index_to_braillie_char(0b00000001, EncodeOrientation::Rows), + char::from_u32(0x2800 + 0b10000000).unwrap() + ); + } + + #[test] + fn check_some_strings() { + assert_eq!( + to_binary_braillie_str("Hi", EncodeOrientation::Rows), + "⠌⢎" + ); + assert_eq!( + to_binary_braillie_str("Hello, world!", EncodeOrientation::Rows), + "⠌⢪⠮⠮⣮⠦⠂⣺⣮⡚⠮⠪⢂" + ); + assert_eq!( + to_binary_braillie_str("ąęćó", EncodeOrientation::Rows), + "⠩⢡⠩⢕⠩⣡⣉⣓" + ); + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..4922e17 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,112 @@ +use std::env; +use std::process::exit; + +use binary_braillie::to_binary_braillie; + +fn main() { + let args = parse_args(); + if args.value_to_convert.len() <= 0 { + print!("{}: No input specified!", args.program_name) + } + let mut value: Vec = if !args.hexadecimal { + Vec::from(args.value_to_convert.as_bytes()) + } + else { + Vec::from(hex::decode(args.value_to_convert).unwrap_or_else( + |_e_| { + print!("{}: Invalid hex provided", args.program_name); + exit(128); + }) + )}; + + if args.reverse_characters { value.reverse(); } + + print!("{}", to_binary_braillie(&value, value.len(), args.mode.try_into().unwrap())) +} + +struct Arguments { + pub hexadecimal: bool, + pub mode: u8, + pub program_name: String, + pub reverse_characters: bool, + pub value_to_convert: String, +} + +fn parse_args() -> Arguments { + let mut args = env::args().peekable(); + let mut rvalue = Arguments { + hexadecimal: false, + mode: 0, + program_name: args.next().unwrap_or(String::from("t2br")), + reverse_characters: false, + value_to_convert: String::new(), + }; + let program_name = &rvalue.program_name; + + while args.peek() != None { + let arg = args.next().unwrap(); + + if arg == "--help" + || arg == "-h" + || arg == "-?" + { + print_help(rvalue.program_name); + exit(1); + } + else if arg == "--hex" { + rvalue.hexadecimal = true; + } + else if arg == "--direction" { + let direction = args.next().unwrap_or_else(|| { + println!("{}: argument for {} was not provided", program_name, arg); + exit(64); + }); + match direction.as_str() { + "row" => { rvalue.mode &= !(1 << 1) ; rvalue.mode &= !(1 << 2); } + "row-reverse" => { rvalue.mode |= 1 << 1 ; rvalue.mode &= !(1 << 2); } + "column" => { rvalue.mode &= !(1 << 1) ; rvalue.mode |= 1 << 2 ; } + "column-reverse" => { rvalue.mode |= 1 << 1 ; rvalue.mode |= 1 << 2 ; } + _ => { + println!("{}: invalid direction \"{}\" provided", program_name, direction); + exit(65); + } + } + } + else if arg == "--wrap" { + let wrap = args.next().unwrap_or_else(|| { + println!("{}: argument for {} was not provided", program_name, arg); + exit(64); + }); + match wrap.as_str() { + "normal" => rvalue.mode &= !(1 << 0), + "reverse" => rvalue.mode |= 1 << 0, + _ => { + println!("{}: invalid wrap \"{}\" provided", program_name, wrap); + exit(65); + } + } + } + else if arg == "-r" + || arg == "--reverse" { + rvalue.reverse_characters = true; + } + else { + if rvalue.value_to_convert.len() > 0 { rvalue.value_to_convert.push(' '); }; + rvalue.value_to_convert.push_str(&arg); + } + } + + return rvalue; +} + +fn print_help(program_name: String) { + print!("Usage: {program_name} [options] \n"); + print!("Convert input to binary represented in braillie characters\n\n"); + print!(" --hex convert hexadecimal to braillie represented binary\n\n"); + print!(" --direction [mode] direction of bits per character\n"); + print!(" possible values: row, row-reverse, column, column-reverse\n\n"); + print!(" --wrap [mode] direction of bits wrapping per character\n"); + print!(" possible values: normal, reverse\n\n"); + print!(" -r, --reverse reverse outputted characters\n\n"); + print!(" -h, -?, --help display this help and exit"); +}