-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 5cd111c
Showing
10 changed files
with
348 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/target |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "fallible_map" | ||
version = "0.1.0" | ||
authors = ["Dario Cancelliere <[email protected]>"] | ||
edition = "2018" | ||
license = "MIT" | ||
description = "Utilities for fallible mapping over `Option` and iterators using functions that can return `Result`s." | ||
repository = "https://github.com/tifaremosapere/fallible_map" | ||
homepage = "https://github.com/tifaremosapere/fallible_map" | ||
documentation = "https://docs.rs/fallible_map_ext" | ||
readme = "README.md" | ||
keywords = ["fallible", "mapping", "option", "result", "error-handling"] | ||
categories = ["data-structures", "algorithms", "rust-patterns"] | ||
exclude = ["/target"] | ||
|
||
[dependencies] | ||
|
||
[features] | ||
default = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
MIT License | ||
|
||
Copyright (c) 2024 Ti faremo sapere | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
# Fallible Map | ||
|
||
[![Crates.io](https://img.shields.io/crates/v/fallible_map.svg)](https://crates.io/crates/fallible_map) | ||
![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg) | ||
![Version](https://img.shields.io/badge/version-0.1.0-green) | ||
[![Repository](https://img.shields.io/badge/github-repository-orange)](https://github.com/tifaremosapere/fallible_map) | ||
[![Homepage](https://img.shields.io/badge/homepage-Ti%20faremo%20sapere-brightgreen)](https://tifaremosapere.it) | ||
|
||
`fallible_map` provides utilities for fallible mapping over `Option` types and iterators, allowing the use of functions that can return `Result`s. | ||
|
||
This library includes traits to enhance `Option` and `Iterator` types with methods to handle fallible operations gracefully. | ||
|
||
## Overview | ||
|
||
This crate offers extensions for optional values and iterators to perform fallible mapping operations, returning results that properly reflect potential errors during computation. | ||
|
||
These extensions can be useful in scenarios where operations may fail, and error handling is required. | ||
|
||
## Features | ||
|
||
- **ExtractOption trait:** A helper trait to extract the inner value of an optional container; | ||
- **FallibleMapExt trait:** Extends `Option` with methods for fallible operations, such as `try_map`, `try_unwrap_or`, and `try_and_then`; | ||
- **TryMapIteratorExt trait:** Extends iterators with a `try_map` method, allowing the use of functions that return `Result`s during iteration. | ||
|
||
## Installation | ||
|
||
Add this to your `Cargo.toml`: | ||
|
||
```toml | ||
[dependencies] | ||
fallible_map = "^0.1" | ||
``` | ||
|
||
## Usage | ||
|
||
### Examples | ||
|
||
#### Using FallibleMapExt with `Option` | ||
|
||
```rust | ||
use fallible_map::FallibleMapExt; | ||
|
||
fn main() -> Result<(), String> { | ||
let some_number: Option<i32> = Some(2); | ||
|
||
let result: Result<Option<i32>, String> = some_number.try_map(|num| { | ||
if num % 2 == 0 { | ||
Ok(num * 2) | ||
} else { | ||
Err("Odd number".to_string()) | ||
} | ||
}); | ||
|
||
assert_eq!(result, Ok(Some(4))); | ||
|
||
Ok(()) | ||
} | ||
``` | ||
|
||
#### Using TryMapIteratorExt with `Iterator` | ||
|
||
```rust | ||
use fallible_map::TryMapIteratorExt; | ||
|
||
fn main() -> Result<(), String> { | ||
let numbers = vec![1, 2, 3, 4, 5]; | ||
|
||
let mapped_numbers: Result<Vec<i32>, String> = numbers.into_iter().try_map(|x| { | ||
if x % 2 == 0 { | ||
Ok(x * 2) | ||
} else { | ||
Err(format!("Failed to process {}", x)) | ||
} | ||
}); | ||
|
||
match mapped_numbers { | ||
Ok(nums) => println!("Mapped successfully: {:?}", nums), | ||
Err(e) => println!("Error occurred: {}", e), | ||
} | ||
|
||
Ok(()) | ||
} | ||
``` | ||
|
||
#### Using FallibleMapExt with `try_and_then` | ||
|
||
```rust | ||
use fallible_map::FallibleMapExt; | ||
|
||
fn main() -> Result<(), String> { | ||
let some_number: Option<i32> = Some(2); | ||
|
||
let result: Result<Option<i32>, String> = some_number.try_and_then(|num| { | ||
if num % 2 == 0 { | ||
Ok(Some(num * 2)) | ||
} else { | ||
Err("Odd number".to_string()) | ||
} | ||
}); | ||
|
||
assert_eq!(result, Ok(Some(4))); | ||
|
||
let none_number: Option<i32> = None; | ||
|
||
let result = none_number.try_and_then(|num| { | ||
if num % 2 == 0 { | ||
Ok(Some(num * 2)) | ||
} else { | ||
Err("Odd number".to_string()) | ||
} | ||
}); | ||
|
||
assert_eq!(result, Ok(None)); | ||
|
||
Ok(()) | ||
} | ||
``` | ||
|
||
## License | ||
|
||
This project is licensed under the MIT License. See the [LICENSE](LICENSE.md) file for details. | ||
|
||
## Contribution | ||
|
||
Contributions are welcome! Please feel free to submit a pull request, open an issue, or suggest features and improvements. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
/// `fallible_map_ext` provides utilities for fallible mapping over `Option` | ||
/// types and iterators, allowing the use of functions that can return `Result`s. | ||
/// A helper trait to extract the inner value of an optional container. | ||
pub trait ExtractOption<T> { | ||
/// Extract the inner value as an `Option`. | ||
fn extract(self) -> Option<T>; | ||
} | ||
|
||
/// Implementation of `ExtractOption` for `Option`. | ||
impl<T> ExtractOption<T> for Option<T> { | ||
fn extract(self) -> Option<T> { | ||
self | ||
} | ||
} | ||
|
||
/// Extend `Option` with fallible methods. | ||
/// | ||
/// Useful for mapping fallible operations (i.e., operations that return `Result`), | ||
/// over an optional type. The result will be `Result<Option<U>>`, making it easy | ||
/// to handle errors originating from inside the closure being mapped. | ||
/// | ||
/// # Type Parameters | ||
/// | ||
/// - `C`: The container type that implements `ExtractOption` | ||
/// - `T`: The input container's value type | ||
/// - `U`: The output container's value type | ||
/// - `E`: The possible error type during the mapping | ||
pub trait FallibleMapExt<T, U, E> { | ||
/// Attempt to map a function over an optional value. | ||
/// | ||
/// # Parameters | ||
/// | ||
/// - `f`: A function that takes a value of type `T` and returns a `Result<U, E>`. | ||
/// | ||
/// # Returns | ||
/// | ||
/// A `Result` containing an `Option<U>`, or an error `E`. | ||
fn try_map<F>(self, f: F) -> Result<Option<U>, E> | ||
where | ||
F: FnOnce(T) -> Result<U, E>; | ||
|
||
/// Unwrap an optional value or compute a fallback. | ||
/// | ||
/// # Parameters | ||
/// | ||
/// - `f`: A function that returns a `Result<T, E>`. | ||
/// | ||
/// # Returns | ||
/// | ||
/// A `Result` containing a value of type `T`, or an error `E`. | ||
fn try_unwrap_or<F>(self, f: F) -> Result<T, E> | ||
where | ||
F: FnOnce() -> Result<T, E>; | ||
|
||
/// Chain computation that returns another optional value. | ||
/// | ||
/// # Parameters | ||
/// | ||
/// - `f`: A function that takes a value of type `T` and returns a `Result<Option<U>, E>`. | ||
/// | ||
/// # Returns | ||
/// | ||
/// A `Result` containing an `Option<U>`, or an error `E`. | ||
fn try_and_then<F>(self, f: F) -> Result<Option<U>, E> | ||
where | ||
F: FnOnce(T) -> Result<Option<U>, E>; | ||
} | ||
|
||
/// Implementation of `FallibleMapExt` for types implementing `ExtractOption`. | ||
impl<C, T, U, E> FallibleMapExt<T, U, E> for C | ||
where | ||
C: ExtractOption<T>, | ||
{ | ||
fn try_map<F>(self, f: F) -> Result<Option<U>, E> | ||
where | ||
F: FnOnce(T) -> Result<U, E>, | ||
{ | ||
match self.extract() { | ||
Some(x) => f(x).map(Some), | ||
None => Ok(None), | ||
} | ||
} | ||
|
||
fn try_unwrap_or<F>(self, f: F) -> Result<T, E> | ||
where | ||
F: FnOnce() -> Result<T, E>, | ||
{ | ||
match self.extract() { | ||
Some(x) => Ok(x), | ||
None => f(), | ||
} | ||
} | ||
|
||
fn try_and_then<F>(self, f: F) -> Result<Option<U>, E> | ||
where | ||
F: FnOnce(T) -> Result<Option<U>, E>, | ||
{ | ||
match self.extract() { | ||
Some(x) => f(x), | ||
None => Ok(None), | ||
} | ||
} | ||
} | ||
|
||
/// Extend iterator with fallible map functionality. | ||
/// | ||
/// This trait provides a fallible version of the `map` method, allowing | ||
/// the use of functions that return `Result`s during iteration. | ||
/// | ||
/// # Example | ||
/// | ||
/// ``` | ||
/// use my_crate::TryMapIteratorExt; | ||
/// | ||
/// let numbers = vec![1, 2, 3, 4, 5]; | ||
/// let result: Result<Vec<_>, _> = numbers.into_iter().try_map(|num| { | ||
/// if num % 2 == 0 { | ||
/// Ok(num * 2) | ||
/// } else { | ||
/// Err("Odd number") | ||
/// } | ||
/// }); | ||
/// assert_eq!(result, Err("Odd number")); | ||
/// ``` | ||
pub trait TryMapIteratorExt: Iterator { | ||
/// Attempt to map a function over an iterator. | ||
/// | ||
/// # Parameters | ||
/// | ||
/// - `f`: A function that takes an item and returns a `Result<B, E>`. | ||
/// | ||
/// # Returns | ||
/// | ||
/// A `Result` containing a `Vec<B>`, or an error `E`. | ||
fn try_map<B, F, E>(self, f: F) -> Result<Vec<B>, E> | ||
where | ||
Self: Sized, | ||
F: FnMut(Self::Item) -> Result<B, E>; | ||
} | ||
|
||
/// Implementation of `TryMapIteratorExt` for all iterators. | ||
impl<I> TryMapIteratorExt for I | ||
where | ||
I: Iterator, | ||
{ | ||
fn try_map<B, F, E>(mut self, mut f: F) -> Result<Vec<B>, E> | ||
where | ||
Self: Sized, | ||
F: FnMut(Self::Item) -> Result<B, E>, | ||
{ | ||
self.try_fold(Vec::new(), |mut results, item| { | ||
results.push(f(item)?); | ||
Ok(results) | ||
}) | ||
} | ||
} |