diff --git a/fetcher-config/src/jobs/action.rs b/fetcher-config/src/jobs/action.rs index f15ff634..7e8f96af 100644 --- a/fetcher-config/src/jobs/action.rs +++ b/fetcher-config/src/jobs/action.rs @@ -152,6 +152,7 @@ impl Action { } impl Field { + #[must_use] pub fn parse(self) -> CField { match self { Field::Title => CField::Title, diff --git a/fetcher-config/src/jobs/action/decode_html.rs b/fetcher-config/src/jobs/action/decode_html.rs index c5b47d4a..dc1fb467 100644 --- a/fetcher-config/src/jobs/action/decode_html.rs +++ b/fetcher-config/src/jobs/action/decode_html.rs @@ -22,6 +22,7 @@ pub struct DecodeHtml { } impl DecodeHtml { + #[must_use] pub fn parse(self) -> Vec { self.r#in .into_iter() diff --git a/fetcher-config/src/jobs/action/html/query.rs b/fetcher-config/src/jobs/action/html/query.rs index 819b57e3..9b73b315 100644 --- a/fetcher-config/src/jobs/action/html/query.rs +++ b/fetcher-config/src/jobs/action/html/query.rs @@ -63,6 +63,7 @@ pub struct HtmlQueryRegex { } impl ElementKind { + #[must_use] pub fn parse(self) -> c_query::ElementKind { use ElementKind::{Attr, Class, Tag}; @@ -75,6 +76,7 @@ impl ElementKind { } impl DataLocation { + #[must_use] pub fn parse(self) -> c_query::DataLocation { use DataLocation::{Attr, Text}; @@ -86,6 +88,7 @@ impl DataLocation { } impl ElementQuery { + #[must_use] pub fn parse(self) -> c_query::ElementQuery { c_query::ElementQuery { kind: self.kind.parse(), diff --git a/fetcher-config/src/jobs/action/json.rs b/fetcher-config/src/jobs/action/json.rs index 23b9ff76..77346ea6 100644 --- a/fetcher-config/src/jobs/action/json.rs +++ b/fetcher-config/src/jobs/action/json.rs @@ -83,6 +83,7 @@ impl Json { } impl Key { + #[must_use] pub fn parse(self) -> c_json::Key { match self { Key::String(s) => c_json::Key::String(s), diff --git a/fetcher-config/src/jobs/action/set.rs b/fetcher-config/src/jobs/action/set.rs index 80118de4..0e034660 100644 --- a/fetcher-config/src/jobs/action/set.rs +++ b/fetcher-config/src/jobs/action/set.rs @@ -20,6 +20,7 @@ use serde_with::{serde_as, OneOrMany}; pub struct Set(pub HashMap>); impl Set { + #[must_use] pub fn parse(self) -> Vec { self.0 .into_iter() diff --git a/fetcher-config/src/jobs/action/shorten.rs b/fetcher-config/src/jobs/action/shorten.rs index c0919aab..de491104 100644 --- a/fetcher-config/src/jobs/action/shorten.rs +++ b/fetcher-config/src/jobs/action/shorten.rs @@ -20,6 +20,7 @@ use std::collections::HashMap; pub struct Shorten(pub HashMap); impl Shorten { + #[must_use] pub fn parse(self) -> Vec { self.0 .into_iter() diff --git a/fetcher-config/src/jobs/action/take.rs b/fetcher-config/src/jobs/action/take.rs index e8fbc9a7..12b52bbb 100644 --- a/fetcher-config/src/jobs/action/take.rs +++ b/fetcher-config/src/jobs/action/take.rs @@ -26,6 +26,7 @@ pub enum TakeWhich { } impl Take { + #[must_use] pub fn parse(self) -> CTake { CTake { from: self.0.which.parse(), @@ -35,6 +36,7 @@ impl Take { } impl TakeWhich { + #[must_use] pub fn parse(self) -> CTakeFrom { match self { TakeWhich::FromNewest => CTakeFrom::Beginning, diff --git a/fetcher-config/src/jobs/action/trim.rs b/fetcher-config/src/jobs/action/trim.rs index 9ae50250..df1cf252 100644 --- a/fetcher-config/src/jobs/action/trim.rs +++ b/fetcher-config/src/jobs/action/trim.rs @@ -19,6 +19,7 @@ pub struct Trim { } impl Trim { + #[must_use] pub fn parse(self) -> impl CTransform { CTransformFieldWrapper { field: self.field.parse(), diff --git a/fetcher-config/src/jobs/action/use_as.rs b/fetcher-config/src/jobs/action/use_as.rs index 68b9899b..171cf4a3 100644 --- a/fetcher-config/src/jobs/action/use_as.rs +++ b/fetcher-config/src/jobs/action/use_as.rs @@ -20,6 +20,7 @@ pub struct As { } impl Use { + #[must_use] pub fn parse(self) -> Vec { self.0 .into_iter() diff --git a/fetcher-config/src/jobs/external_data.rs b/fetcher-config/src/jobs/external_data.rs index e91ca80f..07f635f5 100644 --- a/fetcher-config/src/jobs/external_data.rs +++ b/fetcher-config/src/jobs/external_data.rs @@ -105,6 +105,7 @@ impl From> for ExternalDataResult { } impl ExternalDataError { + #[must_use] pub fn new_io_with_path(io_err: io::Error, path: &Path) -> Self { Self::Io { source: io_err, @@ -112,6 +113,7 @@ impl ExternalDataError { } } + #[must_use] pub fn new_rf_incompat_with_path( expected: ReadFilterKind, found: ReadFilterKind, diff --git a/fetcher-config/src/jobs/named/job_name.rs b/fetcher-config/src/jobs/named/job_name.rs index 69ccee03..242772a7 100644 --- a/fetcher-config/src/jobs/named/job_name.rs +++ b/fetcher-config/src/jobs/named/job_name.rs @@ -15,6 +15,7 @@ use std::{ pub struct JobName(pub Arc); impl JobName { + #[must_use] pub fn as_str(&self) -> &str { self } diff --git a/fetcher-config/src/jobs/named/task_name.rs b/fetcher-config/src/jobs/named/task_name.rs index 805b767c..0aca93e0 100644 --- a/fetcher-config/src/jobs/named/task_name.rs +++ b/fetcher-config/src/jobs/named/task_name.rs @@ -19,6 +19,7 @@ pub struct TaskName(pub String); pub type TaskNameMap = HashMap; impl TaskName { + #[must_use] pub fn as_str(&self) -> &str { self } diff --git a/fetcher-config/src/jobs/read_filter.rs b/fetcher-config/src/jobs/read_filter.rs index 3a4640c9..5c31d988 100644 --- a/fetcher-config/src/jobs/read_filter.rs +++ b/fetcher-config/src/jobs/read_filter.rs @@ -29,7 +29,7 @@ pub enum ReadFilter { NotPresentInReadList(NotPresent), } -#[derive(Deserialize, Serialize, Clone, Copy, PartialEq, Debug)] +#[derive(Deserialize, Serialize, Clone, Copy, PartialEq, Eq, Debug)] #[serde(rename_all = "snake_case", deny_unknown_fields)] pub enum Kind { NewerThanRead, @@ -49,10 +49,12 @@ pub struct NotPresent { } impl EntryId { + #[must_use] pub fn parse(self) -> CEntryId { CEntryId(self.0) } + #[must_use] pub fn unparse(other: CEntryId) -> Self { Self(other.0) } @@ -92,6 +94,7 @@ impl ReadFilter { None } + #[must_use] pub fn to_kind(&self) -> Kind { match self { ReadFilter::NewerThanRead(_) => Kind::NewerThanRead, @@ -119,12 +122,14 @@ impl Kind { } impl Newer { + #[must_use] pub fn parse(self) -> CNewer { CNewer { last_read_id: Some(self.last_read_id.parse()), } } + #[must_use] pub fn unparse(read_filter: &CNewer) -> Option { read_filter.last_read_id.as_ref().map(|last_read_id| Self { last_read_id: EntryId::unparse(last_read_id.clone()), @@ -133,6 +138,7 @@ impl Newer { } impl NotPresent { + #[must_use] pub fn parse(self) -> CNotPresent { self.read_list .into_iter() @@ -140,6 +146,7 @@ impl NotPresent { .collect() } + #[must_use] pub fn unparse(read_filter: &CNotPresent) -> Option { if read_filter.is_empty() { None diff --git a/fetcher-config/src/jobs/source.rs b/fetcher-config/src/jobs/source.rs index f845f50d..f8018ef3 100644 --- a/fetcher-config/src/jobs/source.rs +++ b/fetcher-config/src/jobs/source.rs @@ -75,6 +75,7 @@ impl Source { }) } + #[must_use] pub fn supports_replies(&self) -> bool { // Source::Email will support replies in the future #[allow(clippy::match_like_matches_macro)] diff --git a/fetcher-config/src/jobs/source/exec.rs b/fetcher-config/src/jobs/source/exec.rs index 4dd25178..07dc599c 100644 --- a/fetcher-config/src/jobs/source/exec.rs +++ b/fetcher-config/src/jobs/source/exec.rs @@ -18,6 +18,7 @@ pub struct Exec { } impl Exec { + #[must_use] pub fn parse(self) -> Vec { self.cmd.into_iter().map(|cmd| CExec { cmd }).collect() } diff --git a/fetcher-config/src/jobs/source/file.rs b/fetcher-config/src/jobs/source/file.rs index ff39eba9..f9d478ae 100644 --- a/fetcher-config/src/jobs/source/file.rs +++ b/fetcher-config/src/jobs/source/file.rs @@ -16,6 +16,7 @@ use std::path::PathBuf; pub struct File(#[serde_as(deserialize_as = "OneOrMany<_>")] pub Vec); impl File { + #[must_use] pub fn parse(self) -> Vec { self.0.into_iter().map(|path| CFile { path }).collect() } diff --git a/fetcher-config/src/jobs/source/reddit.rs b/fetcher-config/src/jobs/source/reddit.rs index 5b63e62e..76078107 100644 --- a/fetcher-config/src/jobs/source/reddit.rs +++ b/fetcher-config/src/jobs/source/reddit.rs @@ -41,6 +41,7 @@ pub enum TimePeriod { } impl Reddit { + #[must_use] pub fn parse(self) -> Vec { self.0 .into_iter() @@ -50,12 +51,14 @@ impl Reddit { } impl Inner { + #[must_use] pub fn parse(self, subreddit: &str) -> CReddit { CReddit::new(subreddit, self.sort.parse(), self.score_threshold) } } impl Sort { + #[must_use] pub fn parse(self) -> CSort { match self { Sort::Latest | Sort::New => CSort::Latest, diff --git a/fetcher-config/src/jobs/source/string.rs b/fetcher-config/src/jobs/source/string.rs index e64119cf..f4b5110a 100644 --- a/fetcher-config/src/jobs/source/string.rs +++ b/fetcher-config/src/jobs/source/string.rs @@ -13,6 +13,7 @@ use serde_with::{serde_as, OneOrMany}; pub struct StringSource(#[serde_as(deserialize_as = "OneOrMany<_>")] pub Vec); impl StringSource { + #[must_use] pub fn parse(self) -> Vec { self.0.into_iter().collect() } diff --git a/fetcher-config/src/jobs/task/entry_to_msg_map.rs b/fetcher-config/src/jobs/task/entry_to_msg_map.rs index 6fe6eb63..60d8bc2d 100644 --- a/fetcher-config/src/jobs/task/entry_to_msg_map.rs +++ b/fetcher-config/src/jobs/task/entry_to_msg_map.rs @@ -22,26 +22,31 @@ pub struct MessageId(pub i64); pub struct EntryToMsgMap(pub HashMap); impl EntryId { + #[must_use] pub fn parse(self) -> CEntryId { self.0.into() } + #[must_use] pub fn unparse(eid: CEntryId) -> Self { Self(eid.0) } } impl MessageId { + #[must_use] pub fn parse(self) -> CMessageId { self.0.into() } + #[must_use] pub fn unparse(msgid: CMessageId) -> Self { Self(msgid.0) } } impl EntryToMsgMap { + #[must_use] pub fn parse(self) -> HashMap { self.0 .into_iter() @@ -49,6 +54,7 @@ impl EntryToMsgMap { .collect() } + #[must_use] pub fn unparse(map: HashMap) -> Self { Self( map.into_iter() diff --git a/fetcher-config/src/lib.rs b/fetcher-config/src/lib.rs index 37b6b32e..6cb8981c 100644 --- a/fetcher-config/src/lib.rs +++ b/fetcher-config/src/lib.rs @@ -7,12 +7,17 @@ // TODO: mb rename .parse() into .into() or something of that sort? .into() is already used by From/Into traits though. Naming is hard, man... UPD: into_conf() and from_conf() are way better! #![doc = include_str!("../README.md")] +#![warn(clippy::unwrap_used)] +// Additional Lints #![warn(clippy::pedantic)] +// some types are more descriptive with modules name in the name, especially if this type is often used out of the context of this module #![allow(clippy::module_name_repetitions)] -#![allow(clippy::missing_errors_doc)] -#![allow(clippy::missing_panics_doc)] -#![allow(clippy::must_use_candidate)] -#![warn(clippy::unwrap_used)] +#![warn(clippy::nursery)] +#![allow(clippy::option_if_let_else)] // "harder to read, false branch before true branch" +#![allow(clippy::use_self)] // may be hard to understand what Self even is deep into a function's body +#![allow(clippy::equatable_if_let)] // matches!() adds too much noise for little benefit +#![allow(clippy::missing_const_for_fn)] // most of methods take self and self destructor can't be const, so this is pretty much iseless +#![allow(clippy::missing_errors_doc)] // TODO: add more docs pub mod error; pub mod jobs; diff --git a/fetcher-config/src/serde_extentions.rs b/fetcher-config/src/serde_extentions.rs index 7876ce4b..e4fe1c76 100644 --- a/fetcher-config/src/serde_extentions.rs +++ b/fetcher-config/src/serde_extentions.rs @@ -4,11 +4,12 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -pub(crate) mod tuple { +pub mod tuple { use serde::{de::Visitor, ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer}; use std::{fmt, marker::PhantomData}; - pub(crate) fn serialize<'a, S, V, First, Second>( + #[allow(clippy::extra_unused_type_parameters)] // they are used in the where clause and in the function body + pub fn serialize<'a, S, V, First, Second>( tuple: &'a V, serializer: S, ) -> Result @@ -24,7 +25,7 @@ pub(crate) mod tuple { map.end() } - pub(crate) fn deserialize<'de, D, V, First, Second>(deserializer: D) -> Result + pub fn deserialize<'de, D, V, First, Second>(deserializer: D) -> Result where D: Deserializer<'de>, V: From<(First, Second)>, diff --git a/fetcher-config/src/settings/discord.rs b/fetcher-config/src/settings/discord.rs index 3af6d751..37032abc 100644 --- a/fetcher-config/src/settings/discord.rs +++ b/fetcher-config/src/settings/discord.rs @@ -13,12 +13,14 @@ pub struct Discord { } impl Discord { + #[must_use] pub fn parse(self) -> String { let Self { token } = self; token } + #[must_use] pub fn unparse(token: String) -> Self { Self { token } } diff --git a/fetcher-config/src/settings/email_password.rs b/fetcher-config/src/settings/email_password.rs index 33a08b59..aab90986 100644 --- a/fetcher-config/src/settings/email_password.rs +++ b/fetcher-config/src/settings/email_password.rs @@ -13,12 +13,14 @@ pub struct EmailPassword { } impl EmailPassword { + #[must_use] pub fn parse(self) -> String { let Self { password } = self; password } + #[must_use] pub fn unparse(password: String) -> Self { Self { password } } diff --git a/fetcher-config/src/settings/google.rs b/fetcher-config/src/settings/google.rs index 338bd239..f9329564 100644 --- a/fetcher-config/src/settings/google.rs +++ b/fetcher-config/src/settings/google.rs @@ -17,10 +17,12 @@ pub struct Google { } impl Google { + #[must_use] pub fn parse(self) -> CoreGoogleAuth { CoreGoogleAuth::new(self.client_id, self.client_secret, self.refresh_token) } + #[must_use] pub fn unparse(auth: CoreGoogleAuth) -> Self { let CoreGoogleAuth { client_id, diff --git a/fetcher-config/src/settings/telegram.rs b/fetcher-config/src/settings/telegram.rs index f89de31f..ad914c46 100644 --- a/fetcher-config/src/settings/telegram.rs +++ b/fetcher-config/src/settings/telegram.rs @@ -13,12 +13,14 @@ pub struct Telegram { } impl Telegram { + #[must_use] pub fn parse(self) -> String { let Self { token } = self; token } + #[must_use] pub fn unparse(token: String) -> Self { Self { token } } diff --git a/fetcher-config/src/settings/twitter.rs b/fetcher-config/src/settings/twitter.rs index fad7f5e7..925149bf 100644 --- a/fetcher-config/src/settings/twitter.rs +++ b/fetcher-config/src/settings/twitter.rs @@ -14,6 +14,7 @@ pub struct Twitter { } impl Twitter { + #[must_use] pub fn parse(self) -> (String, String) { let Self { api_key, @@ -23,6 +24,7 @@ impl Twitter { (api_key, api_secret) } + #[must_use] pub fn unparse(api_key: String, api_secret: String) -> Self { Self { api_key, diff --git a/fetcher-core/src/auth/google.rs b/fetcher-core/src/auth/google.rs index 4bedb6fc..22f19d8b 100644 --- a/fetcher-core/src/auth/google.rs +++ b/fetcher-core/src/auth/google.rs @@ -64,7 +64,7 @@ impl Google { #[allow(clippy::doc_markdown)] /// Creates a new Google OAuth2 authenticator #[must_use] - pub fn new(client_id: String, client_secret: String, refresh_token: String) -> Self { + pub const fn new(client_id: String, client_secret: String, refresh_token: String) -> Self { Self { client_id, client_secret, diff --git a/fetcher-core/src/lib.rs b/fetcher-core/src/lib.rs index 1971f0f2..27e0d968 100644 --- a/fetcher-core/src/lib.rs +++ b/fetcher-core/src/lib.rs @@ -5,10 +5,16 @@ */ #![doc = include_str!("../README.md")] -#![warn(clippy::pedantic)] #![warn(missing_docs)] #![warn(clippy::unwrap_used)] +// Additional Lints +#![warn(clippy::pedantic)] +// some types are more descriptive with modules name in the name, especially if this type is often used out of the context of this module #![allow(clippy::module_name_repetitions)] +#![warn(clippy::nursery)] +#![allow(clippy::option_if_let_else)] // "harder to read, false branch before true branch" +#![allow(clippy::use_self)] // may be hard to understand what Self even is deep into a function's body +#![allow(clippy::equatable_if_let)] // matches!() adds too much noise for little benefit pub mod action; pub mod auth; diff --git a/fetcher-core/src/read_filter/newer.rs b/fetcher-core/src/read_filter/newer.rs index 49aef168..d2cfe3d2 100644 --- a/fetcher-core/src/read_filter/newer.rs +++ b/fetcher-core/src/read_filter/newer.rs @@ -24,13 +24,13 @@ pub struct Newer { impl Newer { /// Creates a new empty [`Newer`] Read Filter #[must_use] - pub fn new() -> Self { + pub const fn new() -> Self { Self { last_read_id: None } } /// Returns the last read entry id, if any #[must_use] - pub fn last_read(&self) -> Option<&EntryId> { + pub const fn last_read(&self) -> Option<&EntryId> { self.last_read_id.as_ref() } } diff --git a/fetcher-core/src/sink/discord.rs b/fetcher-core/src/sink/discord.rs index 4375b6e3..92bd8320 100644 --- a/fetcher-core/src/sink/discord.rs +++ b/fetcher-core/src/sink/discord.rs @@ -188,7 +188,7 @@ impl Sink for Discord { impl TargetInner { async fn send_message<'a, F>(&self, bot: &Bot, f: F) -> Result where - F: for<'b> FnOnce(&'b mut CreateMessage<'a>) -> &'b mut CreateMessage<'a>, + F: for<'b> FnOnce(&'b mut CreateMessage<'a>) -> &'b mut CreateMessage<'a> + Send, { let msg = match self { TargetInner::Channel(chan) => chan.send_message(bot, f).await?, diff --git a/fetcher-core/src/sink/message.rs b/fetcher-core/src/sink/message.rs index 3c4f90d6..9e9a5667 100644 --- a/fetcher-core/src/sink/message.rs +++ b/fetcher-core/src/sink/message.rs @@ -43,7 +43,7 @@ pub enum Media { impl Message { /// Check if the message is entirely empty. Even a single media attachment will mark this message as not empty #[must_use] - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.title.is_none() && self.body.is_none() && self.link.is_none() && self.media.is_none() } } diff --git a/fetcher-core/src/sink/message/length_limiter.rs b/fetcher-core/src/sink/message/length_limiter.rs index c6c75d0e..cd80c3c5 100644 --- a/fetcher-core/src/sink/message/length_limiter.rs +++ b/fetcher-core/src/sink/message/length_limiter.rs @@ -4,7 +4,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -pub(crate) struct MessageLengthLimiter<'a> { +pub struct MessageLengthLimiter<'a> { pub head: Option<&'a str>, pub body: Option<&'a str>, pub tail: Option<&'a str>, diff --git a/fetcher-core/src/source/email.rs b/fetcher-core/src/source/email.rs index 8e6f51ae..58c04fb6 100644 --- a/fetcher-core/src/source/email.rs +++ b/fetcher-core/src/source/email.rs @@ -149,7 +149,7 @@ impl Email { /// Creates an [`Email`] source that uses a password to authenticate via IMAP #[must_use] - pub fn new_generic( + pub const fn new_generic( imap: String, email: String, password: String, diff --git a/fetcher-core/src/source/twitter.rs b/fetcher-core/src/source/twitter.rs index 31e691c6..f1988b4b 100644 --- a/fetcher-core/src/source/twitter.rs +++ b/fetcher-core/src/source/twitter.rs @@ -48,7 +48,7 @@ pub enum TwitterError { impl Twitter { /// Creates a new [`Twitter`] source #[must_use] - pub fn new(handle: String, api_key: String, api_secret: String) -> Self { + pub const fn new(handle: String, api_key: String, api_secret: String) -> Self { Self { timeline: None, handle, diff --git a/fetcher/src/main.rs b/fetcher/src/main.rs index a5e31dd2..f98357b7 100644 --- a/fetcher/src/main.rs +++ b/fetcher/src/main.rs @@ -5,9 +5,18 @@ */ #![doc = include_str!("../README.md")] +// #![warn(clippy::unwrap_used)] +// Additional Lints #![warn(clippy::pedantic)] -#![allow(clippy::missing_errors_doc)] // TODO: add more docs (even though it a bin crate, they are for me...) and remove this +// some types are more descriptive with modules name in the name, especially if this type is often used out of the context of this module #![allow(clippy::module_name_repetitions)] +#![warn(clippy::nursery)] +#![allow(clippy::option_if_let_else)] // "harder to read, false branch before true branch" +#![allow(clippy::use_self)] // may be hard to understand what Self even is deep into a function's body +#![allow(clippy::equatable_if_let)] // matches!() adds too much noise for little benefit +#![allow(clippy::missing_const_for_fn)] // most of methods take self and self destructor can't be const, so this is pretty much iseless +#![allow(clippy::missing_errors_doc)] // TODO: add more docs +#![allow(clippy::future_not_send)] // not useful for a binary crate pub mod args; pub mod error_handling; @@ -528,6 +537,7 @@ async fn run_job( let name = name.clone(); async move { + #[allow(clippy::redundant_pub_crate)] // false positive loop { select! { res = async_job => {