use core::fmt;
use core::iter::FusedIterator;
use crate::display_flags::InstructionDisplayFlags;
use crate::encoded_field_mask::EncodedFieldMask;
use crate::instr::Instruction;
use crate::operands::{Operand, OperandDescriptor, OperandDisplay, ValuedOperand, OPERANDS};
use crate::utils;
pub(crate) const OPERAND_COUNT: usize = {
let mut count = 1;
count += 26;
if cfg!(feature = "MIPS_II") {
count += 0;
}
if cfg!(feature = "MIPS_III") {
count += 0;
}
if cfg!(feature = "MIPS_IV") {
count += 0;
}
if cfg!(feature = "RSP") {
count += 13;
}
if cfg!(feature = "R3000GTE") {
count += 6;
}
if cfg!(feature = "R4000ALLEGREX") {
count += 56;
}
if cfg!(feature = "R5900EE") {
count += 26;
}
if cfg!(feature = "RspViceMsp") {
count += 0;
}
count
};
pub const OPERAND_COUNT_MAX: usize = {
5
};
impl Operand {
#[must_use]
pub fn get_descriptor(&self) -> &'static OperandDescriptor {
&OPERANDS[*self]
}
#[must_use]
pub fn name(&self) -> &'static str {
self.get_descriptor().name()
}
#[must_use]
pub fn mask(&self) -> EncodedFieldMask {
self.get_descriptor().mask()
}
}
impl Operand {
pub const fn display<'ins, 'flg, T>(
&self,
instr: &'ins Instruction,
display_flags: &'flg InstructionDisplayFlags,
imm_override: Option<T>,
) -> OperandDisplay<'ins, 'flg, T>
where
T: fmt::Display,
{
OperandDisplay::new(*self, instr, display_flags, imm_override)
}
}
impl Operand {
#[must_use]
pub(crate) fn to_valued_operand(self, instr: &Instruction) -> ValuedOperand {
ValuedOperand::from_operand(self, instr)
}
}
impl Operand {
#[must_use]
pub const fn default() -> Self {
Self::ALL_EMPTY
}
#[must_use]
pub(crate) const fn arr0() -> [Self; OPERAND_COUNT_MAX] {
[Self::default(); OPERAND_COUNT_MAX]
}
#[must_use]
pub(crate) const fn arr1(op0: Self) -> [Self; OPERAND_COUNT_MAX] {
let mut arr = [Self::default(); OPERAND_COUNT_MAX];
arr[0] = op0;
arr
}
#[must_use]
pub(crate) const fn arr2(op0: Self, op1: Self) -> [Self; OPERAND_COUNT_MAX] {
let mut arr = [Self::default(); OPERAND_COUNT_MAX];
arr[0] = op0;
arr[1] = op1;
arr
}
#[must_use]
pub(crate) const fn arr3(op0: Self, op1: Self, op2: Self) -> [Self; OPERAND_COUNT_MAX] {
let mut arr = [Self::default(); OPERAND_COUNT_MAX];
arr[0] = op0;
arr[1] = op1;
arr[2] = op2;
arr
}
#[must_use]
#[cfg(feature = "R4000ALLEGREX")]
pub(crate) const fn arr4(
op0: Self,
op1: Self,
op2: Self,
op3: Self,
) -> [Self; OPERAND_COUNT_MAX] {
let mut arr = [Self::default(); OPERAND_COUNT_MAX];
arr[0] = op0;
arr[1] = op1;
arr[2] = op2;
arr[3] = op3;
arr
}
#[must_use]
#[cfg(feature = "R3000GTE")]
pub(crate) const fn arr5(
op0: Self,
op1: Self,
op2: Self,
op3: Self,
op4: Self,
) -> [Self; OPERAND_COUNT_MAX] {
let mut arr = [Self::default(); OPERAND_COUNT_MAX];
arr[0] = op0;
arr[1] = op1;
arr[2] = op2;
arr[3] = op3;
arr[4] = op4;
arr
}
}
impl Default for Operand {
fn default() -> Self {
Self::default()
}
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct OperandIterator<'ins> {
operands: &'ins [Operand; OPERAND_COUNT_MAX],
index: usize,
end: usize,
}
impl<'ins> OperandIterator<'ins> {
pub(crate) fn new(operands: &'ins [Operand; OPERAND_COUNT_MAX]) -> Self {
let end = utils::array_len_non_default(operands);
Self {
operands,
index: 0,
end,
}
}
}
impl Iterator for OperandIterator<'_> {
type Item = Operand;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.end {
return None;
}
let val = self.operands[self.index];
if val == Operand::default() {
return None;
}
self.index = self.index.saturating_add(1);
Some(val)
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.index = self.index.saturating_add(n);
self.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.end - self.index;
(remaining, Some(remaining))
}
fn count(mut self) -> usize {
let count = self.size_hint().0;
self.index = self.end;
count
}
fn last(mut self) -> Option<Self::Item> {
self.next_back()
}
}
impl DoubleEndedIterator for OperandIterator<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.index >= self.end {
return None;
}
self.end = self.end.saturating_sub(1);
let val = self.operands[self.end];
if val == Operand::default() {
return None;
}
Some(val)
}
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
self.end = self.end.saturating_sub(n);
self.next_back()
}
}
impl ExactSizeIterator for OperandIterator<'_> {}
impl FusedIterator for OperandIterator<'_> {}
#[cfg(test)]
mod tests {
use crate::opcodes::Opcode;
use super::*;
#[test]
fn test_operand_iter_addiu() {
let mut operands = Opcode::core_addiu.get_descriptor().operands_iter();
assert_eq!(operands.size_hint(), (3, Some(3)));
assert_eq!(operands.next(), Some(Operand::core_rt));
assert_eq!(operands.next(), Some(Operand::core_rs));
assert_eq!(operands.next(), Some(Operand::core_imm_i16));
assert_eq!(operands.next(), None);
assert_eq!(operands.size_hint(), (0, Some(0)));
}
#[test]
fn test_operand_iter_addiu_rev() {
let mut operands = Opcode::core_addiu.get_descriptor().operands_iter().rev();
assert_eq!(operands.size_hint(), (3, Some(3)));
assert_eq!(operands.next(), Some(Operand::core_imm_i16));
assert_eq!(operands.next(), Some(Operand::core_rs));
assert_eq!(operands.next(), Some(Operand::core_rt));
assert_eq!(operands.next(), None);
assert_eq!(operands.size_hint(), (0, Some(0)));
}
#[test]
fn test_operand_iter_addiu_forward_back() {
let mut operands = Opcode::core_addiu.get_descriptor().operands_iter();
assert_eq!(operands.size_hint(), (3, Some(3)));
assert_eq!(operands.next(), Some(Operand::core_rt));
assert_eq!(operands.size_hint(), (2, Some(2)));
assert_eq!(operands.next_back(), Some(Operand::core_imm_i16));
assert_eq!(operands.size_hint(), (1, Some(1)));
assert_eq!(operands.next(), Some(Operand::core_rs));
assert_eq!(operands.size_hint(), (0, Some(0)));
assert_eq!(operands.next(), None);
assert_eq!(operands.size_hint(), (0, Some(0)));
}
}