use std::{error, fmt, result};
use bindings::{
THEMIS_BUFFER_TOO_SMALL, THEMIS_DATA_CORRUPT, THEMIS_FAIL, THEMIS_INVALID_PARAMETER,
THEMIS_INVALID_SIGNATURE, THEMIS_NOT_SUPPORTED, THEMIS_NO_MEMORY, THEMIS_SCOMPARE_MATCH,
THEMIS_SCOMPARE_NOT_READY, THEMIS_SCOMPARE_NO_MATCH, THEMIS_SCOMPARE_SEND_OUTPUT_TO_PEER,
THEMIS_SSESSION_GET_PUB_FOR_ID_CALLBACK_ERROR, THEMIS_SSESSION_KA_NOT_FINISHED,
THEMIS_SSESSION_SEND_OUTPUT_TO_PEER, THEMIS_SSESSION_TRANSPORT_ERROR, THEMIS_SUCCESS,
};
use crate::secure_session::TransportError;
pub(crate) use bindings::themis_status_t;
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug, Eq, PartialEq)]
pub struct Error {
kind: ErrorKind,
}
impl Error {
pub(crate) fn with_kind(kind: ErrorKind) -> Error {
Error { kind }
}
pub(crate) fn from_themis_status(status: themis_status_t) -> Error {
let kind = match status as u32 {
THEMIS_SUCCESS => ErrorKind::Success,
THEMIS_FAIL => ErrorKind::Fail,
THEMIS_INVALID_PARAMETER => ErrorKind::InvalidParameter,
THEMIS_NO_MEMORY => ErrorKind::NoMemory,
THEMIS_BUFFER_TOO_SMALL => ErrorKind::BufferTooSmall,
THEMIS_DATA_CORRUPT => ErrorKind::DataCorrupt,
THEMIS_INVALID_SIGNATURE => ErrorKind::InvalidSignature,
THEMIS_NOT_SUPPORTED => ErrorKind::NotSupported,
_ => ErrorKind::UnknownError(status),
};
Error { kind }
}
pub(crate) fn from_session_status(status: themis_status_t) -> Error {
let kind = match status as u32 {
THEMIS_SSESSION_SEND_OUTPUT_TO_PEER => ErrorKind::SessionSendOutputToPeer,
THEMIS_SSESSION_KA_NOT_FINISHED => ErrorKind::SessionKeyAgreementNotFinished,
THEMIS_SSESSION_TRANSPORT_ERROR => {
ErrorKind::SessionTransportError(TransportError::unspecified())
}
THEMIS_SSESSION_GET_PUB_FOR_ID_CALLBACK_ERROR => {
ErrorKind::SessionGetPublicKeyForIdError
}
_ => return Error::from_themis_status(status),
};
Error { kind }
}
pub(crate) fn from_transport_error(error: TransportError) -> Error {
let kind = ErrorKind::SessionTransportError(error);
Error { kind }
}
pub(crate) fn from_compare_status(status: themis_status_t) -> Error {
let kind = match status as u32 {
THEMIS_SCOMPARE_SEND_OUTPUT_TO_PEER => ErrorKind::CompareSendOutputToPeer,
_ => return Error::from_themis_status(status),
};
Error { kind }
}
pub(crate) fn from_match_status(status: themis_status_t) -> Error {
let kind = match status as u32 {
THEMIS_SCOMPARE_NOT_READY => ErrorKind::CompareNotReady,
THEMIS_SCOMPARE_MATCH => ErrorKind::CompareMatch,
THEMIS_SCOMPARE_NO_MATCH => ErrorKind::CompareNoMatch,
_ => return Error::from_themis_status(status),
};
Error { kind }
}
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
}
impl error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.kind {
ErrorKind::UnknownError(status) => write!(f, "unknown error: {}", status),
ErrorKind::Success => write!(f, "success"),
ErrorKind::Fail => write!(f, "failure"),
ErrorKind::InvalidParameter => write!(f, "invalid parameter"),
ErrorKind::NoMemory => write!(f, "out of memory"),
ErrorKind::BufferTooSmall => write!(f, "buffer too small"),
ErrorKind::DataCorrupt => write!(f, "corrupted data"),
ErrorKind::InvalidSignature => write!(f, "invalid signature"),
ErrorKind::NotSupported => write!(f, "operation not supported"),
ErrorKind::SessionSendOutputToPeer => write!(f, "send key agreement data to peer"),
ErrorKind::SessionKeyAgreementNotFinished => write!(f, "key agreement not finished"),
ErrorKind::SessionTransportError(ref details) => {
write!(f, "transport layer error: {}", details)
}
ErrorKind::SessionGetPublicKeyForIdError => {
write!(f, "failed to get public key for ID")
}
ErrorKind::CompareSendOutputToPeer => write!(f, "send comparison data to peer"),
ErrorKind::CompareMatch => write!(f, "data matches"),
ErrorKind::CompareNoMatch => write!(f, "data does not match"),
ErrorKind::CompareNotReady => write!(f, "comparator not ready"),
}
}
}
#[derive(Debug)]
pub enum ErrorKind {
#[doc(hidden)]
UnknownError(i32),
#[doc(hidden)]
Success,
Fail,
InvalidParameter,
NoMemory,
BufferTooSmall,
DataCorrupt,
InvalidSignature,
NotSupported,
#[doc(hidden)]
SessionSendOutputToPeer,
SessionKeyAgreementNotFinished,
SessionTransportError(TransportError),
SessionGetPublicKeyForIdError,
#[doc(hidden)]
CompareSendOutputToPeer,
#[doc(hidden)]
CompareMatch,
#[doc(hidden)]
CompareNoMatch,
CompareNotReady,
}
impl Eq for ErrorKind {}
impl PartialEq for ErrorKind {
fn eq(&self, other: &ErrorKind) -> bool {
error_kinds_equal(self, other)
}
}
impl PartialEq<&ErrorKind> for ErrorKind {
fn eq(&self, other: &&ErrorKind) -> bool {
error_kinds_equal(self, other)
}
}
impl PartialEq<ErrorKind> for &ErrorKind {
fn eq(&self, other: &ErrorKind) -> bool {
error_kinds_equal(self, other)
}
}
fn error_kinds_equal(lhs: &ErrorKind, rhs: &ErrorKind) -> bool {
match (lhs, rhs) {
(ErrorKind::UnknownError(lhs), ErrorKind::UnknownError(rhs)) => (lhs == rhs),
(ErrorKind::Success, ErrorKind::Success) => true,
(ErrorKind::Fail, ErrorKind::Fail) => true,
(ErrorKind::InvalidParameter, ErrorKind::InvalidParameter) => true,
(ErrorKind::NoMemory, ErrorKind::NoMemory) => true,
(ErrorKind::BufferTooSmall, ErrorKind::BufferTooSmall) => true,
(ErrorKind::DataCorrupt, ErrorKind::DataCorrupt) => true,
(ErrorKind::InvalidSignature, ErrorKind::InvalidSignature) => true,
(ErrorKind::NotSupported, ErrorKind::NotSupported) => true,
(ErrorKind::SessionSendOutputToPeer, ErrorKind::SessionSendOutputToPeer) => true,
(ErrorKind::SessionKeyAgreementNotFinished, ErrorKind::SessionKeyAgreementNotFinished) => {
true
}
(ErrorKind::SessionTransportError(_), ErrorKind::SessionTransportError(_)) => true,
(ErrorKind::SessionGetPublicKeyForIdError, ErrorKind::SessionGetPublicKeyForIdError) => {
true
}
(ErrorKind::CompareSendOutputToPeer, ErrorKind::CompareSendOutputToPeer) => true,
(ErrorKind::CompareMatch, ErrorKind::CompareMatch) => true,
(ErrorKind::CompareNoMatch, ErrorKind::CompareNoMatch) => true,
(ErrorKind::CompareNotReady, ErrorKind::CompareNotReady) => true,
_ => false,
}
}