Created
August 17, 2016 19:51
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(test)] | |
#![feature(question_mark)] | |
extern crate rand; | |
extern crate test; | |
#[cfg(feature="parallel")] | |
extern crate rayon; | |
use std::ptr; | |
use std::path::Path; | |
#[cfg(feature="parallel")] | |
use rayon::prelude::*; | |
use std::io::Read; | |
use std::fs::File; | |
use std::os::unix::fs::PermissionsExt; | |
use std::fmt::Write; | |
const BUF_SIZE: usize = 1_024_000; | |
fn convert(x: [u8; 3]) -> [u8; 4] { | |
[ | |
(x[0] >> 2) + 32, | |
(((x[0] & 0b00000011) << 4) | (x[1] >> 4)) + 32, | |
(((x[1] & 0b00001111) << 2) | (x[2] >> 6)) + 32, | |
(x[2] & 0b00111111) + 32, | |
] | |
} | |
#[cfg(feature="parallel")] | |
fn uuencode<T: AsRef<[u8]>>(val: T) -> Vec<String> { | |
let lines = val.as_ref().chunks(45).collect::<Vec<&[u8]>>(); | |
let mut encoded = Vec::new(); | |
lines.par_iter().map(|line| { | |
let len = (if line.len() > 0 { line.len() as u8 + 32 } else { 96 }) as char; | |
let mut encoded = String::new(); | |
for chunk in line.chunks(3) { | |
let mut bits = [0u8; 3]; | |
unsafe { std::ptr::copy(chunk.as_ptr(), bits.as_mut_ptr(), chunk.len()); } | |
let converted = convert(bits); | |
let converted = std::str::from_utf8(&converted).unwrap(); | |
encoded.push_str(converted); | |
} | |
encoded.insert(0, len); | |
encoded | |
}).collect_into(&mut encoded); | |
encoded | |
} | |
#[cfg(not(feature="parallel"))] | |
fn uuencode<T: AsRef<[u8]>>(val: T) -> Vec<String> { | |
let lines = val.as_ref().chunks(45); | |
let encoded = lines.map(|line| { | |
let len = (if line.len() > 0 { line.len() as u8 + 32 } else { 96 }) as char; | |
let mut encoded = String::new(); | |
for chunk in line.chunks(3) { | |
let mut bits = [0u8; 3]; | |
unsafe { std::ptr::copy(chunk.as_ptr(), bits.as_mut_ptr(), chunk.len()); } | |
let converted = convert(bits); | |
let converted = std::str::from_utf8(&converted).unwrap(); | |
encoded.push_str(converted); | |
} | |
encoded.insert(0, len); | |
encoded | |
}).collect(); | |
encoded | |
} | |
fn uuencode_file(path: &Path) -> std::io::Result<String> { | |
let mut file = File::open(path)?; | |
let metadata = file.metadata()?; | |
let mut encoded = String::with_capacity(metadata.len() as usize); | |
encoded.push_str(&format!("begin {} {}\n", metadata.permissions().mode(), path.file_name().unwrap().to_str().unwrap())); | |
let mut buf = [0; BUF_SIZE]; | |
while let Ok(bytes) = file.read(&mut buf) { | |
if bytes == 0 { | |
encoded.write_str("`\nend"); | |
break; | |
} | |
for line in uuencode(&buf[..bytes-1]) { | |
writeln!(encoded, "{}", line); | |
} | |
} | |
Ok(encoded) | |
} | |
#[bench] | |
fn uuencode_bench(bencher: &mut test::Bencher) { | |
use rand::thread_rng; | |
use rand::Rng; | |
let mut rng = thread_rng(); | |
let mut buf = vec![]; | |
buf.resize(10000000, 0); | |
rng.fill_bytes(&mut buf); | |
bencher.iter(move || { uuencode(&buf); }); | |
} | |
fn main() { | |
println!("{}", uuencode_file(Path::new("/tmp/img.png")).unwrap()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment