refactor(assoc): improve error handling and type safety
- Remove unused `Infallible` import - Add `ParseProgIdKindError` for better ProgId parsing error handling - Implement `BlankProgId` variant for empty ProgId strings - Add `ExtKey::new` and `ProgIdKey::new` constructors - Add `as_inner` methods to `ExtKey` and `ProgIdKey` - Replace `to_string()` calls with `as_inner().to_string()` - Update error type from `BlankStringError` to `BlankPathError` - Rename `BlankStringError` to `BlankPathError` with updated message - Update `blank_path_guard` return type and error handling - Remove `Display` and `FromStr` implementations from `ExtKey` and `ProgIdKey`
This commit is contained in:
@ -4,7 +4,6 @@
|
||||
use crate::extra::windows::{Ext, ProgId};
|
||||
use crate::extra::winreg as winreg_extra;
|
||||
use crate::utilities;
|
||||
use std::convert::Infallible;
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
use thiserror::Error as TeError;
|
||||
@ -25,7 +24,9 @@ pub enum Error {
|
||||
#[error("{0}")]
|
||||
ParseProgId(#[from] crate::extra::windows::ParseProgIdError),
|
||||
#[error("{0}")]
|
||||
BlankPath(#[from] crate::extra::winreg::BlankStringError),
|
||||
ParseProgIdKind(#[from] ParseProgIdKindError),
|
||||
#[error("{0}")]
|
||||
BlankPath(#[from] crate::extra::winreg::BlankPathError),
|
||||
}
|
||||
|
||||
/// The result type used in this crate.
|
||||
@ -113,6 +114,15 @@ impl From<Scope> for View {
|
||||
|
||||
// region: ProgId Kind
|
||||
|
||||
/// The error occurs when parsing ProgId kind.
|
||||
#[derive(Debug, TeError)]
|
||||
pub enum ParseProgIdKindError {
|
||||
#[error("{0}")]
|
||||
FromStd(#[from] crate::extra::windows::ParseProgIdError),
|
||||
#[error("given ProgId is blank")]
|
||||
BlankProgId,
|
||||
}
|
||||
|
||||
/// The variant of ProgId for the compatibility
|
||||
/// with those software which do not follow Microsoft suggestions.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
@ -133,13 +143,17 @@ impl Display for ProgIdKind {
|
||||
}
|
||||
|
||||
impl FromStr for ProgIdKind {
|
||||
type Err = Infallible;
|
||||
type Err = ParseProgIdKindError;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
Ok(match s.parse::<ProgId>() {
|
||||
Ok(v) => Self::Std(v),
|
||||
Err(_) => Self::Other(s.to_string()),
|
||||
})
|
||||
if s.is_empty() {
|
||||
Err(ParseProgIdKindError::BlankProgId)
|
||||
} else {
|
||||
Ok(match s.parse::<ProgId>() {
|
||||
Ok(v) => Self::Std(v),
|
||||
Err(_) => Self::Other(s.to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,6 +245,20 @@ pub struct ExtKey {
|
||||
ext: Ext,
|
||||
}
|
||||
|
||||
impl ExtKey {
|
||||
/// Create new file extension registry key representer.
|
||||
pub fn new(s: &str) -> Result<Self> {
|
||||
Ok(Self {
|
||||
ext: Ext::from_str(s)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Fetch the reference to inner extension representer.
|
||||
pub fn as_inner(&self) -> &Ext {
|
||||
&self.ext
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtKey {
|
||||
/// Set the default "Open With" of this file extension to given ProgId.
|
||||
pub fn link(&self, prog_id: &ProgIdKey, scope: Scope) -> Result<()> {
|
||||
@ -243,7 +271,7 @@ impl ExtKey {
|
||||
let (subkey, _) =
|
||||
classes.create_subkey_with_flags(blank_path_guard(self.ext.to_string())?, KEY_WRITE)?;
|
||||
// Set the default way to open this file extension
|
||||
subkey.set_value("", &prog_id.to_string())?;
|
||||
subkey.set_value("", &prog_id.as_inner().to_string())?;
|
||||
|
||||
// Okey
|
||||
Ok(())
|
||||
@ -268,7 +296,7 @@ impl ExtKey {
|
||||
)? {
|
||||
// Only delete the default key if it is equal to our ProgId
|
||||
if let Some(value) = try_get_value::<String, _>(&subkey, "")? {
|
||||
if value == prog_id.to_string() {
|
||||
if value == prog_id.as_inner().to_string() {
|
||||
// Delete the default key.
|
||||
subkey.delete_value("")?;
|
||||
}
|
||||
@ -297,9 +325,7 @@ impl ExtKey {
|
||||
Some(subkey) => {
|
||||
// Try get associated ProgId if possible
|
||||
match try_get_value::<String, _>(&subkey, "")? {
|
||||
Some(value) => {
|
||||
Some(ProgIdKey::from_str(value.as_str()).expect("unexpected Infallable"))
|
||||
}
|
||||
Some(value) => Some(ProgIdKey::new(value.as_str())?),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
@ -311,22 +337,6 @@ impl ExtKey {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ExtKey {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.ext)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for ExtKey {
|
||||
type Err = <Ext as FromStr>::Err;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
Ok(Self {
|
||||
ext: Ext::from_str(s)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region: ProgId Registry Key
|
||||
@ -336,6 +346,20 @@ pub struct ProgIdKey {
|
||||
prog_id: ProgIdKind,
|
||||
}
|
||||
|
||||
impl ProgIdKey {
|
||||
/// Create new ProgId registry representer.
|
||||
pub fn new(s: &str) -> Result<Self> {
|
||||
Ok(Self {
|
||||
prog_id: ProgIdKind::from_str(s)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Fetch the reference to inner ProgId.
|
||||
pub fn as_inner(&self) -> &ProgIdKind {
|
||||
&self.prog_id
|
||||
}
|
||||
}
|
||||
|
||||
impl ProgIdKey {
|
||||
/// Create ProgId into Registry in given scope with given parameters
|
||||
pub fn create(&self, scope: Scope, command: &str) -> Result<()> {
|
||||
@ -364,20 +388,4 @@ impl ProgIdKey {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ProgIdKey {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.prog_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for ProgIdKey {
|
||||
type Err = <ProgIdKind as FromStr>::Err;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
Ok(Self {
|
||||
prog_id: ProgIdKind::from_str(s)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
@ -62,14 +62,14 @@ pub fn try_get_value<T: FromRegValue, N: AsRef<OsStr>>(
|
||||
|
||||
// endregion
|
||||
|
||||
// region: Blank String Guard
|
||||
// region: Blank Path Guard
|
||||
|
||||
/// The error occurs when given string is empty.
|
||||
/// The error occurs when given registry path is empty.
|
||||
#[derive(Debug, TeError)]
|
||||
#[error("unexpected empty string")]
|
||||
pub struct BlankStringError {}
|
||||
#[error("unexpected empty registry path")]
|
||||
pub struct BlankPathError {}
|
||||
|
||||
impl BlankStringError {
|
||||
impl BlankPathError {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
@ -82,9 +82,9 @@ impl BlankStringError {
|
||||
/// Because it will cause unexpected behavior that returning key self, rather than subkey.
|
||||
/// This is VERY dangerous especially for those registry delete functions.
|
||||
/// So I create this function to prevent any harmful blank path was passed into registry function.
|
||||
pub fn blank_path_guard<P: AsRef<OsStr>>(path: P) -> std::result::Result<P, BlankStringError> {
|
||||
pub fn blank_path_guard<P: AsRef<OsStr>>(path: P) -> std::result::Result<P, BlankPathError> {
|
||||
if path.as_ref().is_empty() {
|
||||
Err(BlankStringError::new())
|
||||
Err(BlankPathError::new())
|
||||
} else {
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user