diff --git a/lychee-lib/src/client.rs b/lychee-lib/src/client.rs index 9795a44..b7858e9 100644 --- a/lychee-lib/src/client.rs +++ b/lychee-lib/src/client.rs @@ -33,6 +33,7 @@ use crate::{ checker::{file::FileChecker, mail::MailChecker, website::WebsiteChecker}, filter::{Excludes, Filter, Includes}, remap::Remaps, + types::DEFAULT_ACCEPTED_STATUS_CODES, }; /// Default number of redirects before a request is deemed as failed, 5. @@ -238,7 +239,7 @@ pub struct ClientBuilder { /// Set of accepted return codes / status codes. /// /// Unmatched return codes/ status codes are deemed as errors. - #[builder(default = HashSet::try_from(StatusCodeSelector::default()).unwrap())] + #[builder(default = DEFAULT_ACCEPTED_STATUS_CODES.clone())] accepted: HashSet, /// Response timeout per request in seconds. diff --git a/lychee-lib/src/types/status_code/selector.rs b/lychee-lib/src/types/status_code/selector.rs index 6574dd0..17324be 100644 --- a/lychee-lib/src/types/status_code/selector.rs +++ b/lychee-lib/src/types/status_code/selector.rs @@ -1,4 +1,4 @@ -use std::{collections::HashSet, fmt::Display, str::FromStr}; +use std::{collections::HashSet, fmt::Display, hash::BuildHasher, str::FromStr, sync::LazyLock}; use http::StatusCode; use serde::{Deserialize, de::Visitor}; @@ -6,6 +6,11 @@ use thiserror::Error; use crate::{AcceptRangeError, types::accept::AcceptRange}; +/// These values are the default status codes which are accepted by lychee. +/// SAFETY: This does not panic as all provided status codes are valid. +pub static DEFAULT_ACCEPTED_STATUS_CODES: LazyLock> = + LazyLock::new(|| >::try_from(StatusCodeSelector::default()).unwrap()); + #[derive(Debug, Error, PartialEq)] pub enum StatusCodeSelectorError { #[error("invalid/empty input")] @@ -45,6 +50,7 @@ impl FromStr for StatusCodeSelector { } } +/// These values are the default status codes which are accepted by lychee. impl Default for StatusCodeSelector { fn default() -> Self { Self::new_from(vec![AcceptRange::new(100, 103), AcceptRange::new(200, 299)]) @@ -105,7 +111,7 @@ impl StatusCodeSelector { } } -impl From for HashSet { +impl From for HashSet { fn from(value: StatusCodeSelector) -> Self { value .ranges @@ -115,7 +121,7 @@ impl From for HashSet { } } -impl TryFrom for HashSet { +impl TryFrom for HashSet { type Error = http::status::InvalidStatusCode; fn try_from(value: StatusCodeSelector) -> Result { @@ -190,7 +196,6 @@ impl<'de> Deserialize<'de> for StatusCodeSelector { #[cfg(test)] mod test { use super::*; - use http::status::InvalidStatusCode; use rstest::rstest; #[rstest] @@ -261,4 +266,10 @@ mod test { let actual: HashSet = StatusCodeSelector::from_str(input).unwrap().into(); assert_eq!(actual, expected); } + + #[test] + fn test_default_accepted_values() { + // assert that accessing the value does not panic as described in the SAFETY note. + let _ = &*DEFAULT_ACCEPTED_STATUS_CODES; + } }