Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/granular errors #59

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ repository = "https://github.com/muja/unrar.rs"
regex = "1"
bitflags = "1"
widestring = "1"
thiserror = "1.0.50"

[dependencies.unrar_sys]
path = "unrar_sys"
Expand Down
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,14 @@ For more sophisticated examples, please look inside the `examples/` folder.
Here's what a function that returns the first content of a file could look like:

```rust
fn first_file_content<P: AsRef<Path>>(path: P) -> UnrarResult<Vec<u8>> {
let archive = Archive::new(&path).open_for_processing()?; // cursor: before header
fn first_file_content<P: AsRef<Path>>(path: P) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
let archive = unrar::Archive::new(&path).open_for_processing()?; // cursor: before header
let archive = archive.read_header()?.expect("empty archive"); // cursor: before file
dbg!(&archive.entry().filename);
let (data, _rest) = archive.read()?; // cursor: before header
Ok(data)
}
# use std::path::Path;
# use unrar::{Archive, UnrarResult};
#
# let data = first_file_content("data/version.rar").unwrap();
# assert_eq!(std::str::from_utf8(&data), Ok("unrar-0.4.0"));
Expand Down
7 changes: 3 additions & 4 deletions examples/basic_extract.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use unrar::Archive;

fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut archive =
Archive::new("../archive.rar")
.open_for_processing()
.unwrap();
let args = std::env::args();
let file = args.skip(1).next().unwrap_or("archive.rar".to_owned());
let mut archive = Archive::new(&file).open_for_processing().unwrap();
while let Some(header) = archive.read_header()? {
println!(
"{} bytes: {}",
Expand Down
4 changes: 2 additions & 2 deletions examples/read_named.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use unrar::{Archive, UnrarResult};
use unrar::Archive;

fn main() -> UnrarResult<()> {
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Basic args parsing
// Usage: cargo run --example extract_named <archive> <entry-filename-to-print>
let mut args = std::env::args_os().skip(1);
Expand Down
66 changes: 38 additions & 28 deletions src/archive.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::error::*;
use crate::Nulable;
use crate::OpenError;
use crate::open_archive::{CursorBeforeHeader, List, ListSplit, OpenArchive, OpenMode, Process};
use regex::Regex;
use std::borrow::Cow;
Expand Down Expand Up @@ -323,21 +324,29 @@ impl<'a> Archive<'a> {
///
/// See also: [`Process`]
///
/// # Panics
/// # Errors
///
/// Panics if `self.filename` contains nul values.
pub fn open_for_processing(self) -> UnrarResult<OpenArchive<Process, CursorBeforeHeader>> {
/// - `NulError` if `self.filename` or `self.password` contains nul values.
/// - `RarError` if there was an error opening/reading/decoding the archive.
///
pub fn open_for_processing(
self,
) -> Result<OpenArchive<Process, CursorBeforeHeader>, Nulable<OpenError>> {
self.open(None)
}

/// Opens the underlying archive for listing its entries, i.e. the payloads are skipped automatically.
///
/// See also: [`List`]
///
/// # Panics
/// # Errors
///
/// - `NulError` if `self.filename` or `self.password` contains nul values.
/// - `RarError` if there was an error opening/reading/decoding the archive.
///
/// Panics if `self.filename` contains nul values.
pub fn open_for_listing(self) -> UnrarResult<OpenArchive<List, CursorBeforeHeader>> {
pub fn open_for_listing(
self,
) -> Result<OpenArchive<List, CursorBeforeHeader>, Nulable<OpenError>> {
self.open(None)
}

Expand All @@ -348,23 +357,22 @@ impl<'a> Archive<'a> {
///
/// See also: [`ListSplit`]
///
/// # Panics
/// # Errors
///
/// Panics if `self.filename` contains nul values.

pub fn open_for_listing_split(self) -> UnrarResult<OpenArchive<ListSplit, CursorBeforeHeader>> {
/// - `NulError` if `self.filename` or `self.password` contains nul values.
/// - `RarError` if there was an error opening/reading/decoding the archive.
///
pub fn open_for_listing_split(
self,
) -> Result<OpenArchive<ListSplit, CursorBeforeHeader>, Nulable<OpenError>> {
self.open(None)
}

/// Opens the underlying archive with the provided parameters.
///
/// # Panics
///
/// Panics if `path` contains nul values.
fn open<M: OpenMode>(
self,
recover: Option<&mut Option<OpenArchive<M, CursorBeforeHeader>>>,
) -> UnrarResult<OpenArchive<M, CursorBeforeHeader>> {
) -> Result<OpenArchive<M, CursorBeforeHeader>, Nulable<OpenError>> {
OpenArchive::new(&self.filename, self.password, recover)
}

Expand All @@ -378,8 +386,8 @@ impl<'a> Archive<'a> {
/// # Example: I don't care if there was a recoverable error
///
/// ```no_run
/// # use unrar::{Archive, List, UnrarResult};
/// # fn x() -> UnrarResult<()> {
/// # use unrar::{Archive, List};
/// # fn x() -> Result<(), unrar::Nulable<unrar::OpenError>> {
/// let mut open_archive = Archive::new("file").break_open::<List>(None)?;
/// // use open_archive
/// # Ok(())
Expand All @@ -389,8 +397,8 @@ impl<'a> Archive<'a> {
/// # Example: I want to know if there was a recoverable error
///
/// ```no_run
/// # use unrar::{Archive, List, UnrarResult};
/// # fn x() -> UnrarResult<()> {
/// # use unrar::{Archive, List};
/// # fn x() -> Result<(), unrar::Nulable<unrar::OpenError>> {
/// let mut possible_error = None;
/// let mut open_archive = Archive::new("file").break_open::<List>(Some(&mut possible_error))?;
/// // check the error, e.g.:
Expand All @@ -400,21 +408,23 @@ impl<'a> Archive<'a> {
/// # }
/// ```
///
/// # Panics
/// # Errors
///
/// - `NulError` if `self.filename` or `self.password` contains nul values.
/// - `RarError` if there was an error opening/reading/decoding the archive.
///
/// Panics if `path` contains nul values.
pub fn break_open<M: OpenMode>(
self,
error: Option<&mut Option<UnrarError>>,
) -> UnrarResult<OpenArchive<M, CursorBeforeHeader>> {
error: Option<&mut Option<OpenError>>,
) -> Result<OpenArchive<M, CursorBeforeHeader>, Nulable<OpenError>> {
let mut recovered = None;
self.open(Some(&mut recovered))
.or_else(|x| match recovered {
Some(archive) => {
error.map(|error| *error = Some(x));
.or_else(|e| match (recovered, e) {
(Some(archive), Nulable::Rar(e)) => {
error.map(|error| *error = Some(e));
Ok(archive)
}
None => Err(x),
(_, _) => Err(e),
})
}
}
Expand Down
Loading
Loading