diff --git a/CHANGELOG.md b/CHANGELOG.md index 92f7539..4eea759 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ # Changelog +## [4.6.0] - 2022-9-26 +- Added 'set_result` and `try_result` fn for more simpler error handling. +- Added `IOError` type alias +- Update examples +- Imrove doc + ## [4.0.2] - 2022-9-26 - Fix unexpected deadlock on `result` fn. diff --git a/Cargo.toml b/Cargo.toml index e0ab52c..e06b913 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "flowync" -version = "4.0.2" +version = "4.6.0" authors = ["Ar37-rs "] edition = "2021" description = "A simple utility for multithreading a/synchronization" diff --git a/README.md b/README.md index ac6cf41..6c7f04e 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,25 @@ [![Crates.io](https://img.shields.io/crates/v/flowync.svg)](https://crates.io/crates/flowync) ![minimum rustc 1.61.0](https://img.shields.io/badge/rustc-1.61.0-blue.svg) -[![Flowync documentation](https://docs.rs/flowync/badge.svg)](https://docs.rs/flowync) [![CI](https://github.com/Ar37-rs/flowync/actions/workflows/ci.yml/badge.svg)](https://github.com/Ar37-rs/flowync/actions/workflows/ci.yml) +[![Flowync documentation](https://docs.rs/flowync/badge.svg)](https://docs.rs/flowync) [![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/) + + ## Quick Example ```rust -use flowync::Flower; +use flowync::{Flower, IOError}; type TestFlower = Flower; +fn fetch_things(id: usize) -> Result { + let result = + Ok::(format!("the flower with id: {} successfully completed fetching.", id)); + let success = result?; + Ok(success) +} + fn main() { let flower: TestFlower = Flower::new(1); std::thread::spawn({ @@ -24,14 +33,10 @@ fn main() { // until the option value successfully being polled in the main thread. handle.send(i); // or handle.send_async(i).await; can be used from any multithreaded async runtime, - - // Return error if the job is failure, for example: - // if i >= 3 { - // return handle.error("Err"); - // } } - // And return if the job successfully completed. - handle.success("Ok".to_string()); + let result = fetch_things(handle.id()); + // Set result and then extract later. + handle.set_result(result) } }); diff --git a/examples/main.rs b/examples/main.rs index 3243d9a..9330d45 100644 --- a/examples/main.rs +++ b/examples/main.rs @@ -1,7 +1,15 @@ -#![allow(clippy::needless_return)] -use flowync::Flower; +use flowync::{Flower, IOError}; type TestFlower = Flower; +fn fetch_things(id: usize) -> Result { + let result = Ok::(format!( + "the flower with id: {} successfully completed fetching.", + id + )); + let success = result?; + Ok(success) +} + fn main() { let flower: TestFlower = Flower::new(1); std::thread::spawn({ @@ -14,14 +22,10 @@ fn main() { // until the option value successfully being polled in the main thread. handle.send(i); // or handle.send_async(i).await; can be used from any multithreaded async runtime, - - // Return error if the job is failure, for example: - // if i >= 3 { - // return handle.error("Err"); - // } } - // And return if the job successfully completed. - handle.success("Ok".to_string()); + let result = fetch_things(handle.id()); + // Set result and then extract later. + handle.set_result(result) } }); diff --git a/examples/simple.rs b/examples/simple.rs index 4eb127b..600ba6e 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,8 +1,13 @@ -use flowync::Flower; -use std::io::Error; - +use flowync::{Flower, IOError}; type TestSimpleFlower = Flower<(), String>; +fn fetch_things(id: usize) -> Result { + let result = + Ok::(format!("the flower with id: {} successfully completed", id)); + let success = result?; + Ok(success) +} + fn main() { let flower: TestSimpleFlower = Flower::new(1); std::thread::spawn({ @@ -11,20 +16,9 @@ fn main() { handle.activate(); move || { let id = handle.id(); - let result = Ok::(format!( - "thse flower with id: {} successfully completed", - id - )); - match result { - Ok(value) => { - // And return if the job successfully completed. - handle.success(value); - } - Err(e) => { - // Return error immediately if something not right, for example: - handle.error(e); - } - } + let result = fetch_things(id); + // Set result and then try_result later. + handle.set_result(result) } }); @@ -34,7 +28,7 @@ fn main() { // Check if the flower is_active() // and will deactivate itself if the result value successfully received. if flower.is_active() { - flower.result(|result| { + flower.try_result(|result| { match result { Ok(value) => println!("{}", value), Err(err_msg) => println!("{}", err_msg), diff --git a/src/lib.rs b/src/lib.rs index 0d9d61e..9ed31cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,72 +55,74 @@ where /// /// Where: /// -/// S = type of sender (channel) value +/// `S` = type of sender (`channel`) value /// -/// R = type of Ok value of the Result (Result<'R', String>, and Err value always return String) +/// `R` = type of `Ok` value of the `Result` (`Result`, and Err value always return `String`) /// /// # Quick Example: /// ///``` -///use flowync::Flower; -///type TestFlower = Flower; +/// use flowync::{Flower, IOError}; +/// type TestFlower = Flower; /// -///fn _main() { -/// let flower: TestFlower = Flower::new(1); -/// std::thread::spawn({ -/// let handle = flower.handle(); -/// // Activate -/// handle.activate(); -/// move || { -/// for i in 0..10 { -/// // Send current value through channel, will block the spawned thread -/// // until the option value successfully being polled in the main thread. -/// handle.send(i); -/// // or handle.send_async(i).await; can be used from any multithreaded async runtime, -/// -/// // Return error if the job is failure, for example: -/// // if i >= 3 { -/// // return handle.error("Err"); -/// // } -/// } -/// // And return if the job successfully completed. -/// handle.success("Ok".to_string()); -/// } -/// }); +/// fn fetch_things(id: usize) -> Result { +/// let result = +/// Ok::(format!("the flower with id: {} successfully completed fetching.", id)); +/// let success = result?; +/// Ok(success) +/// } /// -/// let mut exit = false; +/// fn main() { +/// let flower: TestFlower = Flower::new(1); +/// std::thread::spawn({ +/// let handle = flower.handle(); +/// // Activate +/// handle.activate(); +/// move || { +/// for i in 0..10 { +/// // Send current value through channel, will block the spawned thread +/// // until the option value successfully being polled in the main thread. +/// handle.send(i); +/// // or handle.send_async(i).await; can be used from any multithreaded async runtime, +/// } +/// let result = fetch_things(handle.id()); +/// // Set result and then extract later. +/// handle.set_result(result) +/// } +/// }); /// -/// loop { -/// // Check if the flower is_active() -/// // and will deactivate itself if the result value successfully received. -/// if flower.is_active() { -/// // Another logic goes here... -/// // e.g: -/// // notify_loading_fn(); +/// let mut exit = false; /// -/// flower -/// .extract(|channel| { +/// loop { +/// // Check if the flower is_active() +/// // and will deactivate itself if the result value successfully received. +/// if flower.is_active() { +/// // another logic goes here... +/// // e.g: +/// // notify_loading_fn(); +/// +/// flower +/// .extract(|channel| { /// // Poll channel /// if let Some(value) = channel { /// println!("{}", value); /// } /// }) -/// .finalize(|result| { -/// match result { -/// Ok(value) => println!("{}", value), -/// Err(err_msg) => println!("{}", err_msg), -/// } -/// -/// // Exit if completed -/// exit = true; -/// }); -/// } +/// .finalize(|result| { +/// match result { +/// Ok(value) => println!("{}", value), +/// Err(err_msg) => println!("{}", err_msg), +/// } +/// // Exit if finalized +/// exit = true; +/// }); +/// } /// -/// if exit { -/// break; -/// } -/// } -///} +/// if exit { +/// break; +/// } +/// } +/// } /// ``` pub struct Flower where @@ -223,10 +225,15 @@ where self.state.channel_present.load(Ordering::Relaxed) } - /// Get the result of the flower and ignore channel value (if any). + #[deprecated = "result is highly deprecated, use `try_result` fn is instead"] + pub fn result(&self, f: impl FnOnce(Result)) { + self.try_result(f); + } + + /// Try get the result of the flower and ignore channel value (if any). /// /// **Warning!** don't use this fn if channel value is important, use `extract fn` and then use `finalize fn` instead. - pub fn result(&self, f: impl FnOnce(Result)) { + pub fn try_result(&self, f: impl FnOnce(Result)) { if self.state.channel_present.load(Ordering::Relaxed) { let _ = self.state.mtx.lock().unwrap().0.take(); self.state.cvar.notify_all(); @@ -377,6 +384,14 @@ where .await } + /// Set result value + pub fn set_result(&self, r: Result>) { + match r { + Ok(val) => self.success(val), + Err(e) => self.error(e), + } + } + /// Set the Ok value of the result. pub fn success(&self, r: R) { { @@ -461,10 +476,12 @@ where } pub type OIError = Box; +// Alternative alias to avoid conflict with other crate type +pub type IOError = OIError; -/// A trait to convert option into `Result`. +/// A converter to convert `Option` into `Result` using `catch` fn. pub trait IntoResult { - /// Convert `Option` into `Result` + /// Convert `Option` into `Result` fn catch(self, error_msg: impl ToString) -> Result>; }