1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
use thiserror::Error;

use super::ffi;

#[derive(Error, Debug)]
#[repr(u8)]
pub enum VcosError {
	#[error("Resource temporarily unavailable")]
	Again = ffi::VCOS_STATUS_T::VCOS_EAGAIN.0 as u8,
	#[error("No such file or directory")]
	NoEntry = ffi::VCOS_STATUS_T::VCOS_ENOENT.0 as u8,
	#[error("No space left on device")]
	NoSpace = ffi::VCOS_STATUS_T::VCOS_ENOSPC.0 as u8,
	#[error("Invalid argument")]
	Invalid = ffi::VCOS_STATUS_T::VCOS_EINVAL.0 as u8,
	#[error("Permission denied")]
	Access = ffi::VCOS_STATUS_T::VCOS_EACCESS.0 as u8,
	#[error("Cannot allocate memory")]
	NoMemory = ffi::VCOS_STATUS_T::VCOS_ENOMEM.0 as u8,
	#[error("Function not implemented")]
	NoSys = ffi::VCOS_STATUS_T::VCOS_ENOSYS.0 as u8,
	#[error("File exists")]
	Exist = ffi::VCOS_STATUS_T::VCOS_EEXIST.0 as u8,
	#[error("No such device or address")]
	NxIo = ffi::VCOS_STATUS_T::VCOS_ENXIO.0 as u8,
	#[error("Interrupted system call")]
	Interrupt = ffi::VCOS_STATUS_T::VCOS_EINTR.0 as u8
}

impl ffi::VCOS_STATUS_T {
	pub fn to_result(self) -> Result<(), VcosError> {
		let error = match self {
			ffi::VCOS_STATUS_T::VCOS_SUCCESS => return Ok(()),
			ffi::VCOS_STATUS_T::VCOS_EAGAIN => VcosError::Again,
			ffi::VCOS_STATUS_T::VCOS_ENOENT => VcosError::NoEntry,
			ffi::VCOS_STATUS_T::VCOS_ENOSPC => VcosError::NoSpace,
			ffi::VCOS_STATUS_T::VCOS_EINVAL => VcosError::Invalid,
			ffi::VCOS_STATUS_T::VCOS_EACCESS => VcosError::Access,
			ffi::VCOS_STATUS_T::VCOS_ENOMEM => VcosError::NoMemory,
			ffi::VCOS_STATUS_T::VCOS_ENOSYS => VcosError::NoSys,
			ffi::VCOS_STATUS_T::VCOS_EEXIST => VcosError::Exist,
			ffi::VCOS_STATUS_T::VCOS_ENXIO => VcosError::NxIo,
			ffi::VCOS_STATUS_T::VCOS_EINTR => VcosError::Interrupt,
			_ => unreachable!()
		};

		Err(error)
	}
}

#[derive(Error, Debug)]
pub enum GencmdInitError {
	#[error("Failed to initialize vcos: {0}")]
	VcosInit(VcosError),
	#[error("Failed to initialize vchi")]
	VchiInit,
	#[error("Failed to create vchi connection")]
	VchiConnect,
	#[error("Another instance is already initialized")]
	AlreadyInitialized
}

#[derive(Error, Debug)]
pub enum GencmdDeinitError {
	#[error("Failed to destroy vchi connection")]
	VchiDisconnect
}

#[derive(Error, Debug)]
pub enum GencmdCmdError {
	#[error(
		"Command is too long for this interface (max len {})",
		ffi::GENCMD_MAX_LENGTH
	)]
	CommandTooLong,
	#[error("Failed to send command")]
	Send,
	#[error("Failed to read response")]
	Read,
	#[error("The received response is not valid utf8: {0}")]
	Utf8(#[from] std::str::Utf8Error),
	#[error(transparent)]
	ErrorResponse(#[from] GencmdErrorResponse),
	#[error("Response has invalid format: {0}")]
	InvalidResponseFormat(Box<dyn std::error::Error + Send + Sync>)
}
impl GencmdCmdError {
	pub fn from_invalid_format(error: impl std::error::Error + Send + Sync + 'static) -> Self {
		GencmdCmdError::InvalidResponseFormat(Box::new(error))
	}
}

#[derive(Error, Debug)]
pub enum GencmdErrorResponse {
	#[error("Command not registered")]
	CommandNotRegistered,
	#[error("Invalid arguments")]
	InvalidArguments
}
impl GencmdErrorResponse {
	pub const fn code(&self) -> i32 {
		match self {
			GencmdErrorResponse::CommandNotRegistered => 1,
			GencmdErrorResponse::InvalidArguments => 2
		}
	}
}