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
132
133
134
135
136
137
138
use crate::{ import::* };


/// The error type for errors happening in `async_runtime`.
///
/// Use [`RtErr::kind()`] to know which kind of error happened. [RtErrKind] implements [Eq],
/// so you can do the following if all you want to know is the kind of error:
///
/// ```ignore
/// use async_runtime::*;
///
/// rt::init( RtConfig::Local ).expect( "Set default executor" );
///
/// match rt::init( RtConfig::Pool )
/// {
///    Err(e) =>
///    {
///       if let RtErrKind::DoubleExecutorInit = e.kind()
///       {
///          println!( "{}", e );
///       }
///
///       // This also works:
///       //
///       match e.kind()
///       {
///          RtErrKind::DoubleExecutorInit => println!( "{}", e ),
///          _ => {},
///       }
///    },
///
///    Ok(_) => {}
/// }
/// ```
//
#[ derive( Debug ) ]
//
pub struct RtErr
{
	inner: FailContext<RtErrKind>,
}



/// The different kind of errors that can happen when you use the `async_runtime` API.
//
#[ derive( Clone, PartialEq, Eq, Debug, Fail ) ]
//
pub enum RtErrKind
{
	/// You should not call [rt::init](crate::rt::init) twice on the same thread. In general if you are a library
	/// author, you should not call it unless you started the thread. Otherwise just call [rt::spawn](crate::rt::spawn)
	/// and let the client code decide which executor shall be used.
	//
	#[ fail( display = "DoubleExecutorInit: Cannot initialize global executor twice" ) ]
	//
	DoubleExecutorInit,

	/// An backend error happened while trying to spawn:
	///
	/// - Spawning on wasm   is infallible.
	/// - Spawning on juliex is infallible (as long as you don't call [rt::spawn_local](crate::rt::spawn_local)).
	/// - Spawning on futures::executor::LocalPool can fail with [futures::task::SpawnError].
	///   The only reason for this is that the executor was shut down.
	///
	/// Note that even though certain executors are infallible right now, that might change in the
	/// future, notably WASM is bound to change quite alot over time.
	//
	#[ fail( display = "Spawn: Failed to spawn a future in: {}", context ) ]
	//
	Spawn
	{
		/// Add contextual information to which future failed to spawn.
		///
		context: String
	},
}



impl Fail for RtErr
{
	fn cause( &self ) -> Option< &dyn Fail >
	{
		self.inner.cause()
	}

	fn backtrace( &self ) -> Option< &Backtrace >
	{
		self.inner.backtrace()
	}
}



impl fmt::Display for RtErr
{
	fn fmt( &self, f: &mut fmt::Formatter<'_> ) -> fmt::Result
	{
		fmt::Display::fmt( &self.inner, f )
	}
}


impl RtErr
{
	/// Allows matching on the error kind
	//
	pub fn kind( &self ) -> &RtErrKind
	{
		self.inner.get_context()
	}
}

impl From<RtErrKind> for RtErr
{
	fn from( kind: RtErrKind ) -> RtErr
	{
		RtErr { inner: FailContext::new( kind ) }
	}
}

impl From< FailContext<RtErrKind> > for RtErr
{
	fn from( inner: FailContext<RtErrKind> ) -> RtErr
	{
		RtErr { inner }
	}
}


// TODO: this no longer compiles. It compiles fine in thespis, but not in this crate even though this
// file is largely copy/paste. The problem is that there is a blanket impl for Fail in failure for every
// E: std::error::Error + 'static + Send + Sync
//
// impl std::error::Error for RtErr {}