use super::*;
use crate::core::errors::*;
use getset::{CopyGetters, Getters};
#[cfg(feature = "serialize-json")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "serialize-json")]
use serde_repr::{Deserialize_repr, Serialize_repr};
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
#[cfg_attr(feature = "serialize-json", derive(Serialize_repr, Deserialize_repr))]
#[repr(u8)]
pub enum ErrorCode {
ErrorUnknown = 0,
ErrorHandshake,
ErrorPing,
ErrorMessage,
ErrorDevice,
}
#[derive(
Debug,
Clone,
ButtplugMessage,
ButtplugMessageValidator,
ButtplugMessageFinalizer,
Getters,
CopyGetters,
)]
#[cfg_attr(feature = "serialize-json", derive(Serialize, Deserialize))]
pub struct Error {
#[cfg_attr(feature = "serialize-json", serde(rename = "Id"))]
id: u32,
#[cfg_attr(feature = "serialize-json", serde(rename = "ErrorCode"))]
#[getset(get_copy = "pub")]
error_code: ErrorCode,
#[cfg_attr(feature = "serialize-json", serde(rename = "ErrorMessage"))]
#[getset(get = "pub")]
error_message: String,
#[cfg_attr(feature = "serialize-json", serde(skip))]
original_error: Option<ButtplugError>,
}
impl PartialEq for Error {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
&& self.error_code == other.error_code
&& self.error_message == other.error_message
}
}
impl Error {
pub fn new(
error_code: ErrorCode,
error_message: &str,
original_error: Option<ButtplugError>,
) -> Self {
Self {
id: 0,
error_code,
error_message: error_message.to_string(),
original_error,
}
}
pub fn original_error(&self) -> ButtplugError {
if self.original_error.is_some() {
self
.original_error
.clone()
.expect("Already checked that it's valid.")
} else {
#[cfg(feature = "serialize-json")]
{
if let Ok(deserialized_msg) = serde_json::from_str(&self.error_message) {
return deserialized_msg;
}
}
ButtplugError::from(self.clone())
}
}
}
impl From<ButtplugError> for Error {
fn from(error: ButtplugError) -> Self {
let code = match error {
ButtplugError::ButtplugDeviceError { .. } => ErrorCode::ErrorDevice,
ButtplugError::ButtplugMessageError { .. } => ErrorCode::ErrorMessage,
ButtplugError::ButtplugPingError { .. } => ErrorCode::ErrorPing,
ButtplugError::ButtplugHandshakeError { .. } => ErrorCode::ErrorHandshake,
ButtplugError::ButtplugUnknownError { .. } => ErrorCode::ErrorUnknown,
};
#[cfg(feature = "serialize-json")]
let msg = serde_json::to_string(&error).expect("All buttplug errors are serializable");
#[cfg(not(feature = "serialize-json"))]
let msg = error.to_string();
Error::new(code, &msg, Some(error))
}
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
ButtplugMessage,
ButtplugMessageValidator,
ButtplugMessageFinalizer,
Getters,
CopyGetters,
)]
#[cfg_attr(feature = "serialize-json", derive(Serialize, Deserialize))]
pub struct ErrorV0 {
#[cfg_attr(feature = "serialize-json", serde(rename = "Id"))]
id: u32,
#[cfg_attr(feature = "serialize-json", serde(rename = "ErrorCode"))]
#[getset(get_copy = "pub")]
error_code: ErrorCode,
#[cfg_attr(feature = "serialize-json", serde(rename = "ErrorMessage"))]
#[getset(get = "pub")]
error_message: String,
}
impl ErrorV0 {
pub fn new(error_code: ErrorCode, error_message: &str) -> Self {
Self {
id: 0,
error_code,
error_message: error_message.to_string(),
}
}
}
impl From<Error> for ErrorV0 {
fn from(error: Error) -> Self {
let mut err = ErrorV0::new(error.error_code, &error.error_message);
err.set_id(error.id());
err
}
}
#[cfg(feature = "serialize-json")]
#[cfg(test)]
mod test {
use crate::core::message::{ButtplugCurrentSpecServerMessage, Error, ErrorCode};
const ERROR_STR: &str = "{\"Error\":{\"Id\":0,\"ErrorCode\":1,\"ErrorMessage\":\"Test Error\"}}";
#[test]
fn test_error_serialize() {
let error = ButtplugCurrentSpecServerMessage::Error(Error::new(
ErrorCode::ErrorHandshake,
"Test Error",
None,
));
let js = serde_json::to_string(&error).expect("Infallible serialization.");
assert_eq!(ERROR_STR, js);
}
#[test]
fn test_error_deserialize() {
let union: ButtplugCurrentSpecServerMessage =
serde_json::from_str(ERROR_STR).expect("Infallible deserialization");
assert_eq!(
ButtplugCurrentSpecServerMessage::Error(Error::new(
ErrorCode::ErrorHandshake,
"Test Error",
None
)),
union
);
}
}