another-rxrust 0.0.46

A different implementation than `rxRust` for easier use of `ReactiveX` in `Rust`.
Documentation
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);
  }
}