Skip to content

Commit 423f8a1

Browse files
committed
fix: convert possible panics to errors
1 parent 0f6a51e commit 423f8a1

File tree

5 files changed

+203
-55
lines changed

5 files changed

+203
-55
lines changed

postgresql_archive/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ pub enum Error {
2222
/// Parse error
2323
#[error(transparent)]
2424
ParseError(anyhow::Error),
25+
/// Poisoned lock
26+
#[error("poisoned lock '{0}'")]
27+
PoisonedLock(String),
2528
/// Repository failure
2629
#[error("{0}")]
2730
RepositoryFailure(String),

postgresql_archive/src/hasher/registry.rs

Lines changed: 64 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::hasher::{blake2b_512, blake2s_256, sha2_256, sha2_512, sha3_256, sha3_512};
2+
use crate::Error::PoisonedLock;
23
use crate::Result;
34
use lazy_static::lazy_static;
45
use std::collections::HashMap;
@@ -33,13 +34,29 @@ impl HasherRegistry {
3334
}
3435

3536
/// Get a hasher for the specified extension.
36-
fn get<S: AsRef<str>>(&self, extension: S) -> Option<HasherFn> {
37+
///
38+
/// # Errors
39+
/// * If the registry is poisoned.
40+
fn get<S: AsRef<str>>(&self, extension: S) -> Result<Option<HasherFn>> {
3741
let extension = extension.as_ref().to_string();
3842
if let Some(hasher) = self.hashers.get(&extension) {
39-
return Some(*hasher.read().unwrap());
43+
let hasher = *hasher
44+
.read()
45+
.map_err(|error| PoisonedLock(error.to_string()))?;
46+
return Ok(Some(hasher));
4047
}
4148

42-
None
49+
Ok(None)
50+
}
51+
52+
/// Get the number of hashers in the registry.
53+
fn len(&self) -> usize {
54+
self.hashers.len()
55+
}
56+
57+
/// Check if the registry is empty.
58+
fn is_empty(&self) -> bool {
59+
self.hashers.is_empty()
4360
}
4461
}
4562

@@ -60,29 +77,56 @@ impl Default for HasherRegistry {
6077
/// Registers a hasher for an extension. Newly registered hashers with the same extension will
6178
/// override existing ones.
6279
///
63-
/// # Panics
80+
/// # Errors
6481
/// * If the registry is poisoned.
6582
#[allow(dead_code)]
66-
pub fn register<S: AsRef<str>>(extension: S, hasher_fn: HasherFn) {
67-
let mut registry = REGISTRY.lock().unwrap();
83+
pub fn register<S: AsRef<str>>(extension: S, hasher_fn: HasherFn) -> Result<()> {
84+
let mut registry = REGISTRY
85+
.lock()
86+
.map_err(|error| PoisonedLock(error.to_string()))?;
6887
registry.register(extension, hasher_fn);
88+
Ok(())
6989
}
7090

7191
/// Get a hasher for the specified extension.
7292
///
73-
/// # Panics
93+
/// # Errors
7494
/// * If the registry is poisoned.
75-
pub fn get<S: AsRef<str>>(extension: S) -> Option<HasherFn> {
76-
let registry = REGISTRY.lock().unwrap();
95+
pub fn get<S: AsRef<str>>(extension: S) -> Result<Option<HasherFn>> {
96+
let registry = REGISTRY
97+
.lock()
98+
.map_err(|error| PoisonedLock(error.to_string()))?;
7799
registry.get(extension)
78100
}
79101

102+
/// Get the number of matchers in the registry.
103+
///
104+
/// # Errors
105+
/// * If the registry is poisoned.
106+
pub fn len() -> Result<usize> {
107+
let registry = REGISTRY
108+
.lock()
109+
.map_err(|error| PoisonedLock(error.to_string()))?;
110+
Ok(registry.len())
111+
}
112+
113+
/// Check if the registry is empty.
114+
///
115+
/// # Errors
116+
/// * If the registry is poisoned.
117+
pub fn is_empty() -> Result<bool> {
118+
let registry = REGISTRY
119+
.lock()
120+
.map_err(|error| PoisonedLock(error.to_string()))?;
121+
Ok(registry.is_empty())
122+
}
123+
80124
#[cfg(test)]
81125
mod tests {
82126
use super::*;
83127

84128
fn test_hasher(extension: &str, expected: &str) -> Result<()> {
85-
let hasher = get(extension).unwrap();
129+
let hasher = get(extension)?.unwrap();
86130
let data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
87131
let hash = hasher(&data)?;
88132
assert_eq!(expected, hash);
@@ -92,12 +136,16 @@ mod tests {
92136
#[test]
93137
fn test_register() -> Result<()> {
94138
let extension = "sha256";
95-
let hashers = REGISTRY.lock().unwrap().hashers.len();
96-
assert!(!REGISTRY.lock().unwrap().hashers.is_empty());
97-
REGISTRY.lock().unwrap().hashers.remove(extension);
98-
assert_ne!(hashers, REGISTRY.lock().unwrap().hashers.len());
99-
register(extension, sha2_256::hash);
100-
assert_eq!(hashers, REGISTRY.lock().unwrap().hashers.len());
139+
let hashers = len()?;
140+
assert!(!is_empty()?);
141+
REGISTRY
142+
.lock()
143+
.map_err(|error| PoisonedLock(error.to_string()))?
144+
.hashers
145+
.remove(extension);
146+
assert_ne!(hashers, len()?);
147+
register(extension, sha2_256::hash)?;
148+
assert_eq!(hashers, len()?);
101149

102150
test_hasher(
103151
extension,

postgresql_archive/src/matcher/registry.rs

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::matcher::{default, postgresql_binaries};
2+
use crate::Error::PoisonedLock;
23
use crate::{Result, DEFAULT_POSTGRESQL_URL};
34
use lazy_static::lazy_static;
45
use semver::Version;
@@ -34,16 +35,35 @@ impl MatchersRegistry {
3435

3536
/// Get a matcher for the specified URL, or the default matcher if no matcher is
3637
/// registered for the URL.
37-
fn get<S: AsRef<str>>(&self, url: S) -> MatcherFn {
38+
///
39+
/// # Errors
40+
/// * If the registry is poisoned.
41+
fn get<S: AsRef<str>>(&self, url: S) -> Result<MatcherFn> {
3842
let url = Some(url.as_ref().to_string());
3943
if let Some(matcher) = self.matchers.get(&url) {
40-
return *matcher.read().unwrap();
44+
let matcher = *matcher
45+
.read()
46+
.map_err(|error| PoisonedLock(error.to_string()))?;
47+
return Ok(matcher);
4148
}
4249

43-
match self.matchers.get(&None) {
44-
Some(matcher) => *matcher.read().unwrap(),
50+
let matcher = match self.matchers.get(&None) {
51+
Some(matcher) => *matcher
52+
.read()
53+
.map_err(|error| PoisonedLock(error.to_string()))?,
4554
None => default::matcher,
46-
}
55+
};
56+
Ok(matcher)
57+
}
58+
59+
/// Get the number of matchers in the registry.
60+
fn len(&self) -> usize {
61+
self.matchers.len()
62+
}
63+
64+
/// Check if the registry is empty.
65+
fn is_empty(&self) -> bool {
66+
self.matchers.is_empty()
4767
}
4868
}
4969

@@ -60,39 +80,71 @@ impl Default for MatchersRegistry {
6080
/// Registers a matcher for a URL. Newly registered matchers with the same url will override
6181
/// existing ones.
6282
///
63-
/// # Panics
83+
/// # Errors
6484
/// * If the registry is poisoned.
6585
#[allow(dead_code)]
66-
pub fn register<S: AsRef<str>>(url: Option<S>, matcher_fn: MatcherFn) {
67-
let mut registry = REGISTRY.lock().unwrap();
86+
pub fn register<S: AsRef<str>>(url: Option<S>, matcher_fn: MatcherFn) -> Result<()> {
87+
let mut registry = REGISTRY
88+
.lock()
89+
.map_err(|error| PoisonedLock(error.to_string()))?;
6890
registry.register(url, matcher_fn);
91+
Ok(())
6992
}
7093

7194
/// Get a matcher for the specified URL, or the default matcher if no matcher is
7295
/// registered for the URL.
7396
///
74-
/// # Panics
97+
/// # Errors
7598
/// * If the registry is poisoned.
76-
pub fn get<S: AsRef<str>>(url: S) -> MatcherFn {
77-
let registry = REGISTRY.lock().unwrap();
99+
pub fn get<S: AsRef<str>>(url: S) -> Result<MatcherFn> {
100+
let registry = REGISTRY
101+
.lock()
102+
.map_err(|error| PoisonedLock(error.to_string()))?;
78103
registry.get(url)
79104
}
80105

106+
/// Get the number of matchers in the registry.
107+
///
108+
/// # Errors
109+
/// * If the registry is poisoned.
110+
pub fn len() -> Result<usize> {
111+
let registry = REGISTRY
112+
.lock()
113+
.map_err(|error| PoisonedLock(error.to_string()))?;
114+
Ok(registry.len())
115+
}
116+
117+
/// Check if the registry is empty.
118+
///
119+
/// # Errors
120+
/// * If the registry is poisoned.
121+
pub fn is_empty() -> Result<bool> {
122+
let registry = REGISTRY
123+
.lock()
124+
.map_err(|error| PoisonedLock(error.to_string()))?;
125+
Ok(registry.is_empty())
126+
}
127+
81128
#[cfg(test)]
82129
mod tests {
83130
use super::*;
131+
use crate::Error::PoisonedLock;
84132
use std::env;
85133

86134
#[test]
87135
fn test_register() -> Result<()> {
88-
let matchers = REGISTRY.lock().unwrap().matchers.len();
89-
assert!(!REGISTRY.lock().unwrap().matchers.is_empty());
90-
REGISTRY.lock().unwrap().matchers.remove(&None::<String>);
91-
assert_ne!(matchers, REGISTRY.lock().unwrap().matchers.len());
92-
register(None::<&str>, default::matcher);
93-
assert_eq!(matchers, REGISTRY.lock().unwrap().matchers.len());
94-
95-
let matcher = get(DEFAULT_POSTGRESQL_URL);
136+
let matchers = len()?;
137+
assert!(!is_empty()?);
138+
REGISTRY
139+
.lock()
140+
.map_err(|error| PoisonedLock(error.to_string()))?
141+
.matchers
142+
.remove(&None::<String>);
143+
assert_ne!(matchers, len()?);
144+
register(None::<&str>, default::matcher)?;
145+
assert_eq!(matchers, len()?);
146+
147+
let matcher = get(DEFAULT_POSTGRESQL_URL)?;
96148
let version = Version::new(16, 3, 0);
97149
let target = target_triple::TARGET;
98150
let name = format!("postgresql-{version}-{target}.tar.gz");
@@ -103,7 +155,7 @@ mod tests {
103155

104156
#[test]
105157
fn test_default_matcher() -> Result<()> {
106-
let matcher = get("https://foo.com");
158+
let matcher = get("https://foo.com")?;
107159
let version = Version::new(16, 3, 0);
108160
let os = env::consts::OS;
109161
let arch = env::consts::ARCH;

postgresql_archive/src/repository/github/repository.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ impl GitHub {
174174
version: &Version,
175175
release: &Release,
176176
) -> Result<(Asset, Option<Asset>, Option<HasherFn>)> {
177-
let matcher = matcher::registry::get(&self.url);
177+
let matcher = matcher::registry::get(&self.url)?;
178178
let mut release_asset: Option<Asset> = None;
179179
for asset in &release.assets {
180180
if matcher(asset.name.as_str(), version)? {
@@ -199,7 +199,7 @@ impl GitHub {
199199
.strip_prefix(format!("{}.", asset.name.as_str()).as_str())
200200
.unwrap_or_default();
201201

202-
if let Some(hasher_fn) = hasher::registry::get(extension) {
202+
if let Some(hasher_fn) = hasher::registry::get(extension)? {
203203
asset_hash = Some(release_asset.clone());
204204
asset_hasher_fn = Some(hasher_fn);
205205
break;

0 commit comments

Comments
 (0)