use itertools::Itertools;
use clap;
use std::io::{BufRead, Write, BufWriter,};
use std::ptr;
use std::borrow::Cow;
use super::Joinkit;
#[derive(Debug, PartialEq, Eq,)]
pub enum DataType {
I,
U,
S,
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum VarData {
I(i64),
U(u64),
S(String),
}
pub fn rec_sep_as_byte(rec_str: &str) -> Result<u8, clap::Error> {
let bytes = rec_str.as_bytes();
if bytes.len() == 1 {
return Ok(bytes[0]);
} else {
let e = clap::Error {message: "Error: input record separator must be encodable to 1 byte \
exactly!".to_owned(),
kind: clap::ErrorKind::ValueValidation,
info: None};
return Err(e);
}
}
pub fn fields_to_idx(f: Vec<&str>) -> Result<Vec<(usize, isize, DataType)>, clap::Error> {
let mut idx: Vec<(usize, isize, DataType)> = Vec::new();
let it = f.iter()
.enumerate()
.flat_map(|(i0, s)| s.split('-')
.enumerate()
.take(2)
.map(move |(i1, s)| (i0, i1, s)));
for (i0, i1, s) in it {
if i1 == 0 {
match s.parse::<usize>() {
Ok(u) => idx.push((u - 1, i0 as isize, DataType::S)),
Err(_) => return Err(clap::Error {message: "Error: could not parse integer fields!".to_owned(),
kind: clap::ErrorKind::ValueValidation,
info: None}),
}
} else { let dt = match s {
"i" => DataType::I,
"u" => DataType::U,
_ => return Err(clap::Error {message: format!("Error: '{}' is not a valid data type!", s),
kind: clap::ErrorKind::ValueValidation,
info: None}),
};
unsafe {
idx.get_unchecked_mut(i0).2 = dt;
}
}
}
idx.sort_by(|a, b| a.0.cmp(&b.0));
{
let mut it = idx.iter();
let mut previous = match it.next() {
Some(t) => t,
None => {
let e = clap::Error {message: "Error: at least one key field expected!".to_owned(),
kind: clap::ErrorKind::ValueValidation,
info: None};
return Err(e);
},
};
for current in it {
if previous.0 == current.0 {
let e = clap::Error {message: "Error: the key fields must be unique!".to_owned(),
kind: clap::ErrorKind::ValueValidation,
info: None};
return Err(e);
}
previous = current;
}
}
Ok(idx)
}
pub unsafe fn extract_key(record: &str,
field_sep: &str,
key_idx: &[(usize, isize, DataType)]) -> Vec<VarData> {
let keys_len = key_idx.len();
let mut keys: Vec<VarData> = Vec::with_capacity(keys_len);
let mut actual_len = 0usize;
{
let ptr = keys.as_mut_ptr();
let key_idx_it = key_idx.iter();
let key_fields_it = record.split(field_sep)
.enumerate()
.merge_join_inner_by(key_idx_it, |l, r| Ord::cmp(&l.0, &r.0));
for ((_, k), &(_, i, ref dt)) in key_fields_it {
let data = match dt {
&DataType::I => {
VarData::I(k.parse::<i64>()
.expect(&format!("Error while parsing the \
key number {}: the value '{}' \
cannot be converted into 'i64'", k,
i + 1)))
}
&DataType::U => {
VarData::U(k.parse::<u64>()
.expect(&format!("Error while parsing the \
key number {}: the value '{}' \
cannot be converted into 'u64'", k,
i + 1)))
}
&DataType::S => VarData::S(k.to_owned()),
};
ptr::write(ptr.offset(i), data);
actual_len += 1;
keys.set_len(actual_len);
}
if actual_len != keys_len {
panic!("Error during the key extraction: the key index exceeds the number of fields
in the record!");
}
}
keys
}
pub unsafe fn extract_key_value<'a, C>(record: C,
field_sep: &str,
key_idx: &[(usize, isize, DataType)]) -> (Vec<VarData>, Cow<'a, str>)
where C: Into<Cow<'a, str>>,
{
let record = record.into();
let key = extract_key(&record, field_sep, key_idx);
(key, record)
}
pub fn num_fields(record: &str,
field_sep: &str,) -> usize {
record.split(field_sep).count()
}
pub fn write_both<W: Write>(stream: &mut BufWriter<W>, lv: &str, rv: &str, fs: &[u8], rs: &[u8]) {
stream.write(lv.as_bytes()).expect("Error: could not write into output stream!");
stream.write(fs).expect("Error: could not write into output stream!");
stream.write(rv.as_bytes()).expect("Error: could not write into output stream!");
stream.write(rs).expect("Error: could not write into output stream!");
}
pub fn write_left<W: Write>(stream: &mut BufWriter<W>, lv: &str, r_len: usize, fs: &[u8], rs: &[u8]) {
stream.write(lv.as_bytes()).expect("Error: could not write into output stream!");
for _ in 0..r_len {
stream.write(fs).expect("Error: could not write into output stream!");
}
stream.write(rs).expect("Error: could not write into output stream!");
}
pub fn write_right<W: Write>(stream: &mut BufWriter<W>, rv: &str, l_len: usize, fs: &[u8], rs: &[u8]) {
for _ in 0..l_len {
stream.write(fs).expect("Error: could not write into output stream!");
}
stream.write(rv.as_bytes()).expect("Error: could not write into output stream!");
stream.write(rs).expect("Error: could not write into output stream!");
}