use std::{fmt, sync::PoisonError};
use num_enum::{FromPrimitive, IntoPrimitive};
use crate::raw;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Clone)]
pub struct Error {
kind: ErrorKind,
origin: Option<ErrorOrigin>,
}
#[derive(
Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, FromPrimitive, IntoPrimitive,
)]
#[repr(u32)]
pub enum ErrorKind {
Generic = raw::TEEC_ERROR_GENERIC,
AccessDenied = raw::TEEC_ERROR_ACCESS_DENIED,
Cancel = raw::TEEC_ERROR_CANCEL,
AccessConflict = raw::TEEC_ERROR_ACCESS_CONFLICT,
ExcessData = raw::TEEC_ERROR_EXCESS_DATA,
BadFormat = raw::TEEC_ERROR_BAD_FORMAT,
BadParameters = raw::TEEC_ERROR_BAD_PARAMETERS,
BadState = raw::TEEC_ERROR_BAD_STATE,
ItemNotFound = raw::TEEC_ERROR_ITEM_NOT_FOUND,
NotImplemented = raw::TEEC_ERROR_NOT_IMPLEMENTED,
NotSupported = raw::TEEC_ERROR_NOT_SUPPORTED,
NoData = raw::TEEC_ERROR_NO_DATA,
OutOfMemory = raw::TEEC_ERROR_OUT_OF_MEMORY,
Busy = raw::TEEC_ERROR_BUSY,
Communication = raw::TEEC_ERROR_COMMUNICATION,
Security = raw::TEEC_ERROR_SECURITY,
ShortBuffer = raw::TEEC_ERROR_SHORT_BUFFER,
ExternalCancel = raw::TEEC_ERROR_EXTERNAL_CANCEL,
TargetDead = raw::TEEC_ERROR_TARGET_DEAD,
#[default]
Unknown,
}
impl ErrorKind {
pub(crate) fn as_str(&self) -> &'static str {
match self {
ErrorKind::Generic => "Non-specific cause.",
ErrorKind::AccessDenied => "Access privileges are not sufficient.",
ErrorKind::Cancel => "The operation was canceled.",
ErrorKind::AccessConflict => "Concurrent accesses caused conflict.",
ErrorKind::ExcessData => "Too much data for the requested operation was passed.",
ErrorKind::BadFormat => "Input data was of invalid format.",
ErrorKind::BadParameters => "Input parameters were invalid.",
ErrorKind::BadState => "Operation is not valid in the current state.",
ErrorKind::ItemNotFound => "The requested data item is not found.",
ErrorKind::NotImplemented => {
"The requested operation should exist but is not yet implemented."
}
ErrorKind::NotSupported => {
"The requested operation is valid but is not supported in this implementation."
}
ErrorKind::NoData => "Expected data was missing.",
ErrorKind::OutOfMemory => "System ran out of resources.",
ErrorKind::Busy => "The system is busy working on something else.",
ErrorKind::Communication => "Communication with a remote party failed.",
ErrorKind::Security => "A security fault was detected.",
ErrorKind::ShortBuffer => "The supplied buffer is too short for the generated output.",
ErrorKind::ExternalCancel => "Undocumented.",
ErrorKind::TargetDead => "Trusted Application has panicked during the operation.",
ErrorKind::Unknown => "Unknown error.",
}
}
}
impl Error {
pub fn new(kind: ErrorKind) -> Error {
Error { kind, origin: None }
}
pub fn from_raw_error(code: u32) -> Error {
Error {
kind: ErrorKind::from(code),
origin: None,
}
}
pub fn with_origin(mut self, origin: ErrorOrigin) -> Self {
self.origin = Some(origin);
self
}
pub fn kind(&self) -> ErrorKind {
self.kind
}
pub fn origin(&self) -> Option<ErrorOrigin> {
self.origin
}
pub fn raw_code(&self) -> u32 {
self.kind.into()
}
pub fn message(&self) -> &str {
self.kind().as_str()
}
}
impl<T> From<PoisonError<T>> for Error {
fn from(_: PoisonError<T>) -> Self {
Error::new(ErrorKind::Generic).with_origin(ErrorOrigin::API)
}
}
impl fmt::Debug for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(
fmt,
"{} (错误代码 0x{:x}, 来源 0x{:x})",
self.message(),
self.raw_code(),
self.origin().map(|v| v.into()).unwrap_or(0_u32),
)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(self, f)
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
self.message()
}
}
impl From<ErrorKind> for Error {
#[inline]
fn from(kind: ErrorKind) -> Error {
Error { kind, origin: None }
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, IntoPrimitive)]
#[repr(u32)]
pub enum ErrorOrigin {
API = raw::TEEC_ORIGIN_API,
COMMS = raw::TEEC_ORIGIN_COMMS,
TEE = raw::TEEC_ORIGIN_TEE,
TA = raw::TEEC_ORIGIN_TRUSTED_APP,
#[default]
UNKNOWN,
}
#[cfg(test)]
mod teec_error_tests {
use super::*;
macro_rules! test_error_kind_messages {
($($variant:ident => $msg:expr),* $(,)?) => {
$(
assert_eq!(ErrorKind::$variant.as_str(), $msg);
)*
};
}
#[test]
fn test_error_types_and_methods() {
test_error_kind_messages! {
Generic => "Non-specific cause.",
AccessDenied => "Access privileges are not sufficient.",
Cancel => "The operation was canceled.",
AccessConflict => "Concurrent accesses caused conflict.",
ExcessData => "Too much data for the requested operation was passed.",
BadFormat => "Input data was of invalid format.",
BadParameters => "Input parameters were invalid.",
BadState => "Operation is not valid in the current state.",
ItemNotFound => "The requested data item is not found.",
NotImplemented => "The requested operation should exist but is not yet implemented.",
NotSupported => "The requested operation is valid but is not supported in this implementation.",
NoData => "Expected data was missing.",
OutOfMemory => "System ran out of resources.",
Busy => "The system is busy working on something else.",
Communication => "Communication with a remote party failed.",
Security => "A security fault was detected.",
ShortBuffer => "The supplied buffer is too short for the generated output.",
ExternalCancel => "Undocumented.",
TargetDead => "Trusted Application has panicked during the operation.",
Unknown => "Unknown error.",
}
let error = Error::new(ErrorKind::BadParameters);
assert_eq!(error.kind(), ErrorKind::BadParameters);
assert_eq!(error.origin(), None);
let raw_error = Error::from_raw_error(ErrorKind::Generic.into());
assert_eq!(raw_error.kind(), ErrorKind::Generic);
let error_with_origin = Error::new(ErrorKind::Generic).with_origin(ErrorOrigin::API);
assert_eq!(error_with_origin.origin(), Some(ErrorOrigin::API));
assert_eq!(error.raw_code(), u32::from(ErrorKind::BadParameters));
assert_eq!(error.message(), "Input parameters were invalid.");
let debug_str = format!("{:?}", error);
assert!(debug_str.contains("错误代码"));
let display_str = format!("{}", error);
assert!(display_str.contains("错误代码"));
let from_kind: Error = ErrorKind::OutOfMemory.into();
assert_eq!(from_kind.kind(), ErrorKind::OutOfMemory);
assert_eq!(u32::from(ErrorOrigin::API), raw::TEEC_ORIGIN_API);
assert_eq!(u32::from(ErrorOrigin::COMMS), raw::TEEC_ORIGIN_COMMS);
assert_eq!(u32::from(ErrorOrigin::TEE), raw::TEEC_ORIGIN_TEE);
assert_eq!(u32::from(ErrorOrigin::TA), raw::TEEC_ORIGIN_TRUSTED_APP);
}
#[test]
fn test_error_kind_all_variants_as_str() {
let error_kinds = vec![
ErrorKind::Generic,
ErrorKind::AccessDenied,
ErrorKind::Cancel,
ErrorKind::AccessConflict,
ErrorKind::ExcessData,
ErrorKind::BadFormat,
ErrorKind::BadParameters,
ErrorKind::BadState,
ErrorKind::ItemNotFound,
ErrorKind::NotImplemented,
ErrorKind::NotSupported,
ErrorKind::NoData,
ErrorKind::OutOfMemory,
ErrorKind::Busy,
ErrorKind::Communication,
ErrorKind::Security,
ErrorKind::ShortBuffer,
ErrorKind::ExternalCancel,
ErrorKind::TargetDead,
ErrorKind::Unknown,
];
for kind in error_kinds {
let error = Error::new(kind);
let _ = error.kind();
}
}
#[test]
fn test_error_origin_to_u32() {
assert_eq!(u32::from(ErrorOrigin::API), raw::TEEC_ORIGIN_API);
assert_eq!(u32::from(ErrorOrigin::COMMS), raw::TEEC_ORIGIN_COMMS);
assert_eq!(u32::from(ErrorOrigin::TEE), raw::TEEC_ORIGIN_TEE);
assert_eq!(u32::from(ErrorOrigin::TA), raw::TEEC_ORIGIN_TRUSTED_APP);
}
}