Skip to content

Commit

Permalink
Much simpler usage.
Browse files Browse the repository at this point in the history
  • Loading branch information
ar37-rs committed Sep 26, 2022
1 parent 3aa2790 commit 2c3db24
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 92 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "flowync"
version = "4.0.2"
version = "4.6.0"
authors = ["Ar37-rs <[email protected]>"]
edition = "2021"
description = "A simple utility for multithreading a/synchronization"
Expand Down
23 changes: 14 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<u32, String>;

fn fetch_things(id: usize) -> Result<String, IOError> {
let result =
Ok::<String, IOError>(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({
Expand All @@ -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)
}
});

Expand Down
22 changes: 13 additions & 9 deletions examples/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
#![allow(clippy::needless_return)]
use flowync::Flower;
use flowync::{Flower, IOError};
type TestFlower = Flower<u32, String>;

fn fetch_things(id: usize) -> Result<String, IOError> {
let result = Ok::<String, IOError>(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({
Expand All @@ -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)
}
});

Expand Down
30 changes: 12 additions & 18 deletions examples/simple.rs
Original file line number Diff line number Diff line change
@@ -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<String, IOError> {
let result =
Ok::<String, IOError>(format!("the flower with id: {} successfully completed", id));
let success = result?;
Ok(success)
}

fn main() {
let flower: TestSimpleFlower = Flower::new(1);
std::thread::spawn({
Expand All @@ -11,20 +16,9 @@ fn main() {
handle.activate();
move || {
let id = handle.id();
let result = Ok::<String, Error>(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)
}
});

Expand All @@ -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),
Expand Down
127 changes: 72 additions & 55 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<R, String>`, and Err value always return `String`)
///
/// # Quick Example:
///
///```
///use flowync::Flower;
///type TestFlower = Flower<u32, String>;
/// use flowync::{Flower, IOError};
/// type TestFlower = Flower<u32, String>;
///
///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<String, IOError> {
/// let result =
/// Ok::<String, IOError>(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<S, R>
where
Expand Down Expand Up @@ -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<R, String>)) {
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<R, String>)) {
pub fn try_result(&self, f: impl FnOnce(Result<R, String>)) {
if self.state.channel_present.load(Ordering::Relaxed) {
let _ = self.state.mtx.lock().unwrap().0.take();
self.state.cvar.notify_all();
Expand Down Expand Up @@ -377,6 +384,14 @@ where
.await
}

/// Set result value
pub fn set_result(&self, r: Result<R, Box<dyn Error>>) {
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) {
{
Expand Down Expand Up @@ -461,10 +476,12 @@ where
}

pub type OIError = Box<dyn Error>;
// 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<T>` into `Result<T, E>` using `catch` fn.
pub trait IntoResult<T> {
/// Convert `Option` into `Result`
/// Convert `Option<T>` into `Result<T, E>`
fn catch(self, error_msg: impl ToString) -> Result<T, Box<dyn Error>>;
}

Expand Down

0 comments on commit 2c3db24

Please sign in to comment.