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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use std::{any::TypeId, sync::Arc};

struct RxErrorInner {
  error: Box<dyn std::any::Any + Send + Sync + 'static>,
  get_str: Box<dyn Fn(&Self) -> String + Send + Sync>,
}

#[derive(Clone)]
pub struct RxError {
  inner: Arc<RxErrorInner>,
}

impl RxError {
  pub fn from_error<E>(err: E) -> RxError
  where
    E: std::fmt::Debug + Send + Sync + 'static,
  {
    RxError {
      inner: Arc::new(RxErrorInner {
        error: Box::new(err),
        get_str: Box::new(|x: &RxErrorInner| {
          format!(
            "RxError({}) -> {:?}",
            std::any::type_name::<E>(),
            x.error.downcast_ref::<E>().unwrap()
          )
        }),
      }),
    }
  }

  pub fn from_result<T, E>(result: Result<T, E>) -> RxError
  where
    T: std::fmt::Debug,
    E: std::fmt::Debug + Send + Sync + 'static,
  {
    RxError {
      inner: Arc::new(RxErrorInner {
        error: Box::new(result.expect_err("Result must be Result::Err!")),
        get_str: Box::new(|x: &RxErrorInner| {
          format!(
            "RxError({}) -> {:?}",
            std::any::type_name::<E>(),
            x.error.downcast_ref::<E>().unwrap()
          )
        }),
      }),
    }
  }

  pub fn downcast_ref<E>(&self) -> Option<&E>
  where
    E: Send + Sync + 'static,
  {
    self.inner.error.downcast_ref::<E>()
  }

  pub fn type_id(&self) -> TypeId {
    self.inner.error.type_id()
  }

  pub fn is<T>(&self) -> bool
  where
    T: 'static,
  {
    self.inner.error.is::<T>()
  }
}

impl std::fmt::Debug for RxError {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.pad(&self.to_string())
  }
}

impl std::string::ToString for RxError {
  fn to_string(&self) -> String {
    (self.inner.get_str)(&self.inner)
  }
}

#[cfg(test)]
mod test {
  use crate::prelude::*;
  use anyhow::anyhow;

  #[test]
  fn str_ref() {
    let error = Err::<i32, _>("aaa");

    let e = RxError::from_error(error.expect_err("?"));
    println!("{:?}", e.downcast_ref::<&str>());

    let e = RxError::from_result(error);
    println!("{:?}", e.downcast_ref::<&str>());
    println!("{:?}", e);
  }

  #[test]
  fn from_error() {
    let error = Err::<i32, _>(std::io::Error::from(
      std::io::ErrorKind::NotFound,
    ));
    let e = RxError::from_error(error.expect_err("?"));
    println!(
      "{:?}",
      e.downcast_ref::<std::io::Error>()
    );

    let error = Err::<i32, _>(std::io::Error::from(
      std::io::ErrorKind::NotFound,
    ));
    let e = RxError::from_result(error);
    println!(
      "{:?}",
      e.downcast_ref::<std::io::Error>()
    );
    println!("{:?}", e);
  }

  #[test]
  fn anyhow_error() {
    let error = Err::<i32, _>(anyhow!("anyhow error"));
    let e = RxError::from_result(error);
    println!(
      "{:?}",
      e.downcast_ref::<anyhow::Error>()
    );
    println!("{:?}", e);
  }
}