blob: 7fa73026b737a2e7a5211ff43e1cf33cc6a4c591 [file] [log] [blame]
use crate::{return_variant, ErrorCode, ReturnVariant};
/// The response type from `command`. Can represent a successful value or a
/// failure.
#[derive(Clone, Copy)]
pub struct CommandReturn {
pub(crate) return_variant: ReturnVariant,
// r1, r2, and r3 should only contain 32-bit values. However, these are
// converted directly from usizes returned by RawSyscalls::four_arg_syscall.
// To avoid casting twice (both when converting to a Command Return and when
// calling a get_*() function), we store the usizes directly. Then using the
// CommandReturn only involves one conversion for each of r1, r2, and r3,
// performed in the get_*() functions.
pub(crate) r1: usize,
pub(crate) r2: usize,
pub(crate) r3: usize,
}
impl CommandReturn {
// I generally expect CommandReturn to be used with pattern matching, e.g.:
//
// let command_return = Syscalls::command(314, 1, 1, 2);
// if let Some((val1, val2)) = command_return.get_success_2_u32() {
// // ...
// } else if let Some(error_code) = command_return.get_failure() {
// // ...
// } else {
// // Incorrect return variant
// }
/// Returns true if this CommandReturn is of type Failure. Note that this
/// does not return true for other failure types, such as Failure with u32.
pub fn is_failure(&self) -> bool {
self.return_variant == return_variant::FAILURE
}
/// Returns true if this CommandReturn is of type Failure with u32.
pub fn is_failure_u32(&self) -> bool {
self.return_variant == return_variant::FAILURE_U32
}
/// Returns true if this CommandReturn is of type Failure with 2 u32.
pub fn is_failure_2_u32(&self) -> bool {
self.return_variant == return_variant::FAILURE_2_U32
}
/// Returns true if this CommandReturn is of type Failure with u64.
pub fn is_failure_u64(&self) -> bool {
self.return_variant == return_variant::FAILURE_U64
}
/// Returns true if this CommandReturn is of type Success. Note that this
/// does not return true for other success types, such as Success with u32.
pub fn is_success(&self) -> bool {
self.return_variant == return_variant::SUCCESS
}
/// Returns true if this CommandReturn is of type Success with u32.
pub fn is_success_u32(&self) -> bool {
self.return_variant == return_variant::SUCCESS_U32
}
/// Returns true if this CommandReturn is of type Success with 2 u32.
pub fn is_success_2_u32(&self) -> bool {
self.return_variant == return_variant::SUCCESS_2_U32
}
/// Returns true if this CommandReturn is of type Success with u64.
pub fn is_success_u64(&self) -> bool {
self.return_variant == return_variant::SUCCESS_U64
}
/// Returns true if this CommandReturn is of type Success with 3 u32.
pub fn is_success_3_u32(&self) -> bool {
self.return_variant == return_variant::SUCCESS_3_U32
}
/// Returns true if this CommandReturn is of type Success with u32 and u64.
pub fn is_success_u32_u64(&self) -> bool {
self.return_variant == return_variant::SUCCESS_U32_U64
}
/// Returns the error code if this CommandReturn is of type Failure.
pub fn get_failure(&self) -> Option<ErrorCode> {
if !self.is_failure() {
return None;
}
Some(self.r1.into())
}
/// Returns the error code and value if this CommandReturn is of type
/// Failure with u32.
pub fn get_failure_u32(&self) -> Option<(ErrorCode, u32)> {
if !self.is_failure_u32() {
return None;
}
Some((self.r1.into(), self.r2 as u32))
}
/// Returns the error code and return values if this CommandReturn is of
/// type Failure with 2 u32.
pub fn get_failure_2_u32(&self) -> Option<(ErrorCode, u32, u32)> {
if !self.is_failure_2_u32() {
return None;
}
Some((self.r1.into(), self.r2 as u32, self.r3 as u32))
}
/// Returns the error code and return value if this CommandReturn is of type
/// Failure with u64.
pub fn get_failure_u64(&self) -> Option<(ErrorCode, u64)> {
if !self.is_failure_u64() {
return None;
}
Some((self.r1.into(), self.r2 as u64 + ((self.r3 as u64) << 32)))
}
/// Returns the value if this CommandReturn is of type Success with u32.
pub fn get_success_u32(&self) -> Option<u32> {
if !self.is_success_u32() {
return None;
}
Some(self.r1 as u32)
}
/// Returns the values if this CommandReturn is of type Success with 2 u32.
pub fn get_success_2_u32(&self) -> Option<(u32, u32)> {
if !self.is_success_2_u32() {
return None;
}
Some((self.r1 as u32, self.r2 as u32))
}
/// Returns the value if this CommandReturn is of type Success with u64.
pub fn get_success_u64(&self) -> Option<u64> {
if !self.is_success_u64() {
return None;
}
Some(self.r1 as u64 + ((self.r2 as u64) << 32))
}
/// Returns the values if this CommandReturn is of type Success with 3 u32.
pub fn get_success_3_u32(&self) -> Option<(u32, u32, u32)> {
if !self.is_success_3_u32() {
return None;
}
Some((self.r1 as u32, self.r2 as u32, self.r3 as u32))
}
/// Returns the values if this CommandReturn is of type Success with u32 and
/// u64.
pub fn get_success_u32_u64(&self) -> Option<(u32, u64)> {
if !self.is_success_u32_u64() {
return None;
}
Some((self.r1 as u32, self.r2 as u64 + ((self.r3 as u64) << 32)))
}
/// Returns the return variant of this command.
pub fn return_variant(&self) -> ReturnVariant {
self.return_variant
}
}