Use invariant
instead of unwrap
and expect
Add the `Invariant` trait, which provides `Invariant::invariant` and `Invariant::invariant_unwrap` methods, and use them instead of unwrap and expect. I think these methods are a bit clearer than `unwrap` and `expect`, since they more clearly document intent, i.e. that the thing passed to `invariant` should be a description of an invariant that should always be true, and should provide better error messages. Replace uses of `unwrap` and `expect` with `invariant`. type: reform fixes: - https://github.com/casey/intermodal/issues/167
This commit is contained in:
parent
faf46c0f0e
commit
a6bf752791
|
@ -4,7 +4,8 @@ Changelog
|
||||||
|
|
||||||
UNRELEASED - 2020-04-18
|
UNRELEASED - 2020-04-18
|
||||||
-----------------------
|
-----------------------
|
||||||
- :white_check_mark: [`xxxxxxxxxxxx`](https://github.com/casey/intermodal/commits/master) Test that globs match torrent contents - Fixes [#377](https://github.com/casey/intermodal/issues/377) - _Casey Rodarmor <casey@rodarmor.com>_
|
- :art: [`xxxxxxxxxxxx`](https://github.com/casey/intermodal/commits/master) Use `invariant` instead of `unwrap` and `expect` - Fixes [#167](https://github.com/casey/intermodal/issues/167) - _Casey Rodarmor <casey@rodarmor.com>_
|
||||||
|
- :white_check_mark: [`faf46c0f0e6f`](https://github.com/casey/intermodal/commit/faf46c0f0e6fd4e4f8b504d414a3bf02d7d68e4a) Test that globs match torrent contents - Fixes [#377](https://github.com/casey/intermodal/issues/377) - _Casey Rodarmor <casey@rodarmor.com>_
|
||||||
- :books: [`0a754d0bcfcf`](https://github.com/casey/intermodal/commit/0a754d0bcfcfd65127d7b6e78d41852df78d3ea2) Add manual Arch install link - Fixes [#373](https://github.com/casey/intermodal/issues/373) - _Casey Rodarmor <casey@rodarmor.com>_
|
- :books: [`0a754d0bcfcf`](https://github.com/casey/intermodal/commit/0a754d0bcfcfd65127d7b6e78d41852df78d3ea2) Add manual Arch install link - Fixes [#373](https://github.com/casey/intermodal/issues/373) - _Casey Rodarmor <casey@rodarmor.com>_
|
||||||
- :art: [`0a870ed2ee2c`](https://github.com/casey/intermodal/commit/0a870ed2ee2cca79fddb9940fb879354468deb4d) Get current time early when creating torrents - Fixes [#207](https://github.com/casey/intermodal/issues/207) - _Casey Rodarmor <casey@rodarmor.com>_
|
- :art: [`0a870ed2ee2c`](https://github.com/casey/intermodal/commit/0a870ed2ee2cca79fddb9940fb879354468deb4d) Get current time early when creating torrents - Fixes [#207](https://github.com/casey/intermodal/issues/207) - _Casey Rodarmor <casey@rodarmor.com>_
|
||||||
- :books: [`9098d3684032`](https://github.com/casey/intermodal/commit/9098d368403232a07684cae8c0b9b1f1383dd2ce) Readme improvements - _Casey Rodarmor <casey@rodarmor.com>_
|
- :books: [`9098d3684032`](https://github.com/casey/intermodal/commit/9098d368403232a07684cae8c0b9b1f1383dd2ce) Readme improvements - _Casey Rodarmor <casey@rodarmor.com>_
|
||||||
|
|
|
@ -55,8 +55,9 @@ pub(crate) use crate::{consts, error, host_port_parse_error};
|
||||||
|
|
||||||
// traits
|
// traits
|
||||||
pub(crate) use crate::{
|
pub(crate) use crate::{
|
||||||
input_stream::InputStream, into_u64::IntoU64, into_usize::IntoUsize, path_ext::PathExt,
|
input_stream::InputStream, into_u64::IntoU64, into_usize::IntoUsize, invariant::Invariant,
|
||||||
platform_interface::PlatformInterface, print::Print, reckoner::Reckoner, step::Step,
|
path_ext::PathExt, platform_interface::PlatformInterface, print::Print, reckoner::Reckoner,
|
||||||
|
step::Step,
|
||||||
};
|
};
|
||||||
|
|
||||||
// structs and enums
|
// structs and enums
|
||||||
|
|
|
@ -173,7 +173,10 @@ impl From<SystemTimeError> for Error {
|
||||||
|
|
||||||
impl From<walkdir::Error> for Error {
|
impl From<walkdir::Error> for Error {
|
||||||
fn from(walkdir_error: walkdir::Error) -> Self {
|
fn from(walkdir_error: walkdir::Error) -> Self {
|
||||||
let path = walkdir_error.path().unwrap().to_owned();
|
let path = walkdir_error
|
||||||
|
.path()
|
||||||
|
.invariant_unwrap("Walkdir errors always have path")
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
if let Some(source) = walkdir_error.into_io_error() {
|
if let Some(source) = walkdir_error.into_io_error() {
|
||||||
Self::Filesystem { source, path }
|
Self::Filesystem { source, path }
|
||||||
|
|
|
@ -19,11 +19,18 @@ impl FromStr for HostPort {
|
||||||
$
|
$
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.invariant_unwrap("regex is valid");
|
||||||
|
|
||||||
if let Some(captures) = socket_address_re.captures(text) {
|
if let Some(captures) = socket_address_re.captures(text) {
|
||||||
let host_text = captures.name("host").unwrap().as_str();
|
let host_text = captures
|
||||||
let port_text = captures.name("port").unwrap().as_str();
|
.name("host")
|
||||||
|
.invariant_unwrap("Capture group `host` always present")
|
||||||
|
.as_str();
|
||||||
|
|
||||||
|
let port_text = captures
|
||||||
|
.name("port")
|
||||||
|
.invariant_unwrap("Capture group `port` always present")
|
||||||
|
.as_str();
|
||||||
|
|
||||||
let host = Host::parse(&host_text).context(host_port_parse_error::Host {
|
let host = Host::parse(&host_text).context(host_port_parse_error::Host {
|
||||||
text: text.to_owned(),
|
text: text.to_owned(),
|
||||||
|
|
22
src/invariant.rs
Normal file
22
src/invariant.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use crate::common::*;
|
||||||
|
|
||||||
|
pub(crate) trait Invariant<T: Sized>: Sized {
|
||||||
|
fn invariant<D: Display>(self, invariant: D) -> Result<T>;
|
||||||
|
|
||||||
|
fn invariant_unwrap<D: Display>(self, invariant: D) -> T {
|
||||||
|
#![allow(clippy::result_unwrap_used)]
|
||||||
|
self.invariant(invariant).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Invariant<T> for Option<T> {
|
||||||
|
fn invariant<D: Display>(self, invariant: D) -> Result<T> {
|
||||||
|
self.ok_or_else(|| Error::internal(format!("Invariant violated: {}", invariant)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E: std::error::Error> Invariant<T> for Result<T, E> {
|
||||||
|
fn invariant<D: Display>(self, invariant: D) -> Result<T> {
|
||||||
|
self.map_err(|err| Error::internal(format!("Invariant `{}` violated: {}", invariant, err)))
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,7 +50,7 @@ impl MagnetLink {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn to_url(&self) -> Url {
|
pub(crate) fn to_url(&self) -> Url {
|
||||||
let mut url = Url::parse("magnet:").unwrap();
|
let mut url = Url::parse("magnet:").invariant_unwrap("`magnet:` is valid URL");
|
||||||
|
|
||||||
let mut query = format!("xt=urn:btih:{}", self.infohash);
|
let mut query = format!("xt=urn:btih:{}", self.infohash);
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,6 @@
|
||||||
clippy::needless_pass_by_value,
|
clippy::needless_pass_by_value,
|
||||||
clippy::non_ascii_literal,
|
clippy::non_ascii_literal,
|
||||||
clippy::option_map_unwrap_or_else,
|
clippy::option_map_unwrap_or_else,
|
||||||
clippy::option_unwrap_used,
|
|
||||||
clippy::result_expect_used,
|
|
||||||
clippy::result_unwrap_used,
|
|
||||||
clippy::shadow_reuse,
|
clippy::shadow_reuse,
|
||||||
clippy::too_many_lines,
|
clippy::too_many_lines,
|
||||||
clippy::unseparated_literal_suffix,
|
clippy::unseparated_literal_suffix,
|
||||||
|
@ -71,6 +68,7 @@ mod input_stream;
|
||||||
mod input_target;
|
mod input_target;
|
||||||
mod into_u64;
|
mod into_u64;
|
||||||
mod into_usize;
|
mod into_usize;
|
||||||
|
mod invariant;
|
||||||
mod lint;
|
mod lint;
|
||||||
mod linter;
|
mod linter;
|
||||||
mod magnet_link;
|
mod magnet_link;
|
||||||
|
|
|
@ -67,7 +67,13 @@ impl<'de> Deserialize<'de> for PieceList {
|
||||||
|
|
||||||
let piece_hashes = bytes
|
let piece_hashes = bytes
|
||||||
.chunks_exact(Sha1Digest::LENGTH)
|
.chunks_exact(Sha1Digest::LENGTH)
|
||||||
.map(|chunk| Sha1Digest::from_bytes(chunk.try_into().unwrap()))
|
.map(|chunk| {
|
||||||
|
Sha1Digest::from_bytes(
|
||||||
|
chunk
|
||||||
|
.try_into()
|
||||||
|
.invariant_unwrap("chunks are all Sha1Digest::LENGTH"),
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(Self { piece_hashes })
|
Ok(Self { piece_hashes })
|
||||||
|
|
|
@ -23,7 +23,12 @@ impl PlatformInterface for Platform {
|
||||||
|
|
||||||
let mut stat: libc::stat = unsafe { mem::zeroed() };
|
let mut stat: libc::stat = unsafe { mem::zeroed() };
|
||||||
|
|
||||||
let cpath = CString::new(path.as_os_str().as_bytes()).expect("Path contained null character.");
|
let cpath = if let Ok(cstr) = CString::new(path.as_os_str().as_bytes()) {
|
||||||
|
cstr
|
||||||
|
} else {
|
||||||
|
// Consider paths containing null bytes to be hidden
|
||||||
|
return Ok(true);
|
||||||
|
};
|
||||||
|
|
||||||
let error_code = unsafe { libc::stat(cpath.as_ptr(), &mut stat) };
|
let error_code = unsafe { libc::stat(cpath.as_ptr(), &mut stat) };
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ struct Extractor {
|
||||||
impl Extractor {
|
impl Extractor {
|
||||||
fn new(print: bool, regexes: &[Regex]) -> Self {
|
fn new(print: bool, regexes: &[Regex]) -> Self {
|
||||||
let regex_set = RegexSet::new(regexes.iter().map(Regex::as_str))
|
let regex_set = RegexSet::new(regexes.iter().map(Regex::as_str))
|
||||||
.expect("Validated regex pattern failed to recompile in regex set");
|
.invariant_unwrap("Regexes already validated by compilation");
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
bencode_decode_errors: 0,
|
bencode_decode_errors: 0,
|
||||||
|
|
|
@ -47,7 +47,7 @@ impl Verify {
|
||||||
content.clone()
|
content.clone()
|
||||||
} else {
|
} else {
|
||||||
match &self.metainfo {
|
match &self.metainfo {
|
||||||
InputTarget::Path(path) => path.parent().unwrap().join(&metainfo.info.name),
|
InputTarget::Path(path) => path.join("..").join(&metainfo.info.name).clean(),
|
||||||
InputTarget::Stdin => PathBuf::from(&metainfo.info.name),
|
InputTarget::Stdin => PathBuf::from(&metainfo.info.name),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -62,7 +62,7 @@ impl TorrentSummary {
|
||||||
creation_date
|
creation_date
|
||||||
.min(i64::max_value() as u64)
|
.min(i64::max_value() as u64)
|
||||||
.try_into()
|
.try_into()
|
||||||
.unwrap(),
|
.invariant_unwrap("min with i64 is always valid i64"),
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -79,7 +79,7 @@ impl<'a> Verifier<'a> {
|
||||||
let to_buffer: usize = remaining
|
let to_buffer: usize = remaining
|
||||||
.min(self.buffer.len().into_u64())
|
.min(self.buffer.len().into_u64())
|
||||||
.try_into()
|
.try_into()
|
||||||
.unwrap();
|
.invariant_unwrap("min with usize should fit in usize");
|
||||||
|
|
||||||
let buffer = &mut self.buffer[0..to_buffer];
|
let buffer = &mut self.buffer[0..to_buffer];
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user