aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Cargo.lock181
-rw-r--r--Cargo.toml23
-rw-r--r--src/bin/aft-demo.rs35
-rw-r--r--src/bin/aft-head.rs8
-rw-r--r--src/bin/aft.rs105
-rw-r--r--src/lib.rs0
7 files changed, 354 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 81a4762..97a2952 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+target/
+
*.o
*.a
*.pyc
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..80a6d46
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,181 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "aft"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "assert_cmd",
+ "atty",
+ "colored",
+ "tabwriter",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f"
+
+[[package]]
+name = "assert_cmd"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c88b9ca26f9c16ec830350d309397e74ee9abdfd8eb1f71cb6ecc71a3fc818da"
+dependencies = [
+ "doc-comment",
+ "predicates",
+ "predicates-core",
+ "predicates-tree",
+ "wait-timeout",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "colored"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59"
+dependencies = [
+ "atty",
+ "lazy_static",
+ "winapi",
+]
+
+[[package]]
+name = "difference"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
+
+[[package]]
+name = "doc-comment"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
+
+[[package]]
+name = "predicates"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "347a1b6f0b21e636bc9872fb60b83b8e185f6f5516298b8238699f7f9a531030"
+dependencies = [
+ "difference",
+ "predicates-core",
+]
+
+[[package]]
+name = "predicates-core"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178"
+
+[[package]]
+name = "predicates-tree"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124"
+dependencies = [
+ "predicates-core",
+ "treeline",
+]
+
+[[package]]
+name = "regex"
+version = "1.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692"
+dependencies = [
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
+
+[[package]]
+name = "tabwriter"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36205cfc997faadcc4b0b87aaef3fbedafe20d38d4959a7ca6ff803564051111"
+dependencies = [
+ "lazy_static",
+ "regex",
+ "unicode-width",
+]
+
+[[package]]
+name = "treeline"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
+
+[[package]]
+name = "wait-timeout"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..e5428b2
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "aft"
+version = "0.1.0"
+authors = ["Bryan Newbold <bnewbold@robocracy.org>"]
+edition = "2018"
+
+[dependencies]
+#serde_json = "1.0"
+#bstr = "0.2"
+#structopt = "0.3"
+anyhow = "1.0"
+colored = "1.9"
+atty = "0.2"
+tabwriter = { version = "1.2", features = ["ansi_formatting"] }
+
+[dev-dependencies]
+assert_cmd = "1"
+
+[profile.release]
+lto = true
+codegen-units = 1
+opt-level = "z"
+panic = "abort"
diff --git a/src/bin/aft-demo.rs b/src/bin/aft-demo.rs
new file mode 100644
index 0000000..9a680c1
--- /dev/null
+++ b/src/bin/aft-demo.rs
@@ -0,0 +1,35 @@
+
+/*
+ * Writes example aft to stdout
+ */
+
+fn main() {
+
+ /*
+ * Sepal length Sepal width Petal length Petal width Species
+ * 5.1 3.5 1.4 0.2 I. setosa
+ * 4.9 3.0 1.4 0.2 I. setosa
+ * 4.7 3.2 1.3 0.2 I. setosa
+ * 4.6 3.1 1.5 0.2 I. setosa
+ * 5.0 3.6 1.4 0.2 I. setosa
+ */
+
+ // start header
+ print!("\x01");
+
+ // colum names
+ println!("{}", ["Sepal length", "Speal width", "Petal length", "Petal width", "Species"].join("\x1E"));
+
+ // colum types
+ println!("{}", ["float", "float", "float", "float", "str"].join("\x1E"));
+
+ // end header / start table
+ print!("\x02");
+
+ // print rows
+ println!("{}", ["5.1", "3.5", "1.4", "0.2", "I. setosa"].join("\x1E"));
+ println!("{}", ["4.9", "3.0", "1.4", "0.2", "I. setosa"].join("\x1E"));
+ println!("{}", ["4.7", "3.2", "1.3", "0.2", "I. setosa"].join("\x1E"));
+ println!("{}", ["4.6", "3.1", "1.5", "0.2", "I. setosa"].join("\x1E"));
+ println!("{}", ["5.0", "3.6", "1.4", "0.2", "I. setosa"].join("\x1E"));
+}
diff --git a/src/bin/aft-head.rs b/src/bin/aft-head.rs
new file mode 100644
index 0000000..b8c848c
--- /dev/null
+++ b/src/bin/aft-head.rs
@@ -0,0 +1,8 @@
+
+/*
+ * Takes the first n lines of input, passes to stdout.
+ */
+
+fn main() {
+ println!("Hello, world2!");
+}
diff --git a/src/bin/aft.rs b/src/bin/aft.rs
new file mode 100644
index 0000000..0ada921
--- /dev/null
+++ b/src/bin/aft.rs
@@ -0,0 +1,105 @@
+
+/*
+ * Default behavior:
+ *
+ * aft < file.aft
+ * pretty-prints as a table to stdout
+ *
+ * ls | aft | aft-sort
+ * detects non-aft stdin and converts to aft on stdout
+ */
+
+use std::str::FromStr;
+use std::io::{self, Read, Write, BufRead};
+use std::error::Error;
+use colored::*;
+
+#[derive(Debug)]
+enum AftFieldType {
+ Str,
+ Int,
+ Float,
+ Bool,
+ Array,
+ Null,
+ Other(String),
+}
+
+impl FromStr for AftFieldType {
+ type Err = Box<dyn Error>;
+
+ fn from_str(raw: &str) -> Result<AftFieldType, Box<dyn Error>> {
+ match raw {
+ "" => Ok(AftFieldType::Null),
+ "str" => Ok(AftFieldType::Str),
+ "int" | "integer" => Ok(AftFieldType::Int),
+ "float" => Ok(AftFieldType::Float),
+ "bool" | "boolean" => Ok(AftFieldType::Bool),
+ "array" => Ok(AftFieldType::Array),
+ other => Ok(AftFieldType::Other(other.to_string())),
+
+ }
+ }
+}
+
+#[derive(Debug)]
+struct AftHeader {
+ col_names: Vec<String>,
+ col_types: Option<Vec<AftFieldType>>,
+}
+
+fn main() -> Result<(), Box<dyn Error>> {
+
+ let mut stdout = io::stdout();
+ let stdin = io::stdin();
+ let mut stdin = stdin.lock();
+
+ // if we aren't connected to terminal, just pass through
+ if !atty::is(atty::Stream::Stdout) {
+ io::copy(&mut stdin, &mut stdout)?;
+ return Ok(())
+ }
+
+ // read first byte of input to check if we are getting AFT; if not just pass through
+ let mut first_byte = [0; 1];
+ let got = stdin.read(&mut first_byte)?;
+ if got != 1 {
+ panic!("couldn't read a byte from stdin");
+ };
+ if first_byte[0] != 0x01 {
+ stdout.write(&first_byte)?;
+ io::copy(&mut stdin, &mut stdout)?;
+ return Ok(())
+ }
+
+ let mut stdin = io::BufReader::new(stdin);
+ let mut header_bytes = vec![];
+ // TODO: sanity limit on length
+ stdin.read_until(0x02, &mut header_bytes)?;
+ if header_bytes[header_bytes.len()-1] != 0x02 {
+ panic!("expected an AFT header");
+ };
+ let header_string = String::from_utf8_lossy(&header_bytes);
+ let header_rows: Vec<&str> = header_string.splitn(2, "\n").collect();
+ let header = match header_rows.len() {
+ 0 => panic!("expected a header"),
+ 1 => AftHeader {
+ col_names: header_rows[0].split("\x1E").map(|v| v.to_string()).collect(),
+ col_types: None,
+ },
+ _ => AftHeader {
+ col_names: header_rows[0].split("\x1E").map(|v| v.to_string()).collect(),
+ col_types: Some(header_rows[1].split("\x1E").map(|v| AftFieldType::from_str(v)).collect::<Result<Vec<AftFieldType>, Box<dyn Error>>>()?),
+ },
+ };
+
+ let mut tw = tabwriter::TabWriter::new(stdout);
+ writeln!(tw, "{}", header.col_names.join("\t").bold())?;
+ for line in stdin.lines() {
+ let line = line?;
+ writeln!(tw, "{}", line.replace("\x1E", "\t"))?;
+ }
+ tw.flush()?;
+
+ Ok(())
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/lib.rs