this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: redo the dispatching with generics

+120 -38
+43 -16
src/gzip.rs
··· 1 - extern crate flate2; 2 - 1 + use crate::utils::*; 3 2 use flate2::write::GzEncoder; 4 3 use flate2::{read::GzDecoder, Compression}; 5 4 use std::fs::File; ··· 9 8 /// The standard extension for the gzip format. 10 9 pub const EXT: &str = "gz"; 11 10 12 - pub fn compress_file<I: AsRef<Path>, O: Write>(in_file: I, output: O, level: u32) { 13 - compress(File::open(in_file).unwrap(), output, level); 11 + pub struct Gzip { 12 + pub compression_level: u32, 13 + pub common_args: CmprssCommonArgs, 14 14 } 15 15 16 - /// Compress an input file or directory into a gzip archive. 17 - pub fn compress<I: Read, O: Write>(mut input: I, output: O, level: u32) { 18 - let mut encoder = GzEncoder::new(output, Compression::new(level)); 16 + impl CmprssArgTrait for Gzip { 17 + fn common_args(&self) -> &CmprssCommonArgs { 18 + &self.common_args 19 + } 20 + } 19 21 20 - std::io::copy(&mut input, &mut encoder).unwrap(); 21 - encoder.finish().unwrap(); 22 + impl CmprssInfo for Gzip { 23 + /// The standard extension for the gzip format. 24 + fn extension(&self) -> &str { 25 + "gz" 26 + } 27 + 28 + /// Full name for gzip. 29 + fn name(&self) -> &str { 30 + "gzip" 31 + } 22 32 } 23 33 24 - /// Extract a gzipped file 25 - pub fn extract_file<I: AsRef<Path>, O: Write>(in_file: I, output: O) { 26 - extract(File::open(in_file).unwrap(), output); 34 + impl CmprssFile for Gzip { 35 + /// Compress an input file to gzip 36 + fn compress_file<I: AsRef<Path>, O: Write>(&self, in_file: I, output: O) { 37 + self.compress(File::open(in_file).unwrap(), output); 38 + } 39 + 40 + /// Extract a gzipped file 41 + fn extract_file<I: AsRef<Path>, O: Write>(&self, in_file: I, output: O) { 42 + self.extract(File::open(in_file).unwrap(), output); 43 + } 27 44 } 28 45 29 - /// Extract the gzip compressed data 30 - pub fn extract<I: Read, O: Write>(input: I, mut output: O) { 31 - let mut decoder = GzDecoder::new(input); 32 - std::io::copy(&mut decoder, &mut output).unwrap(); 46 + impl CmprssRead for Gzip { 47 + /// Compress an input file or directory into a gzip archive. 48 + fn compress<I: Read, O: Write>(&self, mut input: I, output: O) { 49 + let mut encoder = GzEncoder::new(output, Compression::new(self.compression_level)); 50 + 51 + std::io::copy(&mut input, &mut encoder).unwrap(); 52 + encoder.finish().unwrap(); 53 + } 54 + 55 + /// Extract the gzip compressed data 56 + fn extract<I: Read, O: Write>(&self, input: I, mut output: O) { 57 + let mut decoder = GzDecoder::new(input); 58 + std::io::copy(&mut decoder, &mut output).unwrap(); 59 + } 33 60 }
+41 -22
src/main.rs
··· 1 1 mod gzip; 2 2 mod tar; 3 + mod utils; 3 4 4 5 use clap::{Args, Parser, Subcommand}; 5 6 use std::fs::File; 6 7 use std::path::Path; 8 + use utils::*; 7 9 8 10 /// A compression multi-tool 9 11 #[derive(Parser, Debug)] ··· 84 86 85 87 /// Generates the output filename. 86 88 /// This either takes the given name or guesses the name based on the extension 87 - fn output_filename(input: &Path, output: Option<String>, extension: &str) -> String { 88 - match output { 89 + fn output_filename(input: &Path, output: &Option<String>, extension: &str) -> String { 90 + match output.clone() { 89 91 Some(file) => file, 90 92 None => { 91 93 format!( ··· 101 103 fn command_tar(args: TarArgs) { 102 104 let input_path = Path::new(&args.input); 103 105 if args.compress { 104 - let out = output_filename(input_path, args.output, tar::EXT); 106 + let out = output_filename(input_path, &args.output, tar::EXT); 105 107 tar::compress_file(input_path, File::create(out).unwrap()); 106 108 } else if args.extract { 107 109 tar::extract_file(input_path, args.output.unwrap_or(".".to_string())); ··· 113 115 "error: input appears to already be a tar archive, exiting. Use '--compress' if needed." 114 116 ) 115 117 } else { 116 - let out = output_filename(input_path, args.output, tar::EXT); 118 + let out = output_filename(input_path, &args.output, tar::EXT); 117 119 tar::compress_file(input_path, File::create(out).unwrap()); 118 120 } 119 121 } 120 122 } 121 123 122 - /// Execute a gzip command 123 - fn command_gzip(args: GzipArgs) { 124 + /// Execute an extract command. 125 + /// 126 + /// Attempts to extract based on the file extension. 127 + fn command_extract(args: ExtractArgs) { 128 + let input_path = Path::new(&args.input); 129 + match input_path.extension().unwrap().to_str().unwrap() { 130 + tar::EXT => tar::extract_file(input_path, args.output.unwrap_or(".".to_string())), 131 + _ => println!("error: unknown format "), 132 + } 133 + } 134 + 135 + /// Implement compression/extraction with a generic Compressor. 136 + fn command_generic<T: CmprssArgTrait + CmprssRead + CmprssInfo>(compressor: T) { 137 + let args = compressor.common_args(); 124 138 let input_path = Path::new(&args.input); 125 139 if args.compress { 126 - let out = output_filename(input_path, args.output, gzip::EXT); 127 - gzip::compress_file(input_path, File::create(out).unwrap(), args.compression); 140 + let out = output_filename(input_path, &args.output, compressor.extension()); 141 + compressor.compress(File::open(input_path).unwrap(), File::create(out).unwrap()); 128 142 } else if args.extract { 129 143 assert!(args.output.is_some(), "error: output filename required"); 130 - gzip::extract_file(input_path, File::create(args.output.unwrap()).unwrap()); 144 + compressor.extract( 145 + File::open(input_path).unwrap(), 146 + File::create(args.output.clone().unwrap()).unwrap(), 147 + ); 131 148 } else { 132 149 // Neither is set. 133 150 // Compress by default, warn if if looks like an archive. 134 - if input_path.extension().unwrap() == gzip::EXT { 151 + if input_path.extension().unwrap() == compressor.extension() { 135 152 println!( 136 - "error: input appears to already be a gzip archive, exiting. Use '--compress' if needed." 153 + "error: input appears to already be a {} archive, exiting. Use '--compress' if needed.", compressor.name() 137 154 ) 138 155 } else { 139 - let out = output_filename(input_path, args.output, gzip::EXT); 140 - gzip::compress_file(input_path, File::create(out).unwrap(), args.compression); 156 + let out = output_filename(input_path, &args.output, gzip::EXT); 157 + compressor.compress(File::open(input_path).unwrap(), File::create(out).unwrap()); 141 158 } 142 159 } 143 160 } 144 161 145 - /// Execute an extract command. 146 - /// 147 - /// Attempts to extract based on the file extension. 148 - fn command_extract(args: ExtractArgs) { 149 - let input_path = Path::new(&args.input); 150 - match input_path.extension().unwrap().to_str().unwrap() { 151 - tar::EXT => tar::extract_file(input_path, args.output.unwrap_or(".".to_string())), 152 - _ => println!("error: unknown format "), 162 + fn parse_gzip(args: GzipArgs) -> gzip::Gzip { 163 + gzip::Gzip { 164 + compression_level: args.compression, 165 + common_args: CmprssCommonArgs { 166 + compress: args.compress, 167 + extract: args.extract, 168 + input: args.input, 169 + output: args.output, 170 + }, 153 171 } 154 172 } 155 173 ··· 158 176 match args.format { 159 177 Some(Format::Tar(a)) => command_tar(a), 160 178 Some(Format::Extract(a)) => command_extract(a), 161 - Some(Format::Gzip(a)) => command_gzip(a), 179 + //Some(Format::Gzip(a)) => command_gzip(a), 180 + Some(Format::Gzip(a)) => command_generic(parse_gzip(a)), 162 181 None => println!("none"), 163 182 }; 164 183 }
+36
src/utils.rs
··· 1 + use std::io::{Read, Write}; 2 + use std::path::Path; 3 + 4 + /// Trait for generic compression/extract over Read/Write objects 5 + pub trait CmprssRead { 6 + fn compress<I: Read, O: Write>(&self, input: I, output: O); 7 + fn extract<I: Read, O: Write>(&self, input: I, output: O); 8 + } 9 + 10 + /// Trait for compressing/extracting from a file. 11 + pub trait CmprssFile { 12 + /// Compress an input file 13 + fn compress_file<I: AsRef<Path>, O: Write>(&self, in_file: I, output: O); 14 + 15 + /// Extract a file 16 + fn extract_file<I: AsRef<Path>, O: Write>(&self, in_file: I, output: O); 17 + } 18 + 19 + pub struct CmprssCommonArgs { 20 + pub compress: bool, 21 + pub extract: bool, 22 + pub input: String, 23 + pub output: Option<String>, 24 + } 25 + 26 + /// Getter method for the common arguments 27 + pub trait CmprssArgTrait { 28 + // TODO: There is probably a cleaner way to do this? 29 + fn common_args(&self) -> &CmprssCommonArgs; 30 + } 31 + 32 + /// Generic info about the given compressor. 33 + pub trait CmprssInfo { 34 + fn extension(&self) -> &str; 35 + fn name(&self) -> &str; 36 + }