use super::message::{
self,
ButtplugMessageSpecVersion,
ErrorCode,
InputType,
OutputType,
serializer::ButtplugSerializerError,
};
use futures::future::BoxFuture;
use serde::{Deserialize, Serialize};
use thiserror::Error;
pub type ButtplugResult<T = ()> = Result<T, ButtplugError>;
macro_rules! impl_error_to_future {
($($error_type:ty),* $(,)?) => {
$(
impl<T> From<$error_type> for BoxFuture<'static, Result<T, ButtplugError>>
where
T: Send + 'static,
{
fn from(err: $error_type) -> BoxFuture<'static, Result<T, ButtplugError>> {
ButtplugError::from(err).into()
}
}
)*
};
}
impl_error_to_future!(
ButtplugHandshakeError,
ButtplugMessageError,
ButtplugPingError,
ButtplugDeviceError,
ButtplugUnknownError,
);
#[derive(Debug, Error, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ButtplugHandshakeError {
#[error("Expected either a ServerInfo or Error message, received {0}")]
UnexpectedHandshakeMessageReceived(String),
#[error("Expected a RequestServerInfo message to start connection. Message either not received or wrong message received.")]
RequestServerInfoExpected,
#[error("Handshake already happened, cannot run handshake again.")]
HandshakeAlreadyHappened,
#[error("Server has already connected and disconnected, cannot be reused")]
ReconnectDenied,
#[error("Server spec version ({0}) must be equal or greater than client version ({1})")]
MessageSpecVersionMismatch(ButtplugMessageSpecVersion, ButtplugMessageSpecVersion),
#[error("Untyped Deserialized Error: {0}")]
UntypedDeserializedError(String),
#[error("Unhandled spec version requested, may require extra arguments to activate: {0}")]
UnhandledMessageSpecVersionRequested(ButtplugMessageSpecVersion),
}
#[derive(Debug, Error, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ButtplugMessageError {
#[error("Got unexpected message type: {0}")]
UnexpectedMessageType(String),
#[error("{0} {1} cannot be converted to {2}")]
VersionError(String, String, String),
#[error("Message conversion error: {0}")]
MessageConversionError(String),
#[error("Invalid message contents: {0}")]
InvalidMessageContents(String),
#[error("Unhandled message type: {0}")]
UnhandledMessage(String),
#[error("Message validation error(s): {0}")]
ValidationError(String),
#[error(transparent)]
MessageSerializationError(#[from] ButtplugSerializerError),
#[error("Untyped Deserialized Error: {0}")]
UntypedDeserializedError(String),
}
#[derive(Debug, Error, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ButtplugPingError {
#[error("Pinged timer exhausted, system has shut down.")]
PingedOut,
#[error("Ping timer not running.")]
PingTimerNotRunning,
#[error("Ping time must be greater than 0.")]
InvalidPingTimeout,
#[error("Untyped Deserialized Error: {0}")]
UntypedDeserializedError(String),
}
#[derive(Debug, Error, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ButtplugDeviceError {
#[error("Device {0} not connected")]
DeviceNotConnected(String),
#[error("Device does not support message type {0}.")]
MessageNotSupported(String),
#[error("Device only has {0} features, but {1} commands were sent.")]
DeviceFeatureCountMismatch(u32, u32),
#[error("Device only has {0} features, but was given an index of {1}")]
DeviceFeatureIndexError(u32, u32),
#[error("Device feature mismatch: {0}")]
DeviceFeatureMismatch(String),
#[error("Device only has {0} sensors, but was given an index of {1}")]
DeviceSensorIndexError(u32, u32),
#[error("Device connection error: {0}")]
DeviceConnectionError(String),
#[error("Device communication error: {0}")]
DeviceCommunicationError(String),
#[error("Device feature only has {0} steps for control, but {1} steps specified.")]
DeviceStepRangeError(i32, i32),
#[error("Device got {0} output command but has no viable outputs")]
DeviceNoOutputError(OutputType),
#[error("Device got {0} input command but has no viable inputs")]
DeviceNoInputError(InputType),
#[error("Device does not have endpoint {0}")]
InvalidEndpoint(String),
#[error("Device does not handle command type: {0}")]
UnhandledCommand(String),
#[error("Device type specific error: {0}")]
DeviceSpecificError(String),
#[error("No device available at index {0}")]
DeviceNotAvailable(u32),
#[error("Device scanning already started.")]
DeviceScanningAlreadyStarted,
#[error("Device scanning already stopped.")]
DeviceScanningAlreadyStopped,
#[error("Device permission error: {0}")]
DevicePermissionError(String),
#[error("Device command does not take negative numbers")]
DeviceCommandSignError,
#[error("{0}")]
ProtocolAttributesNotFound(String),
#[error("Protocol {0} not implemented in library")]
ProtocolNotImplemented(String),
#[error("{0} protocol specific error: {1}")]
ProtocolSpecificError(String, String),
#[error("{0}")]
ProtocolRequirementError(String),
#[error("Protocol already added to system {0}")]
ProtocolAlreadyAdded(String),
#[error("Untyped Deserialized Error: {0}")]
UntypedDeserializedError(String),
#[error("Device Configuration Error: {0}")]
DeviceConfigurationError(String),
#[error("Output Type Mismatch: Index {0} got command for {1}, which is not valid")]
DeviceOutputTypeMismatch(u32, OutputType, OutputType),
#[error("Input Type Mismatch: Index {0} got command for {1}, which is not valid")]
DeviceInputTypeMismatch(u32, InputType),
#[error("Protocol does not have an implementation available for Sensor Type {0}")]
ProtocolInputNotSupported(InputType),
#[error("Device does not support {0}")]
OutputNotSupported(OutputType),
}
#[derive(Debug, Error, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ButtplugUnknownError {
#[error("Cannot start scanning, no device communication managers available to use for scanning.")]
NoDeviceCommManagers,
#[error("Got unexpected enum type: {0}")]
UnexpectedType(String),
#[error("Untyped Deserialized Error: {0}")]
UntypedDeserializedError(String),
#[error("Device Manager has been shut down by its owning server and is no longer available.")]
DeviceManagerNotRunning,
}
#[derive(Debug, Error, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ButtplugError {
#[error(transparent)]
ButtplugHandshakeError(#[from] ButtplugHandshakeError),
#[error(transparent)]
ButtplugMessageError(#[from] ButtplugMessageError),
#[error(transparent)]
ButtplugPingError(#[from] ButtplugPingError),
#[error(transparent)]
ButtplugDeviceError(#[from] ButtplugDeviceError),
#[error(transparent)]
ButtplugUnknownError(#[from] ButtplugUnknownError),
}
impl From<message::ErrorV0> for ButtplugError {
fn from(error: message::ErrorV0) -> Self {
match error.error_code() {
ErrorCode::ErrorDevice => {
ButtplugDeviceError::UntypedDeserializedError(error.error_message().clone()).into()
}
ErrorCode::ErrorMessage => {
ButtplugMessageError::UntypedDeserializedError(error.error_message().clone()).into()
}
ErrorCode::ErrorHandshake => {
ButtplugHandshakeError::UntypedDeserializedError(error.error_message().clone()).into()
}
ErrorCode::ErrorUnknown => {
ButtplugUnknownError::UntypedDeserializedError(error.error_message().clone()).into()
}
ErrorCode::ErrorPing => {
ButtplugPingError::UntypedDeserializedError(error.error_message().clone()).into()
}
}
}
}