Skip to content

Commit

Permalink
Merge pull request #12 from ChrisRega/0.5.0-dev
Browse files Browse the repository at this point in the history
0.5.0 dev branch
  • Loading branch information
ChrisRega authored May 29, 2023
2 parents 50df977 + b337060 commit 65837e2
Show file tree
Hide file tree
Showing 7 changed files with 384 additions and 168 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "lazy_async_promise"
version = "0.4.0"
version = "0.5.0"
edition = "2021"
authors = ["Christopher Regali <[email protected]>"]
license = "MIT"
Expand All @@ -15,5 +15,5 @@ description = "Primitives for lazily getting data from futures with tokio for im
tokio = {version="1", features=["rt-multi-thread", "sync"]}

[dev-dependencies]
tokio = {version="1", features=["rt-multi-thread", "sync", "time", "fs"]}
tokio = {version="1", features=["rt-multi-thread", "sync", "time", "fs", "macros"]}

5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ Another example usage of this crate with a small egui/eframe blog-reader can be

Changelog:

0.5.0
- Fixed visibility issues with BoxSendError (thanks @aspcartman)
- Added progress tracked wrapper for immediate value promise (made lazyvaluepromise obsolete at least for me)
- Updated documentation

0.4.0:
- Added more flexible API to lazy and immediate structures, allowing to take the values
- Added DirectCacheAccess trait to make option-based usage of the immediate value promise more convenient
Expand Down
192 changes: 90 additions & 102 deletions src/immediatevalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ use crate::{BoxedSendError, DirectCacheAccess, FutureResult};
/// assert_eq!(*value_opt.unwrap(), 34);
/// ```
///
pub struct ImmediateValuePromise<T: Send + 'static> {
pub struct ImmediateValuePromise<T: Send> {
value_arc: Arc<Mutex<Option<FutureResult<T>>>>,
state: ImmediateValueState<T>,
}
Expand Down Expand Up @@ -160,9 +160,9 @@ impl<T: Send + 'static> DirectCacheAccess<T> for ImmediateValuePromise<T> {
}
}

