commit fde07fe0c0038c76e6ddaa3deeb37db2ce94ab91
parent 8fd8669d36e9f422beae4ce39a643490d6202010
Author: Zack Newman <zack@philomathiclife.com>
Date: Wed, 21 Aug 2024 18:31:09 -0600
update deps. handle lints
Diffstat:
10 files changed, 152 insertions(+), 243 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -9,37 +9,29 @@ license = "MIT OR Apache-2.0"
name = "rpz"
readme = "README.md"
repository = "https://git.philomathiclife.com/repos/rpz/"
-version = "0.6.2"
+version = "1.0.0"
-[lib]
-name = "rpz"
-path = "src/lib.rs"
-
-[[bin]]
-name = "rpz"
-path = "src/main.rs"
+[badges]
+maintenance = { status = "actively-developed" }
[dependencies]
ascii_domain = { version = "0.6.1", default-features = false }
-num-bigint = { version = "0.4.5", default-features = false }
-reqwest = { version = "0.12.4", default-features = false, features = ["brotli", "deflate", "gzip", "rustls-tls-native-roots", "trust-dns"] }
-serde = { version = "1.0.201", default-features = false }
+num-bigint = { version = "0.4.6", default-features = false }
+reqwest = { version = "0.12.7", default-features = false, features = ["brotli", "deflate", "gzip", "rustls-tls-native-roots", "trust-dns"] }
+serde = { version = "1.0.208", default-features = false }
superset_map = { version = "0.2.3", default-features = false }
-tokio = { version = "1.37.0", default-features = false, features = ["rt", "time"] }
-toml = { version = "0.8.12", default-features = false, features = ["parse"] }
-url = { version = "2.5.0", default-features = false, features = ["serde"] }
+tokio = { version = "1.39.3", default-features = false, features = ["rt", "time"] }
+toml = { version = "0.8.19", default-features = false, features = ["parse"] }
+url = { version = "2.5.2", default-features = false, features = ["serde"] }
zfc = { version = "0.3.2", default-features = false }
[target.'cfg(target_os = "openbsd")'.dependencies]
-priv_sep = { version = "1.0.1", default-features = false, features = ["openbsd"], optional = true }
+priv_sep = { version = "2.0.0", default-features = false, features = ["openbsd"], optional = true }
[features]
priv_sep = ["dep:priv_sep"]
default = ["priv_sep"]
-[badges]
-maintenance = { status = "actively-developed" }
-
[profile.release]
lto = true
panic = 'abort'
diff --git a/src/app.rs b/src/app.rs
@@ -16,25 +16,21 @@ pub trait Helper {
fn kind() -> Kind;
}
impl Helper for Adblock<'_> {
- #[inline]
fn kind() -> Kind {
Kind::Adblock
}
}
impl Helper for DomainOnly<'_> {
- #[inline]
fn kind() -> Kind {
Kind::DomainOnly
}
}
impl Helper for Hosts<'_> {
- #[inline]
fn kind() -> Kind {
Kind::Hosts
}
}
impl Helper for Wildcard<'_> {
- #[inline]
fn kind() -> Kind {
Kind::Wildcard
}
@@ -49,12 +45,10 @@ pub struct Domains<'unblock, 'block> {
}
impl<'unblock, 'block> Domains<'unblock, 'block> {
/// Returns a reference to the `RpzDomain`s to block.
- #[inline]
pub const fn block(&self) -> &SupersetSet<RpzDomain<'block>> {
&self.block
}
/// Returns an empty `Domains`.
- #[inline]
pub const fn new() -> Self {
Self {
unblock: SupersetSet::new(),
@@ -63,7 +57,6 @@ impl<'unblock, 'block> Domains<'unblock, 'block> {
}
/// Returns `Domains` based on `LocalFiles` along
/// with a `Vec` of `Summary`.
- #[inline]
pub fn new_with<'c: 'unblock + 'block>(
local: &'c LocalFiles,
) -> (Self, Vec<Summary<'c, FirefoxDomainErr>>) {
@@ -79,7 +72,6 @@ impl<'unblock, 'block> Domains<'unblock, 'block> {
/// a superset of it.
///
/// All parsing errors are ignored.
- #[inline]
fn add_block_file<
'c: 'block,
T: Into<RpzDomain<'block>> + ParsedDomain<'block, Error = FirefoxDomainErr> + Helper,
@@ -126,7 +118,6 @@ impl<'unblock, 'block> Domains<'unblock, 'block> {
/// a superset of it.
///
/// All parsing errors are ignored.
- #[inline]
pub fn add_block_files<'c: 'block>(
&mut self,
files: &'c Files,
@@ -137,8 +128,6 @@ impl<'unblock, 'block> Domains<'unblock, 'block> {
/// a superset of it.
///
/// All parsing errors are ignored.
- #[allow(clippy::into_iter_on_ref)]
- #[inline]
fn add_files<
'unblock,
'block,
@@ -150,7 +139,7 @@ impl<'unblock, 'block> Domains<'unblock, 'block> {
summaries: &mut Vec<Summary<'c, FirefoxDomainErr>>,
) {
files
- .into_iter()
+ .iter()
.fold((), |(), file| doms.add_block_file::<T>(file, summaries));
}
add_files::<Adblock<'_>>(self, &files.adblock, summaries);
@@ -164,7 +153,6 @@ impl<'unblock, 'block> Domains<'unblock, 'block> {
/// `Domains::unblock` does not contain a superset of it.
///
/// All parsing errors are ignored.
- #[inline]
fn add_local_files<'c: 'unblock + 'block>(
&mut self,
files: &'c LocalFiles,
@@ -193,7 +181,6 @@ impl<'unblock, 'block> Domains<'unblock, 'block> {
/// # Errors
///
/// Returns `Error` iff `writeln` or `fs::rename` do.
- #[inline]
pub fn write(
self,
path: Option<(AbsFilePath<false>, AbsFilePath<false>)>,
@@ -204,7 +191,6 @@ impl<'unblock, 'block> Domains<'unblock, 'block> {
/// so long as `exclude` contains a proper superset of the domain.
///
/// Returns the total number of lines written.
- #[inline]
fn write_domain<W: Write>(
doms: &SupersetSet<RpzDomain<'_>>,
exclude: Option<&SupersetSet<RpzDomain<'_>>>,
diff --git a/src/args.rs b/src/args.rs
@@ -1,11 +1,11 @@
-use core::fmt::{self, Display, Formatter};
-use rpz::file::AbsFilePath;
-use std::{
- env::{self, Args},
+use core::{
error::Error,
+ fmt::{self, Display, Formatter},
};
+use rpz::file::AbsFilePath;
+use std::env::{self, Args};
/// Error returned when parsing arguments passed to the application.
-#[allow(clippy::exhaustive_enums, clippy::module_name_repetitions)]
+#[expect(clippy::module_name_repetitions, reason = "prefer the name")]
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum ArgsErr {
/// Error when no arguments were passed to the application.
@@ -27,8 +27,6 @@ pub enum ArgsErr {
QuietAndVerbose,
}
impl Display for ArgsErr {
- #[allow(clippy::ref_patterns)]
- #[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
Self::NoArgs => write!(f, "no arguments were passed, but at least two are required containing the option '-f' and its value which must be an absolute path to the config file"),
@@ -74,13 +72,10 @@ pub enum Opts {
}
impl Opts {
/// Returns `Opts` based on arguments passed to the application.
- #[allow(clippy::too_many_lines)]
- #[inline]
+ #[expect(clippy::too_many_lines, reason = "this is fine")]
pub fn from_args() -> Result<Self, ArgsErr> {
/// Attempts to parse the next `Arg` into `-` or an absolute
/// path to a file.
- #[allow(clippy::option_if_let_else)]
- #[inline]
fn get_path(args: &mut Args) -> Result<ConfigPath, ArgsErr> {
args.next()
.map_or(Err(ArgsErr::ConfigPathNotPassed), |path| {
diff --git a/src/config.rs b/src/config.rs
@@ -30,14 +30,11 @@ pub struct Config {
pub wildcard: HashSet<HttpUrl>,
}
impl Display for Config {
- #[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
/// Helper function that writes the `Url`s in a `HashSet<HttpUrl>`.
- #[allow(clippy::into_iter_on_ref)]
- #[inline]
fn keys(set: &HashSet<HttpUrl>, f: &mut Formatter<'_>, name: &str) -> fmt::Result {
write!(f, "{name}: [").and_then(|()| {
- set.into_iter()
+ set.iter()
.try_fold((), |(), url| write!(f, "{url}, "))
.and_then(|()| f.write_str("], "))
})
@@ -66,8 +63,7 @@ impl Display for Config {
}
}
impl<'de> Deserialize<'de> for Config {
- #[allow(clippy::too_many_lines)]
- #[inline]
+ #[expect(clippy::too_many_lines, reason = "this is fine")]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
@@ -90,7 +86,6 @@ impl<'de> Deserialize<'de> for Config {
Wildcard,
}
impl<'d> Deserialize<'d> for Field {
- #[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'d>,
@@ -99,13 +94,11 @@ impl<'de> Deserialize<'de> for Config {
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
- #[inline]
fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
formatter.write_str(
"'timeout', 'rpz', 'local_dir', 'adblock', 'domain', 'hosts', or 'wildcard'",
)
}
- #[inline]
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
@@ -129,34 +122,35 @@ impl<'de> Deserialize<'de> for Config {
struct ConfigVisitor;
impl<'d> Visitor<'d> for ConfigVisitor {
type Value = Config;
- #[inline]
fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
formatter.write_str("struct Config")
}
- #[allow(clippy::as_conversions, clippy::cast_lossless, clippy::too_many_lines)]
- #[inline]
+ #[expect(
+ clippy::as_conversions,
+ clippy::cast_lossless,
+ clippy::too_many_lines,
+ reason = "carefull verify use is correct"
+ )]
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: MapAccess<'d>,
{
/// Verifies that the `HashSet`s are pairwise disjoint.
- #[allow(
+ #[expect(
clippy::arithmetic_side_effects,
clippy::indexing_slicing,
- clippy::into_iter_on_ref
+ reason = "carefully verify use is correct"
)]
- #[inline]
fn hash_overlap<E: Error>(maps: &[&HashSet<HttpUrl>]) -> Result<(), E> {
/// Verifies the intersection of `left` and `right` is empty.
- #[inline]
fn url_overlap<E: Error>(
left: &HashSet<HttpUrl>,
right: &HashSet<HttpUrl>,
) -> Result<(), E> {
let (mut iter, urls) = if left.len() <= right.len() {
- (left.into_iter(), right)
+ (left.iter(), right)
} else {
- (right.into_iter(), left)
+ (right.iter(), left)
};
iter.try_fold((), |(), url| {
if urls.contains(url) {
@@ -169,16 +163,15 @@ impl<'de> Deserialize<'de> for Config {
}
})
}
- maps.into_iter().enumerate().try_fold((), |(), (idx, map)| {
+ maps.iter().enumerate().try_fold((), |(), (idx, map)| {
maps[idx + 1..]
- .into_iter()
+ .iter()
.try_fold((), |(), map2| url_overlap(map, map2))
})
}
/// Wrapper around a `HashSet` that is deserializable.
struct Urls(HashSet<HttpUrl>);
impl<'de> Deserialize<'de> for Urls {
- #[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
@@ -187,11 +180,9 @@ impl<'de> Deserialize<'de> for Config {
struct HashVisitor;
impl<'d> Visitor<'d> for HashVisitor {
type Value = Urls;
- #[inline]
fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
formatter.write_str("struct Urls")
}
- #[inline]
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'d>,
diff --git a/src/dom.rs b/src/dom.rs
@@ -22,7 +22,6 @@ use superset_map::SetOrd;
use zfc::{BoundedCardinality, Cardinality, Set};
/// Error returned when an invalid string is passed to [`Adblock::parse_value`], [`DomainOnly::parse_value`],
/// [`Hosts::parse_value`], [`Wildcard::parse_value`], or [`RpzDomain::parse_value`].
-#[allow(clippy::exhaustive_enums)]
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum FirefoxDomainErr {
/// The domain is invalid based on [`Domain`] using [`ASCII_FIREFOX`].
@@ -56,8 +55,7 @@ impl error::Error for FirefoxDomainErr {}
const CHARS: &AllowedAscii<[u8; 78]> = &ASCII_FIREFOX;
/// Parses a `[u8]` into a `Domain` using `CHARS` with the added restriction that the `Domain` has a TLD
/// that is either all letters or has length of at least five and begins with `b"xn--"`.
-#[allow(clippy::indexing_slicing)]
-#[inline]
+#[expect(clippy::indexing_slicing, reason = "we verify manually")]
fn domain_icann_tld<'a: 'b, 'b>(val: &'a [u8]) -> Result<Domain<&'b str>, FirefoxDomainErr> {
Domain::try_from_bytes(val, CHARS)
.map_err(FirefoxDomainErr::InvalidDomain)
@@ -72,7 +70,6 @@ fn domain_icann_tld<'a: 'b, 'b>(val: &'a [u8]) -> Result<Domain<&'b str>, Firefo
})
}
/// Action taken by a DNS server when a domain matches.
-#[allow(clippy::exhaustive_enums)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum RpzAction {
/// Send `NXDOMAIN` reply.
@@ -147,7 +144,6 @@ where
)
}
/// Type that can be returned by [`Domain`]-like parsers (e.g., [`Adblock`]).
-#[allow(clippy::exhaustive_enums)]
#[derive(Clone, Copy, Debug)]
pub enum Value<'a, T: ParsedDomain<'a>> {
/// The parsed value is a domain.
@@ -184,7 +180,7 @@ impl<'a, T: ParsedDomain<'a>> Value<'a, T> {
/// # Panics
///
/// Panics iff `self` is [`Self::Comment`] or [`Self::Blank`].
- #[allow(clippy::panic)]
+ #[expect(clippy::panic, reason = "bug if called incorrectly")]
#[inline]
pub fn unwrap_domain(self) -> T {
match self {
@@ -199,7 +195,7 @@ impl<'a, T: ParsedDomain<'a>> Value<'a, T> {
/// # Panics
///
/// Panics iff `self` is [`Self::Domain`] or [`Self::Blank`].
- #[allow(clippy::panic)]
+ #[expect(clippy::panic, reason = "bug if called incorrectly")]
#[inline]
pub fn unwrap_comment(self) -> &'a str {
match self {
@@ -214,7 +210,7 @@ impl<'a, T: ParsedDomain<'a>> Value<'a, T> {
/// # Panics
///
/// Panics iff `self` is [`Self::Domain`] or [`Self::Comment`].
- #[allow(clippy::panic)]
+ #[expect(clippy::panic, reason = "bug if called incorrectly")]
#[inline]
pub fn unwrap_blank(self) {
match self {
@@ -277,7 +273,6 @@ impl<'a> Adblock<'a> {
}
/// Since `DomainOnly` and `Hosts` are treated the same, we have this helper function that can be used
/// for both.
- #[inline]
#[must_use]
fn cmp_dom(&self, other: &Domain<&str>) -> Ordering {
match self.domain.cmp_by_domain_ordering(other) {
@@ -303,7 +298,7 @@ impl<'a> Adblock<'a> {
/// 1. Pairwise comparisons of each [`ascii_domain::dom::Label`] starting from the TLDs.
/// 2. If 1. evaluates as not equivalent, then return the result.
/// 3. If `self` represents a single `Domain` (i.e., `!self.is_subdomains()`),
- /// then return the comparison of label counts.
+ /// then return the comparison of label counts.
/// 4. `self` is greater.
///
/// For example, `com` `<` `example.com` `<` `||example.com` `<` `||com` `<` `net` `<` `example.net` `<` `||example.net` `<` `||net`.
@@ -322,7 +317,7 @@ impl<'a> Adblock<'a> {
/// 1. Pairwise comparisons of each [`ascii_domain::dom::Label`] starting from the TLDs.
/// 2. If 1. evaluates as not equivalent, then return the result.
/// 3. If both domains represent a single `Domain`, then return the comparison
- /// of label counts.
+ /// of label counts.
/// 4. If one domain represents a single `Domain`, then return that that domain is less.
/// 5. If the label counts are the same, `self` is greater.
/// 6. Return the inverse of the comparison of label counts.
@@ -372,7 +367,7 @@ impl<'a> Adblock<'a> {
/// the `Domain` itself when `self.is_subdomains()`.
///
/// `!self.is_subdomains()` ⇔ `self.domain_count() == BigUint::new(vec![1])`.
- #[allow(clippy::arithmetic_side_effects)]
+ #[expect(clippy::arithmetic_side_effects, reason = "arbitrary-sized arithmetic")]
#[inline]
#[must_use]
pub fn domain_count(&self) -> BigUint {
@@ -473,7 +468,7 @@ impl PartialEq<Adblock<'_>> for &Hosts<'_> {
}
}
impl PartialEq<Wildcard<'_>> for Adblock<'_> {
- #[allow(clippy::suspicious_operation_groupings)]
+ #[expect(clippy::suspicious_operation_groupings, reason = "false positive")]
#[inline]
fn eq(&self, other: &Wildcard<'_>) -> bool {
!(self.subdomains || other.proper_subdomains) && self.domain == other.domain
@@ -521,7 +516,7 @@ impl Ord for Adblock<'_> {
/// 1. Pairwise comparisons of each [`ascii_domain::dom::Label`] starting from the TLDs.
/// 2. If 1. evaluates as not equivalent, then return the result.
/// 3. If both domains represent a single `Domain`, then return the comparison
- /// of label counts.
+ /// of label counts.
/// 4. If one domain represents a single `Domain`, then return that that domain is less.
/// 5. Return the inverse of the comparison of label counts.
///
@@ -637,7 +632,11 @@ impl<'a> Deref for Adblock<'a> {
}
impl<'a> ParsedDomain<'a> for Adblock<'a> {
type Error = FirefoxDomainErr;
- #[allow(unsafe_code, clippy::indexing_slicing, clippy::into_iter_on_ref)]
+ #[expect(
+ unsafe_code,
+ clippy::indexing_slicing,
+ reason = "we carefully verify what we are doing"
+ )]
#[inline]
fn parse_value<'b: 'a>(val: &'b str) -> Result<Value<'a, Self>, Self::Error> {
// First remove leading whitepace. Then check for comments via '#' and '!'. Return Blank iff empty.
@@ -675,7 +674,7 @@ impl<'a> ParsedDomain<'a> for Adblock<'a> {
},
);
// `Domain`s allow `$`, but we don't want to allow that symbol for Adblock-style rules.
- val2.into_iter()
+ val2.iter()
.try_fold((), |(), byt2| {
if *byt2 == b'$' {
Err(FirefoxDomainErr::InvalidAdblockDomain)
@@ -754,7 +753,7 @@ impl<'a> DomainOnly<'a> {
/// Same as [`DomainOnly::cardinality`] except that a `NonZeroU8` is returned.
///
/// The value is always 1.
- #[allow(unsafe_code)]
+ #[expect(unsafe_code, reason = "trivial use of NonZeroU8::new_unchecked")]
#[inline]
#[must_use]
pub const fn domain_count(&self) -> NonZeroU8 {
@@ -927,11 +926,11 @@ impl<'a> Deref for DomainOnly<'a> {
}
impl<'a> ParsedDomain<'a> for DomainOnly<'a> {
type Error = FirefoxDomainErr;
- #[allow(
+ #[expect(
unsafe_code,
clippy::arithmetic_side_effects,
clippy::indexing_slicing,
- clippy::into_iter_on_ref
+ reason = "we verify all use is correct"
)]
#[inline]
fn parse_value<'b: 'a>(val: &'b str) -> Result<Value<'a, Self>, Self::Error> {
@@ -948,7 +947,7 @@ impl<'a> ParsedDomain<'a> for DomainOnly<'a> {
} else {
domain_icann_tld(
value[..value
- .into_iter()
+ .iter()
.try_fold(0, |i, byt2| if *byt2 == b'#' { Err(i) } else { Ok(i + 1) })
.map_or_else(convert::identity, convert::identity)]
.trim_ascii_end(),
@@ -1008,7 +1007,7 @@ impl<'a> Hosts<'a> {
/// Same as [`Hosts::cardinality`] except that a `NonZeroU8` is returned.
///
/// The value is always 1.
- #[allow(unsafe_code)]
+ #[expect(unsafe_code, reason = "trivial use of NonZeroU8::new_unchecked")]
#[inline]
#[must_use]
pub const fn domain_count(&self) -> NonZeroU8 {
@@ -1157,11 +1156,11 @@ impl<'a> Deref for Hosts<'a> {
}
impl<'a> ParsedDomain<'a> for Hosts<'a> {
type Error = FirefoxDomainErr;
- #[allow(
+ #[expect(
unsafe_code,
clippy::arithmetic_side_effects,
clippy::indexing_slicing,
- clippy::into_iter_on_ref
+ reason = "carefully verified use is correct"
)]
#[inline]
fn parse_value<'b: 'a>(val: &'b str) -> Result<Value<'a, Self>, Self::Error> {
@@ -1214,7 +1213,7 @@ impl<'a> ParsedDomain<'a> for Hosts<'a> {
} else {
domain_icann_tld(
value[..value
- .into_iter()
+ .iter()
.try_fold(
0,
|i, byt2| if *byt2 == b'#' { Err(i) } else { Ok(i + 1) },
@@ -1274,7 +1273,6 @@ impl<'a> Wildcard<'a> {
}
/// Since `DomainOnly` and `Hosts` are treated the same, we have this helper function that can be used
/// for both.
- #[inline]
#[must_use]
fn cmp_dom(&self, other: &Domain<&str>) -> Ordering {
match self.domain.cmp_by_domain_ordering(other) {
@@ -1300,7 +1298,7 @@ impl<'a> Wildcard<'a> {
/// 1. Pairwise comparisons of each [`ascii_domain::dom::Label`] starting from the TLDs.
/// 2. If 1. evaluates as not equivalent, then return the result.
/// 3. If `self` represents a single `Domain` (i.e., `!self.is_proper_subdomains()`),
- /// then return the comparison of label counts.
+ /// then return the comparison of label counts.
/// 4. Return `self` is greater.
///
/// For example, `com` `<` `example.com` `<` `*.example.com` `<` `*.com` `<` `net` `<` `example.net` `<` `*.example.net` `<` `*.net`.
@@ -1383,7 +1381,7 @@ impl Ord for Wildcard<'_> {
/// 1. Pairwise comparisons of each [`ascii_domain::dom::Label`] starting from the TLDs.
/// 2. If 1. evaluates as not equivalent, then return the result.
/// 3. If both domains represent a single `Domain`, then return the comparison
- /// of label counts.
+ /// of label counts.
/// 4. If one domain represents a single `Domain`, then return that that domain is less.
/// 5. Return the inverse of the comparison of label counts.
///
@@ -1503,11 +1501,11 @@ impl<'a> Deref for Wildcard<'a> {
}
impl<'a> ParsedDomain<'a> for Wildcard<'a> {
type Error = FirefoxDomainErr;
- #[allow(
+ #[expect(
unsafe_code,
clippy::arithmetic_side_effects,
clippy::indexing_slicing,
- clippy::into_iter_on_ref
+ reason = "need them all. care has been taken."
)]
#[inline]
fn parse_value<'b: 'a>(val: &'b str) -> Result<Value<'a, Self>, Self::Error> {
@@ -1534,7 +1532,7 @@ impl<'a> ParsedDomain<'a> for Wildcard<'a> {
);
domain_icann_tld(
val2[..val2
- .into_iter()
+ .iter()
.try_fold(0, |i, byt2| if *byt2 == b'#' { Err(i) } else { Ok(i + 1) })
.map_or_else(convert::identity, convert::identity)]
.trim_ascii_end(),
@@ -1570,7 +1568,6 @@ impl<'a> ParsedDomain<'a> for Wildcard<'a> {
}
}
/// A [`Domain`] in a [response policy zone (RPZ)](https://en.wikipedia.org/wiki/Response_policy_zone) file.
-#[allow(clippy::exhaustive_enums)]
#[derive(Clone, Debug)]
pub enum RpzDomain<'a> {
/// An `Adblock` domain.
@@ -1584,7 +1581,6 @@ pub enum RpzDomain<'a> {
}
impl<'a> RpzDomain<'a> {
/// Returns `true` iff `self` represents a single [`Domain`].
- #[allow(clippy::ref_patterns)]
#[inline]
#[must_use]
pub const fn is_domain(&self) -> bool {
@@ -1596,7 +1592,6 @@ impl<'a> RpzDomain<'a> {
}
/// Returns `true` iff `self` represents proper subdomains of the contained [`Domain`] (i.e.,
/// is a [`Wildcard`] such that [`Wildcard::is_proper_subdomains`]).
- #[allow(clippy::ref_patterns)]
#[inline]
#[must_use]
pub const fn is_proper_subdomains(&self) -> bool {
@@ -1607,7 +1602,6 @@ impl<'a> RpzDomain<'a> {
}
/// Returns `true` iff `self` represents subdomains of the contained [`Domain`] (i.e., is an
/// [`Adblock`] such that [`Adblock::is_subdomains`]).
- #[allow(clippy::ref_patterns)]
#[inline]
#[must_use]
pub const fn is_subdomains(&self) -> bool {
@@ -1618,7 +1612,6 @@ impl<'a> RpzDomain<'a> {
}
/// Returns the count of [`Domain`]s represented by `self`. This function is the same as
/// [`RpzDomain::cardinality`] except that it returns a `BigUint`.
- #[allow(clippy::ref_patterns)]
#[inline]
#[must_use]
pub fn domain_count(&self) -> BigUint {
@@ -1631,7 +1624,6 @@ impl<'a> RpzDomain<'a> {
}
}
impl PartialEq<RpzDomain<'_>> for RpzDomain<'_> {
- #[allow(clippy::ref_patterns)]
#[inline]
fn eq(&self, other: &RpzDomain<'_>) -> bool {
match *self {
@@ -1692,7 +1684,7 @@ impl Ord for RpzDomain<'_> {
/// 1. Pairwise comparisons of each [`ascii_domain::dom::Label`] starting from the TLDs.
/// 2. If 1. evaluates as not equivalent, then return the result.
/// 3. If both domains represent a single `Domain`, then return the comparison
- /// of label counts.
+ /// of label counts.
/// 4. If one domain represents a single `Domain`, then return that that domain is less.
/// 5. If the label counts are the same and exactly one domain represents proper subdomains, the other domain is greater.
/// 6. Return the inverse of the comparison of label counts.
@@ -1701,7 +1693,6 @@ impl Ord for RpzDomain<'_> {
/// ascending order:
///
/// `bar.com`, `www.bar.com`, `*.www.bar.com`, `||www.bar.com`, `*.bar.com`, `||bar.com`, `example.com`, `www.example.com`, `*.www.example.com`, `||www.example.com`, `*.example.com`, `||example.com`, `foo.com`, `www.foo.com`, `*.foo.com`, `*.com`, `example.net`, `*.net`
- #[allow(clippy::ref_patterns)]
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
match *self {
@@ -1733,7 +1724,6 @@ impl Ord for RpzDomain<'_> {
}
}
impl Display for RpzDomain<'_> {
- #[allow(clippy::ref_patterns)]
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
@@ -1754,7 +1744,6 @@ impl<'a> Set for RpzDomain<'a> {
fn cardinality(&self) -> Option<Cardinality> {
Some(Cardinality::Finite(self.domain_count()))
}
- #[allow(clippy::ref_patterns)]
#[inline]
fn contains<Q>(&self, elem: &Q) -> bool
where
@@ -1767,7 +1756,6 @@ impl<'a> Set for RpzDomain<'a> {
Self::Wildcard(ref dom) => dom.contains(elem),
}
}
- #[allow(clippy::ref_patterns)]
#[inline]
fn is_proper_subset(&self, val: &Self) -> bool {
match *val {
@@ -1824,7 +1812,6 @@ impl<'a> Set for RpzDomain<'a> {
impl SetOrd for RpzDomain<'_> {}
impl<'a> Deref for RpzDomain<'a> {
type Target = Domain<&'a str>;
- #[allow(clippy::ref_patterns)]
#[inline]
fn deref(&self) -> &Self::Target {
match *self {
@@ -1862,21 +1849,21 @@ impl<'a: 'b, 'b> From<Wildcard<'a>> for RpzDomain<'b> {
impl<'a> ParsedDomain<'a> for RpzDomain<'a> {
type Error = FirefoxDomainErr;
#[inline]
- fn parse_value<'b: 'a>(value: &'b str) -> Result<Value<'a, Self>, Self::Error> {
- DomainOnly::parse_value(value).map_or_else(
+ fn parse_value<'b: 'a>(val: &'b str) -> Result<Value<'a, Self>, Self::Error> {
+ DomainOnly::parse_value(val).map_or_else(
|_| {
- Hosts::parse_value(value).map_or_else(
+ Hosts::parse_value(val).map_or_else(
|_| {
- Wildcard::parse_value(value).map_or_else(
+ Wildcard::parse_value(val).map_or_else(
|_| {
- Adblock::parse_value(value).map(|val| match val {
+ Adblock::parse_value(val).map(|value| match value {
Value::Domain(dom) => Value::Domain(Self::Adblock(dom)),
Value::Comment(com) => Value::Comment(com),
Value::Blank => Value::Blank,
})
},
- |val| {
- Ok(match val {
+ |value| {
+ Ok(match value {
Value::Domain(dom) => Value::Domain(Self::Wildcard(dom)),
Value::Comment(com) => Value::Comment(com),
Value::Blank => Value::Blank,
@@ -1884,8 +1871,8 @@ impl<'a> ParsedDomain<'a> for RpzDomain<'a> {
},
)
},
- |val| {
- Ok(match val {
+ |value| {
+ Ok(match value {
Value::Domain(dom) => Value::Domain(Self::Hosts(dom)),
Value::Comment(com) => Value::Comment(com),
Value::Blank => Value::Blank,
@@ -1893,8 +1880,8 @@ impl<'a> ParsedDomain<'a> for RpzDomain<'a> {
},
)
},
- |val| {
- Ok(match val {
+ |value| {
+ Ok(match value {
Value::Domain(dom) => Value::Domain(Self::DomainOnly(dom)),
Value::Comment(com) => Value::Comment(com),
Value::Blank => Value::Blank,
@@ -1902,7 +1889,6 @@ impl<'a> ParsedDomain<'a> for RpzDomain<'a> {
},
)
}
- #[allow(clippy::ref_patterns)]
#[inline]
fn domain(&self) -> &Domain<&'a str> {
match *self {
@@ -1912,7 +1898,6 @@ impl<'a> ParsedDomain<'a> for RpzDomain<'a> {
Self::Wildcard(ref dom) => &dom.domain,
}
}
- #[allow(clippy::ref_patterns)]
#[inline]
fn write_to_rpz<W: Write>(&self, action: RpzAction, writer: W) -> Result<(), Error> {
match *self {
@@ -2194,7 +2179,7 @@ mod tests {
assert!(Wildcard::parse_value("*.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a").map_or_else(|e| e == FirefoxDomainErr::InvalidWildcardDomain, |_| false));
// Test 126 labels after wildcard is ok.
assert!(Wildcard::parse_value("*.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a").map_or(false, |val| match val {
- Value::Domain(ref dom) => dom.domain.into_iter().count() == 126 && dom.proper_subdomains,
+ Value::Domain(ref dom) => dom.domain.iter().count() == 126 && dom.proper_subdomains,
Value::Comment(_) | Value::Blank => false,
}));
// Test comment.
@@ -2314,9 +2299,9 @@ mod tests {
// We can have two labels each with one character,
// one label with one to three characters, or 0 labels.
// This is 1 + 52 + 52^2 + 52^3 + 52^2 = (1-52^4)/(1-52) + 52^2 = (52^4 - 1)/51 + 52^2 = 146069.
- assert!(Adblock::parse_value("||a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a").map_or(false, |val| { let dom = val.unwrap_domain(); dom.domain.len().get() == 249 && dom.domain.into_iter().count() == 125 && dom.domain_count() == BigUint::new(vec![146069]) }));
+ assert!(Adblock::parse_value("||a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a").map_or(false, |val| { let dom = val.unwrap_domain(); dom.domain.len().get() == 249 && dom.domain.iter().count() == 125 && dom.domain_count() == BigUint::new(vec![146069]) }));
// A subdomain of length 252 or 253 gets converted to a domain.
- assert!(Adblock::parse_value("||a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a").map_or(false, |val| { let dom = val.unwrap_domain(); dom.domain.into_iter().count() == 127 && !dom.subdomains && dom.domain_count() == BigUint::new(vec![1]) }));
+ assert!(Adblock::parse_value("||a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a").map_or(false, |val| { let dom = val.unwrap_domain(); dom.domain.iter().count() == 127 && !dom.subdomains && dom.domain_count() == BigUint::new(vec![1]) }));
// Pre-calculated manually.
// This is the number of domains possible between 2 and 252 characters.
assert!(Wildcard::parse_value("*.a").map_or(false, |val| {
diff --git a/src/dom_count_auto_gen.rs b/src/dom_count_auto_gen.rs
@@ -2,14 +2,14 @@ use ascii_domain::dom::Domain;
use num_bigint::BigUint;
/// The count of proper subdomains for both `Adblock` and `Wildcard` `Domain` when subdomains
/// and proper subdomains are represented respectively.
-#[allow(
+#[expect(
clippy::arithmetic_side_effects,
clippy::as_conversions,
clippy::indexing_slicing,
clippy::too_many_lines,
- clippy::unreadable_literal
+ clippy::unreadable_literal,
+ reason = "autogenerated code and need it all"
)]
-#[inline]
pub fn proper_subdomain_count(dom: &Domain<&str>) -> BigUint {
// The commented out code at the end of the function was used to calculate the cardinalities
// for each possible value of domain length; however it takes as much as 16 seconds to calculate
diff --git a/src/file.rs b/src/file.rs
@@ -5,6 +5,7 @@ use crate::dom::{
use alloc::string::FromUtf8Error;
use core::{
borrow::Borrow,
+ error::Error,
fmt::{self, Display, Formatter},
hash::Hash,
ops::Deref,
@@ -14,7 +15,6 @@ use reqwest::Client;
use serde::de::{self, Deserialize, Deserializer, Unexpected, Visitor};
use std::{
collections::{HashMap, HashSet},
- error::Error,
fs,
io::{self, ErrorKind},
path::{Path, PathBuf},
@@ -80,7 +80,7 @@ impl<const IS_DIR: bool> AbsFilePath<IS_DIR> {
///
/// If `IS_DIR` and `PathBuf::from(val).as_bytes().last().unwrap() != b'/'`, `val`
/// will have `/` appended to it.
- #[allow(clippy::option_if_let_else)]
+ #[expect(clippy::option_if_let_else, reason = "map will not work")]
#[inline]
#[must_use]
pub fn from_string(val: String) -> Option<Self> {
@@ -131,7 +131,7 @@ impl<const IS_DIR: bool> From<AbsFilePath<IS_DIR>> for PathBuf {
}
}
impl<'de, const IS_DIR: bool> Deserialize<'de> for AbsFilePath<IS_DIR> {
- #[allow(clippy::too_many_lines)]
+ #[expect(clippy::too_many_lines, reason = "this is fine")]
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -141,12 +141,10 @@ impl<'de, const IS_DIR: bool> Deserialize<'de> for AbsFilePath<IS_DIR> {
struct FilePathVisitor<const IS_DIR: bool>;
impl<'de, const IS_DIR: bool> Visitor<'de> for FilePathVisitor<IS_DIR> {
type Value = AbsFilePath<IS_DIR>;
- #[inline]
fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
formatter.write_str("struct AbsFilePath")
}
- #[allow(clippy::arithmetic_side_effects)]
- #[inline]
+ #[expect(clippy::arithmetic_side_effects, reason = "math has been verified")]
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
@@ -161,8 +159,7 @@ impl<'de, const IS_DIR: bool> Deserialize<'de> for AbsFilePath<IS_DIR> {
|byt| {
if *byt == b'/' {
if IS_DIR {
- let mut path = PathBuf::with_capacity(v.len());
- path.push(v);
+ let path = PathBuf::with_capacity(v.len()).join(v);
if path.is_absolute() {
Ok(AbsFilePath { path })
} else {
@@ -178,8 +175,7 @@ impl<'de, const IS_DIR: bool> Deserialize<'de> for AbsFilePath<IS_DIR> {
))
}
} else if IS_DIR {
- let mut path = PathBuf::with_capacity(v.len() + 1);
- path.push(v);
+ let mut path = PathBuf::with_capacity(v.len() + 1).join(v);
path.as_mut_os_string().push("/");
if path.is_absolute() {
Ok(AbsFilePath { path })
@@ -190,8 +186,7 @@ impl<'de, const IS_DIR: bool> Deserialize<'de> for AbsFilePath<IS_DIR> {
))
}
} else {
- let mut path = PathBuf::with_capacity(v.len());
- path.push(v);
+ let path = PathBuf::with_capacity(v.len()).join(v);
if path.is_absolute() && path.file_name().is_some() {
Ok(AbsFilePath { path })
} else {
@@ -204,7 +199,6 @@ impl<'de, const IS_DIR: bool> Deserialize<'de> for AbsFilePath<IS_DIR> {
},
)
}
- #[inline]
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: de::Error,
@@ -329,11 +323,9 @@ impl<'de> Deserialize<'de> for HttpUrl {
struct UrlVisitor;
impl<'d> Visitor<'d> for UrlVisitor {
type Value = HttpUrl;
- #[inline]
fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
formatter.write_str("struct HttpUrl")
}
- #[inline]
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
@@ -363,7 +355,6 @@ impl<'de> Deserialize<'de> for HttpUrl {
}
/// Represents the kind of [`ParsedDomain`]s a [`File`]
/// contains.
-#[allow(clippy::exhaustive_enums)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Kind {
/// [`Adblock`] domains.
@@ -387,7 +378,6 @@ impl Display for Kind {
}
}
/// The name where a [`File`] was sourced from.
-#[allow(clippy::exhaustive_enums)]
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum Name {
/// The `File` came from the contained `AbsFilePath`.
@@ -396,7 +386,6 @@ pub enum Name {
Url(HttpUrl),
}
impl Display for Name {
- #[allow(clippy::ref_patterns)]
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
@@ -487,25 +476,21 @@ trait Helper {
fn kind() -> Kind;
}
impl Helper for Adblock<'_> {
- #[inline]
fn kind() -> Kind {
Kind::Adblock
}
}
impl Helper for DomainOnly<'_> {
- #[inline]
fn kind() -> Kind {
Kind::DomainOnly
}
}
impl Helper for Hosts<'_> {
- #[inline]
fn kind() -> Kind {
Kind::Hosts
}
}
impl Helper for Wildcard<'_> {
- #[inline]
fn kind() -> Kind {
Kind::Wildcard
}
@@ -576,7 +561,7 @@ impl Files {
///
/// Returns a `Vec` containing `Summary` information for each
/// [`File`] that was parsed.
- #[allow(clippy::arithmetic_side_effects, clippy::into_iter_on_ref)]
+ #[expect(clippy::arithmetic_side_effects, reason = "math is verified")]
#[inline]
pub fn add_to_superset<'a: 'b, 'b>(
&'a self,
@@ -584,7 +569,6 @@ impl Files {
) -> Vec<Summary<'a, FirefoxDomainErr>> {
/// Iterates each `String` from `files` and transforms each line
/// into `T` before adding it as an `RpzDomain` into `doms`.
- #[inline]
fn insert<
'a,
'b: 'a,
@@ -595,7 +579,7 @@ impl Files {
summaries: &mut Vec<Summary<'b, FirefoxDomainErr>>,
) {
let kind = T::kind();
- files.into_iter().fold((), |(), file| {
+ files.iter().fold((), |(), file| {
let mut summary = Summary {
file,
kind,
@@ -668,11 +652,13 @@ impl LocalFiles {
///
/// Returns [`io::Error`] iff reading said files causes an error. Note that
/// it is _not_ an error if a directory does not exist.
- #[allow(clippy::wildcard_enum_match_arm)]
+ #[expect(
+ clippy::wildcard_enum_match_arm,
+ reason = "too many to enumerate manually"
+ )]
#[inline]
pub fn from_path(dir: AbsFilePath<true>) -> Result<Option<Self>, io::Error> {
/// Checks if `path` exists.
- #[inline]
fn exists<P: AsRef<Path>>(path: P) -> Result<bool, io::Error> {
fs::metadata(path).map_or_else(
|err| match err.kind() {
@@ -684,14 +670,12 @@ impl LocalFiles {
}
/// Reads all files stored in `adblock/`, `domain/`, `hosts/`, and `wildcard/`
/// directories under `dir/name/`.
- #[inline]
fn get_files(
mut dir: PathBuf,
files: &mut Files,
name: &str,
) -> Result<PathBuf, io::Error> {
/// Reads all files under `dir/name/`.
- #[inline]
fn get_file(
files: &mut Vec<File>,
mut dir: PathBuf,
@@ -742,7 +726,6 @@ impl LocalFiles {
}
}
/// Error returned when downloading text files from HTTP(S) servers.
-#[allow(clippy::exhaustive_enums)]
#[derive(Debug)]
pub enum ExtFileErr {
/// Error when a task exceeds the specified timeout.
@@ -755,7 +738,6 @@ pub enum ExtFileErr {
InvalidUtf8(FromUtf8Error),
}
impl Display for ExtFileErr {
- #[allow(clippy::ref_patterns)]
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
@@ -855,8 +837,7 @@ impl ExternalFiles {
}
/// Downloads the files from `urls` and converts them to `String`s adding the
/// tasks to `set`.
- #[allow(clippy::iter_over_hash_type)]
- #[inline]
+ #[expect(clippy::iter_over_hash_type, reason = "order does not matter")]
fn get_external_files(
set: &mut JoinSet<Result<File, ExtFileErr>>,
client: &'static Client,
diff --git a/src/lib.rs b/src/lib.rs
@@ -10,7 +10,6 @@
//! ad-blocking files into a [response policy zone (RPZ)](https://en.wikipedia.org/wiki/Response_policy_zone)
//! file easier.
#![feature(btree_cursors)]
-#![feature(byte_slice_trim_ascii)]
#![feature(io_error_more)]
#![cfg_attr(doc, feature(doc_auto_cfg))]
#![deny(
@@ -36,17 +35,18 @@
clippy::style,
clippy::suspicious
)]
-#![allow(
+#![expect(
clippy::blanket_clippy_restriction_lints,
+ clippy::exhaustive_enums,
clippy::exhaustive_structs,
clippy::implicit_return,
clippy::min_ident_chars,
clippy::missing_trait_methods,
clippy::multiple_crate_versions,
clippy::question_mark_used,
- clippy::single_call_fn,
+ clippy::ref_patterns,
clippy::single_char_lifetime_names,
- clippy::unseparated_literal_suffix
+ reason = "never want to use these lints"
)]
/// Module for hostname-like domains including parsing [`str`]s
/// from a variety of formats.
diff --git a/src/main.rs b/src/main.rs
@@ -26,16 +26,18 @@
clippy::style,
clippy::suspicious
)]
-#![allow(
+#![expect(
clippy::blanket_clippy_restriction_lints,
clippy::implicit_return,
clippy::min_ident_chars,
clippy::missing_trait_methods,
clippy::multiple_crate_versions,
clippy::question_mark_used,
+ clippy::ref_patterns,
clippy::single_call_fn,
clippy::single_char_lifetime_names,
- clippy::unseparated_literal_suffix
+ clippy::unseparated_literal_suffix,
+ reason = "never want to use these lints"
)]
/// Contains a wrapper of block and unblock `RpzDomain`s
/// which can be used to write to a `File` or `stdout`.
@@ -44,7 +46,6 @@ mod app;
mod args;
/// Module for the TOML config file.
mod config;
-#[allow(clippy::doc_markdown)]
/// Contains functions for `pledge(2)` and `unveil(2)` on OpenBSD platforms when compiled
/// with the `priv_sep` feature; otherwise almost all functions are no-ops.
mod priv_sep;
@@ -54,6 +55,7 @@ use crate::{
config::Config,
};
use core::{
+ error::Error,
fmt::{self, Display, Formatter},
time::Duration,
};
@@ -66,7 +68,6 @@ use rpz::{
};
use std::{
collections::HashSet,
- error::Error,
fs,
io::{self, Read, Write},
sync::OnceLock,
@@ -94,7 +95,6 @@ const VERSION: &str = concat!("rpz ", env!("CARGO_PKG_VERSION"));
/// The User-Agent header value sent to HTTP(S) servers.
const USER_AGENT: &str = concat!("rpz/", env!("CARGO_PKG_VERSION"));
/// Error returned from the program.
-#[allow(clippy::exhaustive_enums)]
enum E {
/// Variant for errors due to incorrect arguments being passed.
Args(ArgsErr),
@@ -111,8 +111,6 @@ enum E {
NoBlockEntries,
}
impl fmt::Debug for E {
- #[allow(clippy::ref_patterns)]
- #[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
Self::Args(ref e) => write!(f, "{e}.\nFor more information, try '--help'."),
@@ -125,8 +123,6 @@ impl fmt::Debug for E {
}
}
impl Display for E {
- #[allow(clippy::ref_patterns)]
- #[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
Self::Args(ref e) => e.fmt(f),
@@ -141,45 +137,38 @@ impl Display for E {
}
impl Error for E {}
impl From<ArgsErr> for E {
- #[inline]
fn from(value: ArgsErr) -> Self {
Self::Args(value)
}
}
impl From<de::Error> for E {
- #[inline]
fn from(value: de::Error) -> Self {
Self::Config(value)
}
}
impl From<io::Error> for E {
- #[inline]
fn from(value: io::Error) -> Self {
Self::Io(value)
}
}
impl From<ExtFileErr> for E {
- #[inline]
fn from(value: ExtFileErr) -> Self {
Self::ExtFile(value)
}
}
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
impl From<UnveilErr> for E {
- #[inline]
fn from(value: UnveilErr) -> Self {
Self::Unveil(value)
}
}
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
impl From<!> for E {
- #[inline]
fn from(value: !) -> Self {
value
}
}
/// Reads `Config` from `conf`.
-#[inline]
fn get_config(conf: ConfigPath) -> Result<Config, E> {
toml::from_str::<Config>(
match conf {
@@ -200,7 +189,6 @@ fn get_config(conf: ConfigPath) -> Result<Config, E> {
.map_err(E::Config)
}
/// Gets `LocalFiles` from `local_dir`.
-#[inline]
fn get_local_files(local_dir: Option<AbsFilePath<true>>) -> Result<Option<LocalFiles>, E> {
local_dir.map_or_else(
|| Ok(None),
@@ -222,8 +210,7 @@ fn get_local_files(local_dir: Option<AbsFilePath<true>>) -> Result<Option<LocalF
)
}
/// Downloads block files from HTTP(S) servers.
-#[allow(clippy::unwrap_used)]
-#[inline]
+#[expect(clippy::unreachable, reason = "there is a bug and we want to crash")]
fn get_external_files(
timeout: Duration,
adblock: HashSet<HttpUrl>,
@@ -249,8 +236,12 @@ fn get_external_files(
.build()
.map_err(ExtFileErr::Http)?,
)
- .unwrap();
- let client = CLIENT.get().unwrap();
+ .unwrap_or_else(|_e| {
+ unreachable!("there is a bug in OnceLock::set")
+ });
+ let client = CLIENT
+ .get()
+ .unwrap_or_else(|| unreachable!("there is a bug in OnceLock::get"));
files.add_adblock(client, adblock);
files.add_domain(client, domain);
files.add_hosts(client, hosts);
@@ -277,7 +268,6 @@ enum Verbosity {
}
/// Writes to `stdout` the summary information in the event the quiet
/// option was not passed.
-#[inline]
fn write_summary(
summaries: Vec<Summary<'_, FirefoxDomainErr>>,
verbose: bool,
@@ -317,7 +307,11 @@ fn write_summary(
error_count,
)
}
-#[allow(clippy::arithmetic_side_effects, clippy::unwrap_used)]
+#[expect(
+ clippy::arithmetic_side_effects,
+ clippy::unreachable,
+ reason = "math is correct and we want to crash if there is a bug"
+)]
fn main() -> Result<(), E> {
let mut promises = priv_sep::pledge_init()?;
priv_sep::veil_all()?;
@@ -399,8 +393,12 @@ fn main() -> Result<(), E> {
if domains.block().is_empty() {
return Err(E::NoBlockEntries);
}
- let (unblock_count, block_count) =
- domains.write(config.rpz.map(|file| (file, tmp_rpz.unwrap())))?;
+ let (unblock_count, block_count) = domains.write(config.rpz.map(|file| {
+ (
+ file,
+ tmp_rpz.unwrap_or_else(|| unreachable!("there is a bug in main")),
+ )
+ }))?;
if matches!(verbosity, Verbosity::None) {
Ok(())
} else {
diff --git a/src/priv_sep.rs b/src/priv_sep.rs
@@ -1,7 +1,7 @@
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
pub use priv_sep::UnveilErr;
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
-use priv_sep::{self, Permissions, Promise, Promises};
+use priv_sep::{self, Permission, Permissions, Promise, Promises};
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
use std::env;
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
@@ -20,8 +20,7 @@ pub struct Zst;
/// to run. Specifically, the `Promise`s `Cpath`, `Dns`, `Inet`, `Rpath`, `Stdio`, `Unveil`, and `Wpath`
/// are passed.
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
-#[inline]
-pub fn pledge_init() -> Result<Promises<7>, Error> {
+pub fn pledge_init() -> Result<Promises, Error> {
let promises = Promises::new([
Promise::Cpath,
Promise::Dns,
@@ -37,9 +36,8 @@ pub fn pledge_init() -> Result<Promises<7>, Error> {
}
}
/// No-op that always returns `Ok`.
-#[allow(clippy::unnecessary_wraps)]
+#[expect(clippy::unnecessary_wraps, reason = "need to align with OpenBSD code")]
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
-#[inline]
pub const fn pledge_init() -> Result<Zst, !> {
Ok(Zst)
}
@@ -48,104 +46,85 @@ pub const fn pledge_init() -> Result<Zst, !> {
/// This should only be called when `stdout` is written to
/// instead of an RPZ file.
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
-#[inline]
-pub fn pledge_away_create_write(promises: &mut Promises<7>) -> Result<(), Error> {
- promises.remove_promises([Promise::Cpath, Promise::Wpath]);
- promises.pledge()
+pub fn pledge_away_create_write(promises: &mut Promises) -> Result<(), Error> {
+ promises.remove_promises_then_pledge([Promise::Cpath, Promise::Wpath])
}
/// No-op that always returns `Ok`.
-#[allow(clippy::unnecessary_wraps)]
+#[expect(clippy::unnecessary_wraps, reason = "need to align with OpenBSD code")]
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
-#[inline]
pub fn pledge_away_create_write(_: &mut Zst) -> Result<(), !> {
Ok(())
}
/// Removes `Promise::Unveil`.
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
-#[inline]
-pub fn pledge_away_unveil(promises: &mut Promises<7>) -> Result<(), Error> {
- promises.remove(Promise::Unveil);
- promises.pledge()
+pub fn pledge_away_unveil(promises: &mut Promises) -> Result<(), Error> {
+ promises.remove_then_pledge(Promise::Unveil)
}
/// No-op that always returns `Ok`.
-#[allow(clippy::unnecessary_wraps)]
+#[expect(clippy::unnecessary_wraps, reason = "need to align with OpenBSD code")]
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
-#[inline]
pub fn pledge_away_unveil(_: &mut Zst) -> Result<(), !> {
Ok(())
}
/// Removes `Promise::Dns` and `Promise::Inet`.
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
-#[inline]
-pub fn pledge_away_net(promises: &mut Promises<7>) -> Result<(), Error> {
- promises.remove_promises(Promises::new([Promise::Dns, Promise::Inet]));
- promises.pledge()
+pub fn pledge_away_net(promises: &mut Promises) -> Result<(), Error> {
+ promises.remove_promises_then_pledge([Promise::Dns, Promise::Inet])
}
/// No-op that always returns `Ok`.
-#[allow(clippy::unnecessary_wraps)]
+#[expect(clippy::unnecessary_wraps, reason = "need to align with OpenBSD code")]
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
-#[inline]
pub fn pledge_away_net(_: &mut Zst) -> Result<(), !> {
Ok(())
}
/// Removes all `Promise`s except `Stdio`.
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
-#[inline]
-pub fn pledge_away_all_but_stdio(promises: &mut Promises<7>) -> Result<(), Error> {
- promises.retain([Promise::Stdio]);
- promises.pledge()
+pub fn pledge_away_all_but_stdio(promises: &mut Promises) -> Result<(), Error> {
+ promises.retain_then_pledge([Promise::Stdio])
}
/// No-op that always returns `Ok`.
-#[allow(clippy::unnecessary_wraps)]
+#[expect(clippy::unnecessary_wraps, reason = "need to align with OpenBSD code")]
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
-#[inline]
pub fn pledge_away_all_but_stdio(_: &mut Zst) -> Result<(), !> {
Ok(())
}
/// Calls `unveil`_on `path` with no `Permissions`.
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
-#[inline]
pub fn unveil_none<P: AsRef<Path>>(path: P) -> Result<(), UnveilErr> {
Permissions::NONE.unveil(path)
}
/// No-op that always returns `Ok`.
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
-#[allow(clippy::unnecessary_wraps)]
-#[inline]
+#[expect(clippy::unnecessary_wraps, reason = "need to align with OpenBSD code")]
pub fn unveil_none<P: AsRef<Path>>(_: P) -> Result<(), !> {
Ok(())
}
/// Calls `unveil_none` on `/`.
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
-#[inline]
pub fn veil_all() -> Result<(), UnveilErr> {
unveil_none("/")
}
/// No-op that always returns `Ok`.
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
-#[allow(clippy::unnecessary_wraps)]
-#[inline]
+#[expect(clippy::unnecessary_wraps, reason = "need to align with OpenBSD code")]
pub const fn veil_all() -> Result<(), !> {
Ok(())
}
/// Calls `unveil`_on `path` with `Permissions::CREATE`.
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
-#[inline]
pub fn unveil_create<P: AsRef<Path>>(path: P) -> Result<(), UnveilErr> {
Permissions::CREATE.unveil(path)
}
/// No-op that always returns `Ok`.
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
-#[allow(clippy::unnecessary_wraps)]
-#[inline]
+#[expect(clippy::unnecessary_wraps, reason = "need to align with OpenBSD code")]
pub fn unveil_create<P: AsRef<Path>>(_: P) -> Result<(), !> {
Ok(())
}
/// Calls `unveil`_on `path` with `Permissions::READ` and returns
/// `true` iff `path` exists.
-#[allow(clippy::wildcard_enum_match_arm)]
+#[expect(clippy::wildcard_enum_match_arm)]
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
-#[inline]
pub fn unveil_read_dir<P: AsRef<Path>>(path: P) -> Result<bool, UnveilErr> {
Permissions::READ.unveil(path).map_or_else(
|err| match err {
@@ -159,9 +138,11 @@ pub fn unveil_read_dir<P: AsRef<Path>>(path: P) -> Result<bool, UnveilErr> {
)
}
/// Returns `true` iff `path` exists
-#[allow(clippy::wildcard_enum_match_arm)]
+#[expect(
+ clippy::wildcard_enum_match_arm,
+ reason = "too many branches to write out manually"
+)]
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
-#[inline]
pub fn unveil_read_dir<P: AsRef<Path>>(path: P) -> Result<bool, Error> {
fs::metadata(path).map_or_else(
|err| match err.kind() {
@@ -173,14 +154,12 @@ pub fn unveil_read_dir<P: AsRef<Path>>(path: P) -> Result<bool, Error> {
}
/// Calls `unveil`_on `path` with `Permissions::READ`.
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
-#[inline]
pub fn unveil_read_file<P: AsRef<Path>>(path: P) -> Result<(), UnveilErr> {
Permissions::READ.unveil(path)
}
/// No-op that always returns `Ok`.
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
-#[allow(clippy::unnecessary_wraps)]
-#[inline]
+#[expect(clippy::unnecessary_wraps, reason = "need to align with OpenBSD code")]
pub fn unveil_read_file<P: AsRef<Path>>(_: P) -> Result<(), !> {
Ok(())
}
@@ -188,32 +167,34 @@ pub fn unveil_read_file<P: AsRef<Path>>(_: P) -> Result<(), !> {
/// in addition to setting the `SSL_CERT_FILE` variable to `/etc/ssl/cert.pem`.
/// We rely on `SSL_CERT_FILE` as that allows one to `unveil(2)` only `/etc/ssl/cert.pem`
/// instead of `/etc/ssl/`.
+#[expect(unsafe_code)]
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
-#[inline]
pub fn unveil_https() -> Result<(), UnveilErr> {
/// The path to the root certificate store.
const CERTS: &str = "/etc/ssl/cert.pem";
- unveil_read_file(CERTS).map(|()| env::set_var("SSL_CERT_FILE", CERTS))
+ unveil_read_file(CERTS).map(|()| {
+ // SAFETY:
+ // `unveil_https` is only called in `super::main`
+ // in a single-threaded context; thus this is OK.
+ unsafe { env::set_var("SSL_CERT_FILE", CERTS) }
+ })
}
/// No-op that always returns `Ok`.
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
-#[allow(clippy::unnecessary_wraps)]
-#[inline]
+#[expect(clippy::unnecessary_wraps, reason = "need to align with OpenBSD code")]
pub const fn unveil_https() -> Result<(), !> {
Ok(())
}
/// Calls `unveil`_on `path` with create, read, and write `Permissions`.
#[cfg(all(feature = "priv_sep", target_os = "openbsd"))]
-#[inline]
pub fn unveil_create_read_write<P: AsRef<Path>>(path: P) -> Result<(), UnveilErr> {
let mut perms = Permissions::ALL;
- perms.execute = false;
+ perms.disable(Permission::Execute);
perms.unveil(path)
}
/// No-op that always returns `Ok`.
#[cfg(not(all(feature = "priv_sep", target_os = "openbsd")))]
-#[allow(clippy::unnecessary_wraps)]
-#[inline]
+#[expect(clippy::unnecessary_wraps, reason = "need to align with OpenBSD code")]
pub fn unveil_create_read_write<P: AsRef<Path>>(_: P) -> Result<(), !> {
Ok(())
}