#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum LightstreamerError {
#[error("invalid argument: {0}")]
InvalidArgument(String),
#[error("invalid state: {0}")]
InvalidState(String),
#[error("connection error: {0}")]
Connection(String),
#[error("subscription error: {0}")]
Subscription(String),
#[error("configuration error: {0}")]
Configuration(String),
#[error("protocol error: {0}")]
Protocol(String),
#[error("channel error: {0}")]
Channel(String),
#[error("parse error: {0}")]
Parse(String),
#[error("authentication error: {0}")]
Authentication(String),
#[error("network error: {0}")]
Network(String),
#[error("timeout: {0}")]
Timeout(String),
#[error("lock error: {0}")]
Lock(String),
}
impl LightstreamerError {
#[cold]
#[must_use]
#[inline]
pub fn invalid_argument(msg: impl Into<String>) -> Self {
Self::InvalidArgument(msg.into())
}
#[cold]
#[must_use]
#[inline]
pub fn invalid_state(msg: impl Into<String>) -> Self {
Self::InvalidState(msg.into())
}
#[cold]
#[must_use]
#[inline]
pub fn connection(msg: impl Into<String>) -> Self {
Self::Connection(msg.into())
}
#[cold]
#[must_use]
#[inline]
pub fn subscription(msg: impl Into<String>) -> Self {
Self::Subscription(msg.into())
}
#[cold]
#[must_use]
#[inline]
pub fn configuration(msg: impl Into<String>) -> Self {
Self::Configuration(msg.into())
}
#[cold]
#[must_use]
#[inline]
pub fn protocol(msg: impl Into<String>) -> Self {
Self::Protocol(msg.into())
}
#[cold]
#[must_use]
#[inline]
pub fn channel(msg: impl Into<String>) -> Self {
Self::Channel(msg.into())
}
#[cold]
#[must_use]
#[inline]
pub fn parse(msg: impl Into<String>) -> Self {
Self::Parse(msg.into())
}
#[cold]
#[must_use]
#[inline]
pub fn lock(msg: impl Into<String>) -> Self {
Self::Lock(msg.into())
}
}
pub type Result<T> = std::result::Result<T, LightstreamerError>;
impl From<String> for LightstreamerError {
fn from(s: String) -> Self {
LightstreamerError::InvalidArgument(s)
}
}
impl From<&str> for LightstreamerError {
fn from(s: &str) -> Self {
LightstreamerError::InvalidArgument(s.to_string())
}
}
impl From<Box<dyn std::error::Error>> for LightstreamerError {
fn from(e: Box<dyn std::error::Error>) -> Self {
LightstreamerError::InvalidState(e.to_string())
}
}
impl From<Box<dyn std::error::Error + Send + Sync>> for LightstreamerError {
fn from(e: Box<dyn std::error::Error + Send + Sync>) -> Self {
LightstreamerError::InvalidState(e.to_string())
}
}
impl From<tokio_tungstenite::tungstenite::http::Error> for LightstreamerError {
fn from(e: tokio_tungstenite::tungstenite::http::Error) -> Self {
LightstreamerError::InvalidState(e.to_string())
}
}
impl From<serde_urlencoded::ser::Error> for LightstreamerError {
fn from(e: serde_urlencoded::ser::Error) -> Self {
LightstreamerError::InvalidArgument(e.to_string())
}
}
impl From<tokio_tungstenite::tungstenite::Error> for LightstreamerError {
fn from(e: tokio_tungstenite::tungstenite::Error) -> Self {
LightstreamerError::Connection(e.to_string())
}
}
impl From<std::io::Error> for LightstreamerError {
fn from(e: std::io::Error) -> Self {
LightstreamerError::Connection(e.to_string())
}
}
impl From<tokio::sync::mpsc::error::SendError<crate::client::SubscriptionRequest>>
for LightstreamerError
{
fn from(e: tokio::sync::mpsc::error::SendError<crate::client::SubscriptionRequest>) -> Self {
LightstreamerError::InvalidState(e.to_string())
}
}
impl From<tokio::sync::mpsc::error::TrySendError<usize>> for LightstreamerError {
fn from(e: tokio::sync::mpsc::error::TrySendError<usize>) -> Self {
LightstreamerError::Channel(e.to_string())
}
}
impl From<crate::connection::ReconnectionError> for LightstreamerError {
fn from(e: crate::connection::ReconnectionError) -> Self {
LightstreamerError::Connection(e.to_string())
}
}
impl From<std::env::VarError> for LightstreamerError {
fn from(e: std::env::VarError) -> Self {
LightstreamerError::Configuration(e.to_string())
}
}
#[deprecated(
since = "0.3.0",
note = "Use LightstreamerError::InvalidArgument instead"
)]
pub type IllegalArgumentException = LightstreamerError;
#[deprecated(since = "0.3.0", note = "Use LightstreamerError::InvalidState instead")]
pub type IllegalStateException = LightstreamerError;
#[cfg(test)]
mod tests {
use super::*;
use std::error::Error;
#[test]
fn test_invalid_argument_error() -> Result<()> {
let error = LightstreamerError::invalid_argument("Test error message");
let debug_output = format!("{:?}", error);
assert!(debug_output.contains("InvalidArgument"));
assert!(debug_output.contains("Test error message"));
assert_eq!(error.to_string(), "invalid argument: Test error message");
Ok(())
}
#[test]
fn test_invalid_state_error() -> Result<()> {
let error = LightstreamerError::invalid_state("Test state error");
let debug_output = format!("{:?}", error);
assert!(debug_output.contains("InvalidState"));
assert!(debug_output.contains("Test state error"));
assert_eq!(error.to_string(), "invalid state: Test state error");
Ok(())
}
#[test]
fn test_all_error_variants() -> Result<()> {
let errors = vec![
(
LightstreamerError::connection("conn"),
"connection error: conn",
),
(
LightstreamerError::subscription("sub"),
"subscription error: sub",
),
(
LightstreamerError::configuration("cfg"),
"configuration error: cfg",
),
(
LightstreamerError::protocol("proto"),
"protocol error: proto",
),
(LightstreamerError::channel("chan"), "channel error: chan"),
(LightstreamerError::parse("parse"), "parse error: parse"),
(LightstreamerError::lock("lock"), "lock error: lock"),
];
for (error, expected_msg) in errors {
assert_eq!(error.to_string(), expected_msg);
}
Ok(())
}
#[test]
fn test_error_propagation() -> Result<()> {
fn function_that_fails() -> Result<()> {
Err(LightstreamerError::invalid_argument("Test propagation"))
}
fn propagate_error() -> Result<()> {
function_that_fails()?;
Ok(())
}
let result = propagate_error();
assert!(result.is_err());
if let Err(error) = result {
assert_eq!(error.to_string(), "invalid argument: Test propagation");
}
Ok(())
}
#[test]
fn test_error_conversion_to_box_dyn() -> Result<()> {
let error = LightstreamerError::invalid_argument("Test conversion");
let boxed_error: Box<dyn Error> = Box::new(error);
assert_eq!(boxed_error.to_string(), "invalid argument: Test conversion");
Ok(())
}
#[test]
fn test_error_as_return_type() -> Result<()> {
fn may_fail(value: i32) -> Result<()> {
if value < 0 {
Err(LightstreamerError::invalid_argument(
"Value cannot be negative",
))
} else if value > 100 {
Err(LightstreamerError::invalid_state("Value too large"))
} else {
Ok(())
}
}
let result = may_fail(-10);
assert!(result.is_err());
if let Err(error) = result {
assert_eq!(
error.to_string(),
"invalid argument: Value cannot be negative"
);
}
let result = may_fail(150);
assert!(result.is_err());
if let Err(error) = result {
assert_eq!(error.to_string(), "invalid state: Value too large");
}
let result = may_fail(50);
assert!(result.is_ok());
Ok(())
}
#[test]
fn test_error_trait_methods() -> Result<()> {
let error = LightstreamerError::invalid_argument("Test error");
let error_ref: &dyn Error = &error;
assert!(error_ref.source().is_none());
Ok(())
}
#[test]
fn test_error_equality() -> Result<()> {
let error1 = LightstreamerError::invalid_argument("test");
let error2 = LightstreamerError::invalid_argument("test");
let error3 = LightstreamerError::invalid_state("test");
assert_eq!(error1, error2);
assert_ne!(error1, error3);
Ok(())
}
#[test]
fn test_error_clone() -> Result<()> {
let error = LightstreamerError::connection("test connection");
let cloned = error.clone();
assert_eq!(error, cloned);
Ok(())
}
}