impl<T: Send> ImmediateValuePromise<T> {
impl<T: Send + 'static> ImmediateValuePromise<T> {
/// Creator, supply a future which returns `Result<T, Box<dyn Error + Send>`. Will be immediately spawned via tokio.
pub fn new<U: Future<Output=Result<T, BoxedSendError>> + Send + 'static>(updater: U) -> Self {
pub fn new<U: Future<Output = Result<T, BoxedSendError>> + Send + 'static>(updater: U) -> Self {
let arc = Arc::new(Mutex::new(None));
let arc_clone = arc.clone();
tokio::spawn(async move {
Expand Down Expand Up @@ -208,119 +208,107 @@ mod test {
use std::fs::File;
use std::time::Duration;

use tokio::runtime::Runtime;

use crate::DirectCacheAccess;
use crate::immediatevalue::{ImmediateValuePromise, ImmediateValueState};
use crate::DirectCacheAccess;

#[test]
fn default() {
Runtime::new().unwrap().block_on(async {
let mut oneshot_val = ImmediateValuePromise::new(async {
tokio::time::sleep(Duration::from_millis(50)).await;
Ok(34)
});
assert!(matches!(
oneshot_val.poll_state(),
ImmediateValueState::Updating
));
tokio::time::sleep(Duration::from_millis(100)).await;
let result = oneshot_val.poll_state();
if let ImmediateValueState::Success(val) = result {
assert_eq!(*val, 34);
return;
}
unreachable!();
#[tokio::test]
async fn default() {
let mut oneshot_val = ImmediateValuePromise::new(async {
tokio::time::sleep(Duration::from_millis(50)).await;
Ok(34)
});
assert!(matches!(
oneshot_val.poll_state(),
ImmediateValueState::Updating
));
tokio::time::sleep(Duration::from_millis(100)).await;
let result = oneshot_val.poll_state();
if let ImmediateValueState::Success(val) = result {
assert_eq!(*val, 34);
return;
}
unreachable!();
}

#[test]
fn error() {
Runtime::new().unwrap().block_on(async {
let mut oneshot_val = ImmediateValuePromise::new(async {
let some_result = File::open("DOES_NOT_EXIST");
some_result?;
Ok("bla".to_string())
});
assert!(matches!(
oneshot_val.poll_state(),
ImmediateValueState::Updating
));
tokio::time::sleep(Duration::from_millis(50)).await;
let result = oneshot_val.poll_state();
if let ImmediateValueState::Error(e) = result {
let _ = format!("{}", **e);
return;
}
unreachable!();
#[tokio::test]
async fn error() {
let mut oneshot_val = ImmediateValuePromise::new(async {
let some_result = File::open("DOES_NOT_EXIST");
some_result?;
Ok("bla".to_string())
});
assert!(matches!(
oneshot_val.poll_state(),
ImmediateValueState::Updating
));
tokio::time::sleep(Duration::from_millis(50)).await;
let result = oneshot_val.poll_state();
if let ImmediateValueState::Error(e) = result {
let _ = format!("{}", **e);
return;
}
unreachable!();
}

#[test]
fn get_state() {
Runtime::new().unwrap().block_on(async {
let mut oneshot_val = ImmediateValuePromise::new(async { Ok("bla".to_string()) });
// get value does not trigger any polling
let state = oneshot_val.get_state();
assert!(matches!(state, ImmediateValueState::Updating));
tokio::time::sleep(Duration::from_millis(50)).await;
let state = oneshot_val.get_state();
assert!(matches!(state, ImmediateValueState::Updating));
#[tokio::test]
async fn get_state() {
let mut oneshot_val = ImmediateValuePromise::new(async { Ok("bla".to_string()) });
// get value does not trigger any polling
let state = oneshot_val.get_state();
assert!(matches!(state, ImmediateValueState::Updating));
tokio::time::sleep(Duration::from_millis(50)).await;
let state = oneshot_val.get_state();
assert!(matches!(state, ImmediateValueState::Updating));

let polled = oneshot_val.poll_state();
assert_eq!(polled.get_value().unwrap(), "bla");
});
let polled = oneshot_val.poll_state();
assert_eq!(polled.get_value().unwrap(), "bla");
}

#[test]
fn get_mut_take_value() {
Runtime::new().unwrap().block_on(async {
let mut oneshot_val = ImmediateValuePromise::new(async { Ok("bla".to_string()) });
tokio::time::sleep(Duration::from_millis(50)).await;
{
// get value does not trigger any polling
let result = oneshot_val.poll_state_mut();
// we got the value
if let Some(inner) = result.get_value_mut() {
assert_eq!(inner, "bla");
// write back
*inner = "changed".to_string();
} else {
unreachable!();
}
let result = oneshot_val.poll_state_mut();
// take it out, should be changed and owned
let value = result.take_value();
assert_eq!(value.unwrap().as_str(), "changed");
assert!(matches!(result, ImmediateValueState::Empty));
#[tokio::test]
async fn get_mut_take_value() {
let mut oneshot_val = ImmediateValuePromise::new(async { Ok("bla".to_string()) });
tokio::time::sleep(Duration::from_millis(50)).await;
{
// get value does not trigger any polling
let result = oneshot_val.poll_state_mut();
// we got the value
if let Some(inner) = result.get_value_mut() {
assert_eq!(inner, "bla");
// write back
*inner = "changed".to_string();
} else {
unreachable!();
}
// afterwards we are empty on get and poll
assert!(matches!(
oneshot_val.get_state(),
ImmediateValueState::Empty
));
assert!(matches!(
oneshot_val.poll_state(),
ImmediateValueState::Empty
));
});
let result = oneshot_val.poll_state_mut();
// take it out, should be changed and owned
let value = result.take_value();
assert_eq!(value.unwrap().as_str(), "changed");
assert!(matches!(result, ImmediateValueState::Empty));
}
// afterwards we are empty on get and poll
assert!(matches!(
oneshot_val.get_state(),
ImmediateValueState::Empty
));
assert!(matches!(
oneshot_val.poll_state(),
ImmediateValueState::Empty
));
}

#[test]
fn option_laziness() {
#[tokio::test]
async fn option_laziness() {
use crate::*;
Runtime::new().unwrap().block_on(async {
let mut option = Some(ImmediateValuePromise::new(async { Ok("bla".to_string()) }));
tokio::time::sleep(Duration::from_millis(50)).await;
option.as_mut().unwrap().poll_state();
let _inner = option.get_value();
let _inner_mut = option.get_value_mut();
let inner_owned = option.take_value().unwrap();
assert_eq!(inner_owned, "bla");
// after value is taken, we can't borrow it again
assert!(option.get_value().is_none());
assert!(option.get_value_mut().is_none());
assert!(option.take_value().is_none());
});
let mut option = Some(ImmediateValuePromise::new(async { Ok("bla".to_string()) }));
tokio::time::sleep(Duration::from_millis(50)).await;
option.as_mut().unwrap().poll_state();
let _inner = option.get_value();
let _inner_mut = option.get_value_mut();
let inner_owned = option.take_value().unwrap();
assert_eq!(inner_owned, "bla");
// after value is taken, we can't borrow it again
assert!(option.get_value().is_none());
assert!(option.get_value_mut().is_none());
assert!(option.take_value().is_none());
}
}
Loading

0 comments on commit 65837e2

Please sign in to comment.