use crate::{AnyVar, Var};
use super::*;
pub fn response_var<T: VarValue>() -> (ResponderVar<T>, ResponseVar<T>) {
let responder = var(Response::Waiting::<T>);
let response = responder.read_only();
(ResponderVar(responder), ResponseVar(response))
}
pub fn response_done_var<T: VarValue>(response: T) -> ResponseVar<T> {
ResponseVar(var(Response::Done(response)).read_only())
}
#[derive(Clone)]
pub struct ResponderVar<T: VarValue>(Var<Response<T>>);
#[derive(Clone)]
pub struct ResponseVar<T: VarValue>(Var<Response<T>>);
impl<T: VarValue> ops::Deref for ResponderVar<T> {
type Target = Var<Response<T>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: VarValue> IntoVar<Response<T>> for ResponderVar<T> {
fn into_var(self) -> Var<Response<T>> {
self.0
}
}
impl<T: VarValue> From<ResponderVar<T>> for Var<Response<T>> {
fn from(var: ResponderVar<T>) -> Self {
var.0
}
}
impl<T: VarValue> From<ResponderVar<T>> for AnyVar {
fn from(var: ResponderVar<T>) -> Self {
var.0.into()
}
}
impl<T: VarValue> ops::Deref for ResponseVar<T> {
type Target = Var<Response<T>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: VarValue> IntoVar<Response<T>> for ResponseVar<T> {
fn into_var(self) -> Var<Response<T>> {
self.0
}
}
impl<T: VarValue> From<ResponseVar<T>> for Var<Response<T>> {
fn from(var: ResponseVar<T>) -> Self {
var.0
}
}
impl<T: VarValue> From<ResponseVar<T>> for AnyVar {
fn from(var: ResponseVar<T>) -> Self {
var.0.into()
}
}
impl<T: VarValue> From<Var<Response<T>>> for ResponderVar<T> {
fn from(var: Var<Response<T>>) -> Self {
if var.capabilities().is_always_read_only() {
tracing::error!("creating `ResponderVar` from `is_always_read_only` var");
}
ResponderVar(var)
}
}
impl<T: VarValue> From<Var<Response<T>>> for ResponseVar<T> {
fn from(var: Var<Response<T>>) -> Self {
ResponseVar(var.read_only())
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum Response<T: VarValue> {
Waiting,
Done(T),
}
impl<T: VarValue> Response<T> {
pub fn is_done(&self) -> bool {
matches!(self, Response::Done(_))
}
pub fn is_waiting(&self) -> bool {
matches!(self, Response::Waiting)
}
pub fn done(&self) -> Option<&T> {
match self {
Response::Waiting => None,
Response::Done(r) => Some(r),
}
}
}
impl<T: VarValue> fmt::Debug for Response<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
match self {
Response::Waiting => {
write!(f, "Response::Waiting")
}
Response::Done(v) => f.debug_tuple("Response::Done").field(v).finish(),
}
} else {
match self {
Response::Waiting => {
write!(f, "Waiting")
}
Response::Done(v) => fmt::Debug::fmt(v, f),
}
}
}
}
impl<T: VarValue> From<Response<T>> for Option<T> {
fn from(value: Response<T>) -> Self {
match value {
Response::Waiting => None,
Response::Done(r) => Some(r),
}
}
}
impl<T: VarValue> From<Response<Option<T>>> for Option<T> {
fn from(value: Response<Option<T>>) -> Self {
match value {
Response::Waiting => None,
Response::Done(r) => r,
}
}
}
impl<T: VarValue> ResponseVar<T> {
pub fn with_rsp<R>(&self, read: impl FnOnce(&T) -> R) -> Option<R> {
self.with(|value| match value {
Response::Waiting => None,
Response::Done(value) => Some(read(value)),
})
}
pub fn with_new_rsp<R>(&self, read: impl FnOnce(&T) -> R) -> Option<R> {
self.with_new(|value| match value {
Response::Waiting => None,
Response::Done(value) => Some(read(value)),
})
.flatten()
}
pub fn is_done(&self) -> bool {
self.with(Response::is_done)
}
pub fn is_waiting(&self) -> bool {
self.with(Response::is_waiting)
}
pub fn rsp(&self) -> Option<T> {
self.with_rsp(Clone::clone)
}
pub async fn wait_rsp(&self) -> T {
self.wait_done().await;
self.rsp().unwrap()
}
pub async fn wait_done(&self) {
self.wait_match(Response::is_done).await;
}
pub fn rsp_new(&self) -> Option<T> {
self.with_new_rsp(Clone::clone)
}
pub fn map_rsp<O, I, M>(&self, waiting_value: I, map: M) -> Var<O>
where
O: VarValue,
I: Fn() -> O + Send + Sync + 'static,
M: FnOnce(&T) -> O + Send + 'static,
{
let mut map = Some(map);
self.filter_map(
move |r| match r {
Response::Waiting => None,
Response::Done(r) => map.take().map(|m| m(r)),
},
waiting_value,
)
}
pub fn map_response<O, M>(&self, mut map: M) -> ResponseVar<O>
where
O: VarValue,
M: FnMut(&T) -> O + Send + 'static,
{
ResponseVar(self.map(move |r| match r {
Response::Waiting => Response::Waiting,
Response::Done(t) => Response::Done(map(t)),
}))
}
}
impl<T: VarValue> IntoFuture for ResponseVar<T> {
type Output = T;
type IntoFuture = std::pin::Pin<Box<dyn Future<Output = T> + Send + Sync>>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(async move { self.wait_rsp().await })
}
}
impl<T: VarValue> ResponderVar<T> {
pub fn respond(&self, response: T) {
self.set(Response::Done(response));
}
pub fn response_var(&self) -> ResponseVar<T> {
ResponseVar(self.read_only())
}
}