From c1b2f7fb59e4432976ad56c724337444ec212314 Mon Sep 17 00:00:00 2001 From: tomellm Date: Wed, 16 Oct 2024 08:01:03 +0200 Subject: [PATCH 1/2] added get_result and take_result They get and take a "Option>" object out of the DirectCacheAccess implementor. When None the status was updating or blank and if the result is present the status was success or error. --- src/immediatevalue.rs | 32 ++++++++++++++++++++++++++++++-- src/immediatevalueprogress.rs | 10 ++++++++-- src/lazyvalue.rs | 28 ++++++++++++++++++++++++++-- src/lazyvec.rs | 26 +++++++++++++++++++++++++- src/lib.rs | 14 ++++++++++++-- 5 files changed, 101 insertions(+), 9 deletions(-) diff --git a/src/immediatevalue.rs b/src/immediatevalue.rs index 9e2a29c..78789dd 100644 --- a/src/immediatevalue.rs +++ b/src/immediatevalue.rs @@ -117,7 +117,7 @@ pub enum ImmediateValueState { Empty, } -impl DirectCacheAccess for ImmediateValueState { +impl DirectCacheAccess for ImmediateValueState { /// gets a mutable reference to the local cache if existing fn get_value_mut(&mut self) -> Option<&mut T> { match self { @@ -134,6 +134,16 @@ impl DirectCacheAccess for ImmediateValueState { } } + fn get_result(&self) -> Option> { + 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 { @@ -146,18 +156,36 @@ impl DirectCacheAccess for ImmediateValueState { } None } + + fn take_result(&mut self) -> Option> { + 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 DirectCacheAccess for ImmediateValuePromise { +impl DirectCacheAccess for ImmediateValuePromise { 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> { + self.state.get_result() + } fn take_value(&mut self) -> Option { self.state.take_value() } + fn take_result(&mut self) -> Option> { + self.state.take_result() + } } impl ImmediateValuePromise { diff --git a/src/immediatevalueprogress.rs b/src/immediatevalueprogress.rs index 5c4a76c..2e5869d 100644 --- a/src/immediatevalueprogress.rs +++ b/src/immediatevalueprogress.rs @@ -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; @@ -132,16 +132,22 @@ impl ProgressTrackedImValProm { } } -impl DirectCacheAccess for ProgressTrackedImValProm { +impl DirectCacheAccess for ProgressTrackedImValProm { 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> { + self.promise.get_result() + } fn take_value(&mut self) -> Option { self.promise.take_value() } + fn take_result(&mut self) -> Option> { + self.promise.take_result() + } } #[cfg(test)] mod test { diff --git a/src/lazyvalue.rs b/src/lazyvalue.rs index 0ae0778..424b01a 100644 --- a/src/lazyvalue.rs +++ b/src/lazyvalue.rs @@ -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}; @@ -75,7 +75,7 @@ impl LazyValuePromise { } } -impl DirectCacheAccess for LazyValuePromise { +impl DirectCacheAccess for LazyValuePromise { /// 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> { @@ -87,6 +87,16 @@ impl DirectCacheAccess for LazyValuePromise { self.cache.as_ref() } + fn get_result(&self) -> Option> { + 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 { @@ -97,6 +107,20 @@ impl DirectCacheAccess for LazyValuePromise { None } } + + fn take_result(&mut self) -> Option> { + 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 Promise for LazyValuePromise { diff --git a/src/lazyvec.rs b/src/lazyvec.rs index e3e36e5..0914608 100644 --- a/src/lazyvec.rs +++ b/src/lazyvec.rs @@ -94,7 +94,7 @@ impl LazyVecPromise { } } -impl DirectCacheAccess> for LazyVecPromise { +impl DirectCacheAccess, String> for LazyVecPromise { fn get_value_mut(&mut self) -> Option<&mut Vec> { Some(&mut self.data) } @@ -103,6 +103,16 @@ impl DirectCacheAccess> for LazyVecPromise { Some(&self.data) } + fn get_result(&self) -> Option, &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`] @@ -114,6 +124,20 @@ impl DirectCacheAccess> for LazyVecPromise { None } } + + fn take_result(&mut self) -> Option, 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 Promise for LazyVecPromise { diff --git a/src/lib.rs b/src/lib.rs index 419b93c..1f8021f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,26 +70,36 @@ impl Deref for BoxedSendError { } /// Trait for directly accessing the cache underneath any promise -pub trait DirectCacheAccess { +pub trait DirectCacheAccess { /// 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>; /// takes the value and leaves the promise in a valid state indicating its emptiness fn take_value(&mut self) -> Option; + /// takes the value or error and leaves the promise in a valid state indicating its emptiness + fn take_result(&mut self) -> Option>; } /// Blanket implementation for any `Option>` allows for better handling of option-laziness -impl> DirectCacheAccess for Option { +impl> DirectCacheAccess for Option { 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> { + self.as_ref().and_then(|inner| inner.get_result()) + } fn take_value(&mut self) -> Option { self.as_mut().and_then(|inner| inner.take_value()) } + fn take_result(&mut self) -> Option> { + self.as_mut().and_then(|inner| inner.take_result()) + } } /// a f64 type which is constrained to the range of 0.0 and 1.0 From 2c9de5e9ad206f766bf57985159b8296f6b1622a Mon Sep 17 00:00:00 2001 From: tomellm Date: Wed, 16 Oct 2024 08:05:21 +0200 Subject: [PATCH 2/2] implemented From<"Future"> for ImmediateValuePromise makes it easier to work with ImmediateValuePromise's since all that is needed to create one is a ".into()". --- src/immediatevalue.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/immediatevalue.rs b/src/immediatevalue.rs index 78789dd..51b67b7 100644 --- a/src/immediatevalue.rs +++ b/src/immediatevalue.rs @@ -231,6 +231,18 @@ impl ImmediateValuePromise { } } +impl From for ImmediateValuePromise +where + T: Future + 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;