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

utility additions to ImmediateValuePromise #13

Merged
merged 2 commits into from
Oct 17, 2024
Merged
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
44 changes: 42 additions & 2 deletions src/immediatevalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ pub enum ImmediateValueState<T> {
Empty,
}

impl<T> DirectCacheAccess<T> for ImmediateValueState<T> {
impl<T> DirectCacheAccess<T, BoxedSendError> for ImmediateValueState<T> {
/// gets a mutable reference to the local cache if existing
fn get_value_mut(&mut self) -> Option<&mut T> {
match self {
Expand All @@ -134,6 +134,16 @@ impl<T> DirectCacheAccess<T> for ImmediateValueState<T> {
}
}

fn get_result(&self) -> Option<Result<&T, &BoxedSendError>> {
if let ImmediateValueState::Success(inner) = self {
Some(Ok(inner))
} else if let ImmediateValueState::Error(error) = self {
Some(Err(error))
} else {
None
}
}

/// Takes ownership of the inner value if ready, leaving self in state [`ImmediateValueState::Empty`].
/// Does nothing if we are in any other state.
fn take_value(&mut self) -> Option<T> {
Expand All @@ -146,18 +156,36 @@ impl<T> DirectCacheAccess<T> for ImmediateValueState<T> {
}
None
}

fn take_result(&mut self) -> Option<Result<T, BoxedSendError>> {
if matches!(self, ImmediateValueState::Success(_)) {
let val = mem::replace(self, ImmediateValueState::Empty);
return match val {
ImmediateValueState::Success(inner) => Some(Ok(inner)),
ImmediateValueState::Error(err) => Some(Err(err)),
_ => None,
};
}
None
}
}

impl<T: Send + 'static> DirectCacheAccess<T> for ImmediateValuePromise<T> {
impl<T: Send + 'static> DirectCacheAccess<T, BoxedSendError> for ImmediateValuePromise<T> {
fn get_value_mut(&mut self) -> Option<&mut T> {
self.state.get_value_mut()
}
fn get_value(&self) -> Option<&T> {
self.state.get_value()
}
fn get_result(&self) -> Option<Result<&T, &BoxedSendError>> {
self.state.get_result()
}
fn take_value(&mut self) -> Option<T> {
self.state.take_value()
}
fn take_result(&mut self) -> Option<Result<T, BoxedSendError>> {
self.state.take_result()
}
}

impl<T: Send + 'static> ImmediateValuePromise<T> {
Expand Down Expand Up @@ -203,6 +231,18 @@ impl<T: Send + 'static> ImmediateValuePromise<T> {
}
}

impl<T, V> From<T> for ImmediateValuePromise<V>
where
T: Future<Output = V> + Send + 'static,
V: Send + 'static
{
fn from(value: T) -> Self {
ImmediateValuePromise::new(async move {
Ok(value.await)
})
}
}

#[cfg(test)]
mod test {
use std::fs::File;
Expand Down
10 changes: 8 additions & 2 deletions src/immediatevalueprogress.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{DirectCacheAccess, Progress};
use crate::{BoxedSendError, DirectCacheAccess, Progress};
use crate::{ImmediateValuePromise, ImmediateValueState};
use std::borrow::Cow;
use std::time::Instant;
Expand Down Expand Up @@ -132,16 +132,22 @@ impl<T: Send + 'static, M> ProgressTrackedImValProm<T, M> {
}
}

impl<T: Send + 'static, M> DirectCacheAccess<T> for ProgressTrackedImValProm<T, M> {
impl<T: Send + 'static, M> DirectCacheAccess<T, BoxedSendError> for ProgressTrackedImValProm<T, M> {
fn get_value_mut(&mut self) -> Option<&mut T> {
self.promise.get_value_mut()
}
fn get_value(&self) -> Option<&T> {
self.promise.get_value()
}
fn get_result(&self) -> Option<Result<&T, &BoxedSendError>> {
self.promise.get_result()
}
fn take_value(&mut self) -> Option<T> {
self.promise.take_value()
}
fn take_result(&mut self) -> Option<Result<T, BoxedSendError>> {
self.promise.take_result()
}
}
#[cfg(test)]
mod test {
Expand Down
28 changes: 26 additions & 2 deletions src/lazyvalue.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
box_future_factory, BoxedFutureFactory, DataState, DirectCacheAccess, Message, Promise,
};
use std::fmt::Debug;
use std::{fmt::Debug, mem};
use std::future::Future;
use tokio::sync::mpsc::{channel, Receiver, Sender};

Expand Down Expand Up @@ -75,7 +75,7 @@ impl<T: Debug> LazyValuePromise<T> {
}
}

