diff --git a/Cargo.toml b/Cargo.toml index bff6c89..917c650 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,3 +31,11 @@ base64 = "0.22" mime_guess = "2.0" urlencoding = "2.1" regex = "1.10" + +[lints.clippy] +correctness = "warn" +suspicious = "warn" +complexity = "warn" +perf = "warn" +style = "warn" +pedantic = "warn" diff --git a/src/config.rs b/src/config.rs index 95d1e49..26c7322 100644 --- a/src/config.rs +++ b/src/config.rs @@ -40,14 +40,14 @@ impl FileConfiguration { port: Some(8080), app_name: Some("EWP".into()), exclude_courses: Some([].into()), - ..FileConfiguration::default() + ..Self::default() } } /// Complete default structure with an existing one fn complete(a: Self) -> Self { // Default config - let d = FileConfiguration::new(); + let d = Self::new(); #[allow(clippy::items_after_statements)] /// Return the default value if nothing is value is none @@ -94,18 +94,15 @@ pub struct Config { /// Load the config file fn get_file_config(file_path: &str) -> FileConfiguration { - match fs::read_to_string(file_path) { - Ok(file) => match toml::from_str(&file) { + fs::read_to_string(file_path).map_or_else( + |_| FileConfiguration::new(), + |file| match toml::from_str(&file) { Ok(stored_config) => FileConfiguration::complete(stored_config), Err(file_error) => { panic!("Error in config file: {file_error}"); } }, - Err(_) => { - // No config file - FileConfiguration::new() - } - } + ) } /// Build the configuration diff --git a/src/misc/github.rs b/src/misc/github.rs index 8a893ea..1210b84 100644 --- a/src/misc/github.rs +++ b/src/misc/github.rs @@ -1,5 +1,3 @@ -use core::panic; - use reqwest::{header::ACCEPT, Error}; use serde::Deserialize; @@ -32,13 +30,15 @@ pub enum ProjectState { Merged = 2, } -impl From for ProjectState { - fn from(orig: u8) -> Self { +impl TryFrom for ProjectState { + type Error = (); + + fn try_from(orig: u8) -> Result { match orig { - 0 => Self::Closed, - 1 => Self::Open, - 2 => Self::Merged, - _ => panic!(), + 0 => Ok(Self::Closed), + 1 => Ok(Self::Open), + 2 => Ok(Self::Merged), + _ => Err(()), } } } diff --git a/src/misc/markdown.rs b/src/misc/markdown.rs index 4dbf496..62be06a 100644 --- a/src/misc/markdown.rs +++ b/src/misc/markdown.rs @@ -106,7 +106,7 @@ pub struct Metadata { impl Metadata { /// Update current metadata boolean fields, keeping true ones - fn merge(&mut self, other: &Metadata) { + fn merge(&mut self, other: &Self) { self.math = self.math || other.math; self.mermaid = self.mermaid || other.mermaid; self.syntax_highlight = self.syntax_highlight || other.syntax_highlight; @@ -268,10 +268,7 @@ pub fn read_md( ) -> File { let arena = Arena::new(); - let opt = match options { - Some(specific_opt) => specific_opt, - None => get_options(), - }; + let opt = options.map_or_else(get_options, |specific_opt| specific_opt); let root = parse_document(&arena, raw_text, &opt); // Find metadata @@ -314,8 +311,7 @@ fn deserialize_metadata(text: &str) -> /// Fetch metadata from AST pub fn get_metadata<'a>(root: &'a AstNode<'a>, mtype: &TypeFileMetadata) -> FileMetadata { - match root - .children() + root.children() .find_map(|node| match &node.data.borrow().value { // Extract metadata from frontmatter NodeValue::FrontMatter(text) => Some(match mtype { @@ -336,9 +332,7 @@ pub fn get_metadata<'a>(root: &'a AstNode<'a>, mtype: &TypeFileMetadata) -> File ..FileMetadata::default() } } - TypeFileMetadata::Generic => FileMetadata { - ..FileMetadata::default() - }, + TypeFileMetadata::Generic => FileMetadata::default(), TypeFileMetadata::Index => FileMetadata { index: Some(deserialize_metadata(text)), ..FileMetadata::default() @@ -349,31 +343,29 @@ pub fn get_metadata<'a>(root: &'a AstNode<'a>, mtype: &TypeFileMetadata) -> File }, }), _ => None, - }) { - Some(data) => data, - // No metadata - None => match mtype { - TypeFileMetadata::Blog => FileMetadata { - blog: Some(FileMetadataBlog::default()), - ..FileMetadata::default() + }) + .map_or_else( + || match mtype { + TypeFileMetadata::Blog => FileMetadata { + blog: Some(FileMetadataBlog::default()), + ..FileMetadata::default() + }, + TypeFileMetadata::Contact => FileMetadata { + contact: Some(FileMetadataContact::default()), + ..FileMetadata::default() + }, + TypeFileMetadata::Generic => FileMetadata::default(), + TypeFileMetadata::Index => FileMetadata { + index: Some(FileMetadataIndex::default()), + ..FileMetadata::default() + }, + TypeFileMetadata::Portfolio => FileMetadata { + portfolio: Some(FileMetadataPortfolio::default()), + ..FileMetadata::default() + }, }, - TypeFileMetadata::Contact => FileMetadata { - contact: Some(FileMetadataContact::default()), - ..FileMetadata::default() - }, - TypeFileMetadata::Generic => FileMetadata { - ..FileMetadata::default() - }, - TypeFileMetadata::Index => FileMetadata { - index: Some(FileMetadataIndex::default()), - ..FileMetadata::default() - }, - TypeFileMetadata::Portfolio => FileMetadata { - portfolio: Some(FileMetadataPortfolio::default()), - ..FileMetadata::default() - }, - }, - } + |data| data, + ) } /// Check whether mermaid diagrams are in the AST diff --git a/src/misc/utils.rs b/src/misc/utils.rs index d01af36..96699d3 100644 --- a/src/misc/utils.rs +++ b/src/misc/utils.rs @@ -54,19 +54,14 @@ impl Responder for Html { /// Read a file pub fn read_file(filename: &str, expected_file: &TypeFileMetadata) -> Option { - match Path::new(filename).extension() { - Some(ext) => match ext.to_str().unwrap() { - "pdf" => match fs::read(filename) { - Ok(bytes) => Some(read_pdf(bytes)), - Err(_) => None, - }, - _ => match fs::read_to_string(filename) { - Ok(text) => Some(read_md(filename, &text, expected_file, None)), - Err(_) => None, - }, - }, - None => None, - } + Path::new(filename) + .extension() + .and_then(|ext| match ext.to_str().unwrap() { + "pdf" => fs::read(filename).map_or(None, |bytes| Some(read_pdf(bytes))), + _ => fs::read_to_string(filename).map_or(None, |text| { + Some(read_md(filename, &text, expected_file, None)) + }), + }) } fn read_pdf(data: Vec) -> File { diff --git a/src/routes/blog.rs b/src/routes/blog.rs index 3f8bb7b..4f04360 100644 --- a/src/routes/blog.rs +++ b/src/routes/blog.rs @@ -110,16 +110,14 @@ impl Hash for Post { } fn get_posts(location: &str) -> Vec { - let entries = match std::fs::read_dir(location) { - Ok(res) => res - .flatten() - .filter(|f| match f.path().extension() { - Some(ext) => ext == "md", - None => false, - }) - .collect::>(), - Err(_) => vec![], - }; + let entries = std::fs::read_dir(location).map_or_else( + |_| vec![], + |res| { + res.flatten() + .filter(|f| f.path().extension().map_or(false, |ext| ext == "md")) + .collect::>() + }, + ); entries .iter() @@ -128,36 +126,37 @@ fn get_posts(location: &str) -> Vec { let filename = fname.to_string_lossy(); let file_without_ext = filename.split_at(filename.len() - 3).0; - let file_metadata = match std::fs::read_to_string(format!("{location}/{filename}")) { - Ok(text) => { - let arena = Arena::new(); + let file_metadata = std::fs::read_to_string(format!("{location}/{filename}")) + .map_or_else( + |_| FileMetadataBlog { + title: Some(file_without_ext.into()), + ..FileMetadataBlog::default() + }, + |text| { + let arena = Arena::new(); - let options = get_options(); - let root = parse_document(&arena, &text, &options); - let mut metadata = get_metadata(root, &TypeFileMetadata::Blog).blog.unwrap(); + let options = get_options(); + let root = parse_document(&arena, &text, &options); + let mut metadata = + get_metadata(root, &TypeFileMetadata::Blog).blog.unwrap(); - // Always have a title - metadata.title = match metadata.title { - Some(title) => Some(title), - None => Some(file_without_ext.into()), - }; + // Always have a title + metadata.title = metadata + .title + .map_or_else(|| Some(file_without_ext.into()), Some); - metadata - } - Err(_) => FileMetadataBlog { - title: Some(file_without_ext.into()), - ..FileMetadataBlog::default() - }, - }; + metadata + }, + ); - if let Some(true) = file_metadata.publish { + if file_metadata.publish == Some(true) { Some(Post { url: file_without_ext.into(), title: file_metadata.title.unwrap(), date: file_metadata.date.unwrap_or({ let m = f.metadata().unwrap(); let date = std::convert::Into::>::into( - m.modified().unwrap_or(m.created().unwrap()), + m.modified().unwrap_or_else(|_| m.created().unwrap()), ) .date_naive(); diff --git a/src/routes/contrib.rs b/src/routes/contrib.rs index ac8e7bb..7a437af 100644 --- a/src/routes/contrib.rs +++ b/src/routes/contrib.rs @@ -84,7 +84,7 @@ async fn build_page(config: Config) -> String { // Distributes each PR in the right vector for d in &mut data { map.get(d.name.as_str()).unwrap().iter().for_each(|p| { - let state = p.state.into(); + let state = p.state.try_into().unwrap(); match state { ProjectState::Closed => d.pulls_closed.push(p.to_owned()), ProjectState::Merged => d.pulls_merged.push(p.to_owned()), diff --git a/src/routes/cours.rs b/src/routes/cours.rs index 85c281f..a3dec8b 100644 --- a/src/routes/cours.rs +++ b/src/routes/cours.rs @@ -96,10 +96,7 @@ fn get_content( path: &web::Query, exclusion_list: &[String], ) -> Option { - let filename = match &path.q { - Some(q) => q, - None => "index.md", - }; + let filename = path.q.as_ref().map_or("index.md", |q| q); // We should support regex? if exclusion_list