diff --git a/chapter6/rstat/.DS_Store b/chapter6/rstat/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/chapter6/rstat/.DS_Store differ diff --git a/chapter6/rstat/.gitignore b/chapter6/rstat/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/chapter6/rstat/.gitignore @@ -0,0 +1 @@ +/target diff --git a/chapter6/rstat/Cargo.lock b/chapter6/rstat/Cargo.lock new file mode 100644 index 0000000..85e3238 --- /dev/null +++ b/chapter6/rstat/Cargo.lock @@ -0,0 +1,223 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[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 = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +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.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rstat" +version = "0.1.0" +dependencies = [ + "structopt", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cc388d94ffabf39b5ed5fadddc40147cb21e605f53db6f8f36a625d27489ac5" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2513111825077552a6751dfad9e11ce0fba07d7276a3943a037d7e93e64c5f" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +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/chapter6/rstat/Cargo.toml b/chapter6/rstat/Cargo.toml new file mode 100644 index 0000000..70b2d02 --- /dev/null +++ b/chapter6/rstat/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rstat" +version = "0.1.0" +authors = ["peshwar9"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +structopt = "0.3.16" diff --git a/chapter6/rstat/src/errors.rs b/chapter6/rstat/src/errors.rs new file mode 100644 index 0000000..7095d5e --- /dev/null +++ b/chapter6/rstat/src/errors.rs @@ -0,0 +1,37 @@ +use std::fmt; +use std::io; + +#[derive(Debug)] +pub struct StatsError { + pub message: String, +} + +impl fmt::Display for StatsError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!(f, "{}", self) + } +} + +impl From<&str> for StatsError { + fn from(s: &str) -> Self { + StatsError { + message: s.to_string(), + } + } +} + +impl From for StatsError { + fn from(e: io::Error) -> Self { + StatsError { + message: e.to_string(), + } + } +} + +impl From for StatsError { + fn from(_e: std::num::TryFromIntError) -> Self { + StatsError { + message: "Number conversion error".to_string(), + } + } +} diff --git a/chapter6/rstat/src/main.rs b/chapter6/rstat/src/main.rs new file mode 100644 index 0000000..d2bf7ed --- /dev/null +++ b/chapter6/rstat/src/main.rs @@ -0,0 +1,32 @@ +use std::path::PathBuf; +use structopt::StructOpt; +mod srcstats; +use srcstats::get_summary_src_stats; + +mod errors; +use errors::StatsError; + +#[derive(Debug, StructOpt)] +#[structopt( + name = "rstat", + about = "This is a tool to generate statistics on Rust projects" +)] +struct Opt { + #[structopt(name = "source directory", parse(from_os_str))] + in_dir: PathBuf, + #[structopt(name = "mode", short)] + mode: String, +} + +fn main() -> Result<(), StatsError> { + let opt = Opt::from_args(); + let mode = &opt.mode[..]; + match mode { + "src" => { + let stats = get_summary_src_stats(&opt.in_dir)?; + println!("Summary stats: {:?}", stats); + } + _ => println!("Sorry, no stats"), + } + Ok(()) +} diff --git a/chapter6/rstat/src/srcstats.rs b/chapter6/rstat/src/srcstats.rs new file mode 100644 index 0000000..0c5ac6d --- /dev/null +++ b/chapter6/rstat/src/srcstats.rs @@ -0,0 +1,78 @@ +use super::errors::StatsError; +use std::convert::TryFrom; +use std::ffi::OsStr; +use std::fs; +use std::fs::DirEntry; +use std::path::{Path, PathBuf}; + +// Struct to hold the stats +#[derive(Debug)] +pub struct SrcStats { + pub number_of_files: u32, + pub loc: u32, + pub comments: u32, + pub blanks: u32, +} + +pub fn get_src_stats_for_file(file_name: &Path) -> Result { + let file_contents = fs::read_to_string(file_name)?; + let mut loc = 0; + let mut blanks = 0; + let mut comments = 0; + + for line in file_contents.lines() { + if line.len() == 0 { + blanks += 1; + } else if line.starts_with("//") { + comments += 1; + } else { + loc += 1; + } + } + let source_stats = SrcStats { + number_of_files: u32::try_from(file_contents.lines().count())?, + loc: loc, + comments: comments, + blanks: blanks, + }; + Ok(source_stats) +} + +pub fn get_summary_src_stats(in_dir: &Path) -> Result { + let mut total_loc = 0; + let mut total_comments = 0; + let mut total_blanks = 0; + let mut dir_entries: Vec = vec![in_dir.to_path_buf()]; + let mut file_entries: Vec = vec![]; + + // Recursively iterate over directory entries to get flat list of .rs files + + while let Some(entry) = dir_entries.pop() { + for inner_entry in fs::read_dir(&entry)? { + if let Ok(entry) = inner_entry { + if entry.path().is_dir() { + dir_entries.push(entry.path()); + } else { + if entry.path().extension() == Some(OsStr::new("rs")) { + file_entries.push(entry); + } + } + } + } + } + let file_count = file_entries.len(); + // Compute the stats + for entry in file_entries { + let stat = get_src_stats_for_file(&entry.path())?; + total_loc += stat.loc; + total_blanks += stat.blanks; + total_comments += stat.comments; + } + + Ok(SrcStats { + number_of_files: u32::try_from(file_count)?, + loc: total_loc, + comments: total_comments, + blanks: total_blanks, + }) +}