impl<T: Debug> DirectCacheAccess<T> for LazyValuePromise<T> {
impl<T: Debug> DirectCacheAccess<T, String> for LazyValuePromise<T> {
/// get current value (may be incomplete) as mutable ref, be careful with this as
/// further modification from the future may still push data.
fn get_value_mut(&mut self) -> Option<&mut T> {
Expand All @@ -87,6 +87,16 @@ impl<T: Debug> DirectCacheAccess<T> for LazyValuePromise<T> {
self.cache.as_ref()
}

fn get_result(&self) -> Option<Result<&T, &String>> {
if let DataState::UpToDate = self.state {
self.cache.as_ref().map(|cache| Ok(cache))
} else if let DataState::Error(error) = &self.state {
Some(Err(error))
} else {
None
}
}

/// takes the current value, if data was [`DataState::UpToDate`] it returns the value and sets the state to
/// [`DataState::Uninitialized`]. Otherwise, returns None.
fn take_value(&mut self) -> Option<T> {
Expand All @@ -97,6 +107,20 @@ impl<T: Debug> DirectCacheAccess<T> for LazyValuePromise<T> {
None
}
}

fn take_result(&mut self) -> Option<Result<T, String>> {
if self.state == DataState::UpToDate {
self.state = DataState::Uninitialized;
self.cache.take().map(|cache|Ok(cache))
} else if let DataState::Error(_) = self.state {
let DataState::Error(err) = mem::replace(&mut self.state, DataState::Uninitialized) else {
unreachable!();
};
Some(Err(err))
} else {
None
}
}
}

impl<T: Debug> Promise for LazyValuePromise<T> {
Expand Down
26 changes: 25 additions & 1 deletion src/lazyvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl<T: Debug> LazyVecPromise<T> {
}
}

impl<T: Debug> DirectCacheAccess<Vec<T>> for LazyVecPromise<T> {
impl<T: Debug> DirectCacheAccess<Vec<T>, String> for LazyVecPromise<T> {
fn get_value_mut(&mut self) -> Option<&mut Vec<T>> {
Some(&mut self.data)
}
Expand All @@ -103,6 +103,16 @@ impl<T: Debug> DirectCacheAccess<Vec<T>> for LazyVecPromise<T> {
Some(&self.data)
}

fn get_result(&self) -> Option<Result<&Vec<T>, &String>> {
if let DataState::UpToDate = self.state {
Some(Ok(&self.data))
} else if let DataState::Error(error) = &self.state {
Some(Err(error))
} else {
None
}
}

/// Take the current data. If state was [`DataState::UpToDate`] it will return the value.
/// If the state was anything else, it will return None. If data is taken successfully, will leave
/// the object in state [`DataState::Uninitialized`]
Expand All @@ -114,6 +124,20 @@ impl<T: Debug> DirectCacheAccess<Vec<T>> for LazyVecPromise<T> {
None
}
}

fn take_result(&mut self) -> Option<Result<Vec<T>, String>> {
if self.state == DataState::UpToDate {
self.state = DataState::Uninitialized;
Some(Ok(mem::take(&mut self.data)))
} else if let DataState::Error(_) = self.state {
let DataState::Error(err) = mem::replace(&mut self.state, DataState::Uninitialized) else {
unreachable!();
};
Some(Err(err))
} else {
None
}
}
}

impl<T: Debug> Promise for LazyVecPromise<T> {
Expand Down
14 changes: 12 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,26 +70,36 @@ impl Deref for BoxedSendError {
}

/// Trait for directly accessing the cache underneath any promise
pub trait DirectCacheAccess<T> {
pub trait DirectCacheAccess<T, E> {
/// returns mutable reference to the cache if applicable
fn get_value_mut(&mut self) -> Option<&mut T>;
/// returns a reference to the cache if applicable
fn get_value(&self) -> Option<&T>;
/// returns a reference to the cache or to error if applicable
fn get_result(&self) -> Option<Result<&T, &E>>;
/// takes the value and leaves the promise in a valid state indicating its emptiness
fn take_value(&mut self) -> Option<T>;
/// takes the value or error and leaves the promise in a valid state indicating its emptiness
fn take_result(&mut self) -> Option<Result<T, E>>;
}

/// Blanket implementation for any `Option<DirectCacheAccess<T>>` allows for better handling of option-laziness
impl<T: Send + 'static, A: DirectCacheAccess<T>> DirectCacheAccess<T> for Option<A> {
impl<T: Send + 'static, E: Send + 'static, A: DirectCacheAccess<T, E>> DirectCacheAccess<T, E> for Option<A> {
fn get_value_mut(&mut self) -> Option<&mut T> {
self.as_mut().and_then(|inner| inner.get_value_mut())
}
fn get_value(&self) -> Option<&T> {
self.as_ref().and_then(|inner| inner.get_value())
}
fn get_result(&self) -> Option<Result<&T, &E>> {
self.as_ref().and_then(|inner| inner.get_result())
}
fn take_value(&mut self) -> Option<T> {
self.as_mut().and_then(|inner| inner.take_value())
}
fn take_result(&mut self) -> Option<Result<T, E>> {
self.as_mut().and_then(|inner| inner.take_result())
}
}

/// a f64 type which is constrained to the range of 0.0 and 1.0
Expand Down
Loading