vertigo/fetch/
resource.rs

1use core::ops::{ControlFlow, FromResidual, Try};
2use std::rc::Rc;
3
4use crate::{Computed, ToComputed};
5
6/// The state of the resource.
7#[derive(Clone, Debug)]
8pub enum Resource<T> {
9    Loading,
10    Ready(T),
11    Error(String),
12}
13
14pub enum ResourceError {
15    Loading,
16    Error(String),
17}
18
19impl<T> Try for Resource<T> {
20    type Output = T;
21    type Residual = ResourceError;
22
23    #[inline]
24    fn from_output(output: Self::Output) -> Self {
25        Resource::Ready(output)
26    }
27
28    #[inline]
29    fn branch(self) -> ControlFlow<ResourceError, Self::Output> {
30        match self {
31            Self::Loading => ControlFlow::Break(ResourceError::Loading),
32            Self::Error(message) => ControlFlow::Break(ResourceError::Error(message)),
33            Self::Ready(value) => ControlFlow::Continue(value),
34        }
35    }
36}
37
38impl<T> FromResidual<ResourceError> for Resource<T> {
39    fn from_residual(residual: ResourceError) -> Resource<T> {
40        match residual {
41            ResourceError::Error(message) => Resource::Error(message),
42            ResourceError::Loading => Resource::Loading,
43        }
44    }
45}
46
47impl<T> Resource<T> {
48    pub fn map<K>(self, map: impl Fn(T) -> K) -> Resource<K> {
49        match self {
50            Resource::Loading => Resource::Loading,
51            Resource::Ready(data) => Resource::Ready(map(data)),
52            Resource::Error(err) => Resource::Error(err),
53        }
54    }
55
56    pub fn ref_map<K>(&self, map: impl Fn(&T) -> K) -> Resource<K> {
57        match self {
58            Resource::Loading => Resource::Loading,
59            Resource::Ready(data) => Resource::Ready(map(data)),
60            Resource::Error(err) => Resource::Error(err.clone()),
61        }
62    }
63}
64
65impl<T: Clone> Resource<T> {
66    #[must_use]
67    pub fn ref_clone(&self) -> Self {
68        match self {
69            Resource::Loading => Resource::Loading,
70            Resource::Ready(data) => Resource::Ready(data.clone()),
71            Resource::Error(error) => Resource::Error(error.clone()),
72        }
73    }
74}
75
76impl<T: PartialEq> PartialEq for Resource<T> {
77    fn eq(&self, other: &Self) -> bool {
78        match (self, other) {
79            (Resource::Loading, Resource::Loading) => true,
80            (Resource::Error(message1), Resource::Error(message2)) => message1.eq(message2),
81            (Resource::Ready(val1), Resource::Ready(val2)) => val1.eq(val2),
82            _ => false,
83        }
84    }
85}
86
87impl<T: Clone + 'static> ToComputed<Resource<Rc<T>>> for Resource<T> {
88    fn to_computed(&self) -> crate::Computed<Resource<Rc<T>>> {
89        Computed::from({
90            let myself = self.clone();
91            move |_| myself.clone().map(|item| Rc::new(item))
92        })
93    }
94}
95
96impl<T: Clone + 'static> ToComputed<Resource<Rc<T>>> for Computed<Resource<T>> {
97    fn to_computed(&self) -> crate::Computed<Resource<Rc<T>>> {
98        self.map(|res| res.map(|item| Rc::new(item)))
99    }
100}