Skip to content

Commit

Permalink
Now returning a Result instead of an Option.
Browse files Browse the repository at this point in the history
  • Loading branch information
IohannRabeson committed Dec 1, 2024
1 parent 9e4c246 commit 73dc7ff
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 15 deletions.
51 changes: 40 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::path::Path;
use std::{fmt::Display, path::Path};

mod provider;

Expand All @@ -14,37 +14,66 @@ pub struct Icon {
pub pixels: Vec<u8>,
}

/// Represents an error
#[derive(Debug)]
pub enum Error {
/// Retrieving the icon failed
Failed,
/// The path does not exist
PathDoesNotExist,
/// The desired icon size is null
NullIconSize,
}

impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Error::Failed => {
write!(f, "Failed to get icon")
}
Error::PathDoesNotExist => {
write!(f, "Path does not exist")
},
Error::NullIconSize => {
write!(f, "Null icon size")
}
}
}
}

impl std::error::Error for Error {}

/// Retrieves the icon for a given file.
///
/// # Parameters
/// * `path` - A file path for which the icon is to be retrieved.
/// * `size` - Desired icon size, must be greater than 0.
/// # Returns
/// * `Some(Icon)` - If the icon is successfully retrieved.
/// * `None` - If the icon could not be retrieved.
/// * `Ok(Icon)` - If the icon is successfully retrieved.
/// * `Err(Error)` - If the icon could not be retrieved.
///
/// # Example
/// ```
/// use file_icon_provider::get_file_icon;
///
/// if let Some(icon) = get_file_icon("path/to/file", 64) {
/// if let Ok(icon) = get_file_icon("path/to/file", 64) {
/// println!("Icon dimensions: {}x{}", icon.width, icon.height);
/// } else {
/// println!("Failed to retrieve the icon.");
/// }
/// ```
pub fn get_file_icon<'a>(path: impl AsRef<Path> + 'a, size: u16) -> Option<Icon> {
pub fn get_file_icon(path: impl AsRef<Path>, size: u16) -> Result<Icon, Error> {
// For consistency: on MacOS if the path does not exist None is returned
// but on Windows a default icon is returned.
if !path.as_ref().exists() {
return None;
return Err(Error::PathDoesNotExist);
}

if size == 0 {
return None;
return Err(Error::NullIconSize);
}

implementation::get_file_icon(path, size)
implementation::get_file_icon(path, size).ok_or(Error::Failed)
}

mod implementation {
Expand Down Expand Up @@ -279,19 +308,19 @@ mod tests {
let program_file_path = std::env::args().next().expect("get program path");
let program_file_path = PathBuf::from(&program_file_path);

assert!(get_file_icon(program_file_path, 32).is_some());
assert!(get_file_icon(program_file_path, 32).is_ok());
}

#[test]
fn test_not_existing_file() {
assert!(get_file_icon("NOT EXISTING", 32).is_none());
assert!(get_file_icon("NOT EXISTING", 32).is_err());
}

#[test]
fn test_null_icon_size() {
let program_file_path = std::env::args().next().expect("get program path");
let program_file_path = PathBuf::from(&program_file_path);

assert!(get_file_icon(program_file_path, 0).is_none());
assert!(get_file_icon(program_file_path, 0).is_err());
}
}
8 changes: 4 additions & 4 deletions src/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{
path::Path,
};

use crate::{get_file_icon, Icon};
use crate::{get_file_icon, Error, Icon};

/// This provider caches icons retrieved using [get_file_icon]
/// into a dictionary where keys are file extensions.
Expand Down Expand Up @@ -40,14 +40,14 @@ impl<T: Clone> FileIconProvider<T> {
}

/// Retrieves the icon for a given file.
pub fn icon(&self, path: impl AsRef<Path>, size: u16) -> Option<T> {
pub fn icon(&self, path: impl AsRef<Path>, size: u16) -> Result<T, Error> {
let path = path.as_ref();
let get_icon = |path| get_file_icon(path, size).map(self.convert);

match path.extension() {
Some(extension) => match self.cache.borrow_mut().entry((size, extension.to_owned())) {
Vacant(vacant_entry) => Some(vacant_entry.insert(get_icon(path)?).clone()),
Occupied(occupied_entry) => Some(occupied_entry.get().clone()),
Vacant(vacant_entry) => Ok(vacant_entry.insert(get_icon(path)?).clone()),
Occupied(occupied_entry) => Ok(occupied_entry.get().clone()),
},
// No extension then no caching.
None => get_icon(path),
Expand Down

0 comments on commit 73dc7ff

Please sign in to comment.