1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use core::ops::{ControlFlow, FromResidual, Try};
use std::rc::Rc;

use crate::{Computed, ToComputed};

/// The state of the resource.
#[derive(Clone, Debug)]
pub enum Resource<T> {
    Loading,
    Ready(T),
    Error(String),
}

pub enum ResourceError {
    Loading,
    Error(String),
}

impl<T> Try for Resource<T> {
    type Output = T;
    type Residual = ResourceError;

    #[inline]
    fn from_output(output: Self::Output) -> Self {
        Resource::Ready(output)
    }

    #[inline]
    fn branch(self) -> ControlFlow<ResourceError, Self::Output> {
        match self {
            Self::Loading => ControlFlow::Break(ResourceError::Loading),
            Self::Error(message) => ControlFlow::Break(ResourceError::Error(message)),
            Self::Ready(value) => ControlFlow::Continue(value),
        }
    }
}

impl<T> FromResidual<ResourceError> for Resource<T> {
    fn from_residual(residual: ResourceError) -> Resource<T> {
        match residual {
            ResourceError::Error(message) => Resource::Error(message),
            ResourceError::Loading => Resource::Loading,
        }
    }
}

impl<T> Resource<T> {
    pub fn map<K>(self, map: impl Fn(T) -> K) -> Resource<K> {
        match self {
            Resource::Loading => Resource::Loading,
            Resource::Ready(data) => Resource::Ready(map(data)),
            Resource::Error(err) => Resource::Error(err),
        }
    }

    pub fn ref_map<K>(&self, map: impl Fn(&T) -> K) -> Resource<K> {
        match self {
            Resource::Loading => Resource::Loading,
            Resource::Ready(data) => Resource::Ready(map(data)),
            Resource::Error(err) => Resource::Error(err.clone()),
        }
    }
}

impl<T: Clone> Resource<T> {
    #[must_use]
    pub fn ref_clone(&self) -> Self {
        match self {
            Resource::Loading => Resource::Loading,
            Resource::Ready(data) => Resource::Ready(data.clone()),
            Resource::Error(error) => Resource::Error(error.clone()),
        }
    }
}

impl<T: PartialEq> PartialEq for Resource<T> {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Resource::Loading, Resource::Loading) => true,
            (Resource::Error(message1), Resource::Error(message2)) => message1.eq(message2),
            (Resource::Ready(val1), Resource::Ready(val2)) => val1.eq(val2),
            _ => false,
        }
    }
}

impl<T: Clone + 'static> ToComputed<Resource<Rc<T>>> for Resource<T> {
    fn to_computed(&self) -> crate::Computed<Resource<Rc<T>>> {
        Computed::from({
            let myself = self.clone();
            move |_| myself.clone().map(|item| Rc::new(item))
        })
    }
}

impl<T: Clone + 'static> ToComputed<Resource<Rc<T>>> for Computed<Resource<T>> {
    fn to_computed(&self) -> crate::Computed<Resource<Rc<T>>> {
        self.map(|res| res.map(|item| Rc::new(item)))
    }
}