// This file is generated by tools/opcode_metadata/generate_rs_opcode_metadata.py
// Do not edit!

use crate::{bytecode::instruction::StackEffect, marshal::MarshalError};

impl super::Opcode {
    /// Returns [`Self`] as [`u8`].
    #[must_use]
    #[inline]
    pub const fn as_u8(self) -> u8 {
        self.as_numeric()
    }

    #[must_use]
    #[inline]
    pub const fn cache_entries(self) -> usize {
        const CACHE_ENTRIES: [u8; 256] = [
            0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 1, 1,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 0, 0,
            0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 3,
            3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1,
            1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, 4, 4, 1, 1, 0, 1, 4, 4, 4, 1, 1,
            3, 3, 3, 3, 3, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 3, 3, 0, 1, 0, 0,
        ];

        CACHE_ENTRIES[self.as_numeric() as usize] as usize
    }

    #[must_use]
    #[inline]
    pub const fn deopt(self) -> Option<Self> {
        const DEOPT: [Option<super::Opcode>; 256] = [
            None,
            None,
            None,
            Some(super::Opcode::BinaryOp),
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::BinaryOp),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::CallKw),
            Some(super::Opcode::CallKw),
            Some(super::Opcode::CallKw),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::Call),
            Some(super::Opcode::CompareOp),
            Some(super::Opcode::CompareOp),
            Some(super::Opcode::CompareOp),
            Some(super::Opcode::ContainsOp),
            Some(super::Opcode::ContainsOp),
            Some(super::Opcode::ForIter),
            Some(super::Opcode::ForIter),
            Some(super::Opcode::ForIter),
            Some(super::Opcode::ForIter),
            Some(super::Opcode::JumpBackward),
            Some(super::Opcode::JumpBackward),
            Some(super::Opcode::LoadAttr),
            Some(super::Opcode::LoadAttr),
            Some(super::Opcode::LoadAttr),
            Some(super::Opcode::LoadAttr),
            Some(super::Opcode::LoadAttr),
            Some(super::Opcode::LoadAttr),
            Some(super::Opcode::LoadAttr),
            Some(super::Opcode::LoadAttr),
            Some(super::Opcode::LoadAttr),
            Some(super::Opcode::LoadAttr),
            Some(super::Opcode::LoadAttr),
            Some(super::Opcode::LoadAttr),
            Some(super::Opcode::LoadAttr),
            Some(super::Opcode::LoadConst),
            Some(super::Opcode::LoadConst),
            Some(super::Opcode::LoadGlobal),
            Some(super::Opcode::LoadGlobal),
            Some(super::Opcode::LoadSuperAttr),
            Some(super::Opcode::LoadSuperAttr),
            Some(super::Opcode::Resume),
            Some(super::Opcode::Send),
            Some(super::Opcode::StoreAttr),
            Some(super::Opcode::StoreAttr),
            Some(super::Opcode::StoreAttr),
            Some(super::Opcode::StoreSubscr),
            Some(super::Opcode::StoreSubscr),
            Some(super::Opcode::ToBool),
            Some(super::Opcode::ToBool),
            Some(super::Opcode::ToBool),
            Some(super::Opcode::ToBool),
            Some(super::Opcode::ToBool),
            Some(super::Opcode::ToBool),
            Some(super::Opcode::UnpackSequence),
            Some(super::Opcode::UnpackSequence),
            Some(super::Opcode::UnpackSequence),
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
            None,
        ];

        DEOPT[self.as_numeric() as usize]
    }

    /// Does this opcode have 'HAS_ARG_FLAG' set.
    #[must_use]
    pub const fn has_arg(self) -> bool {
        matches!(
            self,
            Self::BinaryOp
                | Self::BuildInterpolation
                | Self::BuildList
                | Self::BuildMap
                | Self::BuildSet
                | Self::BuildSlice
                | Self::BuildString
                | Self::BuildTuple
                | Self::Call
                | Self::CallIntrinsic1
                | Self::CallIntrinsic2
                | Self::CallKw
                | Self::CompareOp
                | Self::ContainsOp
                | Self::ConvertValue
                | Self::Copy
                | Self::CopyFreeVars
                | Self::DeleteAttr
                | Self::DeleteDeref
                | Self::DeleteFast
                | Self::DeleteGlobal
                | Self::DeleteName
                | Self::DictMerge
                | Self::DictUpdate
                | Self::EndAsyncFor
                | Self::ExtendedArg
                | Self::ForIter
                | Self::GetAwaitable
                | Self::ImportFrom
                | Self::ImportName
                | Self::IsOp
                | Self::JumpBackward
                | Self::JumpBackwardNoInterrupt
                | Self::JumpForward
                | Self::ListAppend
                | Self::ListExtend
                | Self::LoadAttr
                | Self::LoadCommonConstant
                | Self::LoadConst
                | Self::LoadDeref
                | Self::LoadFast
                | Self::LoadFastAndClear
                | Self::LoadFastBorrow
                | Self::LoadFastBorrowLoadFastBorrow
                | Self::LoadFastCheck
                | Self::LoadFastLoadFast
                | Self::LoadFromDictOrDeref
                | Self::LoadFromDictOrGlobals
                | Self::LoadGlobal
                | Self::LoadName
                | Self::LoadSmallInt
                | Self::LoadSpecial
                | Self::LoadSuperAttr
                | Self::MakeCell
                | Self::MapAdd
                | Self::MatchClass
                | Self::PopJumpIfFalse
                | Self::PopJumpIfNone
                | Self::PopJumpIfNotNone
                | Self::PopJumpIfTrue
                | Self::RaiseVarargs
                | Self::Reraise
                | Self::Send
                | Self::SetAdd
                | Self::SetFunctionAttribute
                | Self::SetUpdate
                | Self::StoreAttr
                | Self::StoreDeref
                | Self::StoreFast
                | Self::StoreFastLoadFast
                | Self::StoreFastStoreFast
                | Self::StoreGlobal
                | Self::StoreName
                | Self::Swap
                | Self::UnpackEx
                | Self::UnpackSequence
                | Self::YieldValue
                | Self::Resume
                | Self::CallAllocAndEnterInit
                | Self::CallBoundMethodExactArgs
                | Self::CallBoundMethodGeneral
                | Self::CallBuiltinClass
                | Self::CallBuiltinFast
                | Self::CallBuiltinFastWithKeywords
                | Self::CallBuiltinO
                | Self::CallIsinstance
                | Self::CallKwBoundMethod
                | Self::CallKwNonPy
                | Self::CallKwPy
                | Self::CallListAppend
                | Self::CallMethodDescriptorFast
                | Self::CallMethodDescriptorFastWithKeywords
                | Self::CallMethodDescriptorNoargs
                | Self::CallMethodDescriptorO
                | Self::CallNonPyGeneral
                | Self::CallPyExactArgs
                | Self::CallPyGeneral
                | Self::CallStr1
                | Self::CallTuple1
                | Self::CallType1
                | Self::CompareOpFloat
                | Self::CompareOpInt
                | Self::CompareOpStr
                | Self::ContainsOpDict
                | Self::ContainsOpSet
                | Self::ForIterGen
                | Self::ForIterList
                | Self::ForIterRange
                | Self::ForIterTuple
                | Self::JumpBackwardJit
                | Self::JumpBackwardNoJit
                | Self::LoadAttrClass
                | Self::LoadAttrClassWithMetaclassCheck
                | Self::LoadAttrGetattributeOverridden
                | Self::LoadAttrInstanceValue
                | Self::LoadAttrMethodLazyDict
                | Self::LoadAttrMethodNoDict
                | Self::LoadAttrMethodWithValues
                | Self::LoadAttrModule
                | Self::LoadAttrNondescriptorNoDict
                | Self::LoadAttrNondescriptorWithValues
                | Self::LoadAttrProperty
                | Self::LoadAttrSlot
                | Self::LoadAttrWithHint
                | Self::LoadConstImmortal
                | Self::LoadConstMortal
                | Self::LoadGlobalBuiltin
                | Self::LoadGlobalModule
                | Self::LoadSuperAttrAttr
                | Self::LoadSuperAttrMethod
                | Self::SendGen
                | Self::StoreAttrWithHint
                | Self::UnpackSequenceList
                | Self::UnpackSequenceTuple
                | Self::UnpackSequenceTwoTuple
                | Self::InstrumentedForIter
                | Self::InstrumentedJumpForward
                | Self::InstrumentedPopJumpIfTrue
                | Self::InstrumentedPopJumpIfFalse
                | Self::InstrumentedPopJumpIfNone
                | Self::InstrumentedPopJumpIfNotNone
                | Self::InstrumentedResume
                | Self::InstrumentedYieldValue
                | Self::InstrumentedEndAsyncFor
                | Self::InstrumentedLoadSuperAttr
                | Self::InstrumentedCall
                | Self::InstrumentedCallKw
                | Self::InstrumentedJumpBackward
                | Self::EnterExecutor
        )
    }

    /// Does this opcode have 'HAS_CONST_FLAG' set.
    #[must_use]
    pub const fn has_const(self) -> bool {
        matches!(
            self,
            Self::LoadConst | Self::LoadConstImmortal | Self::LoadConstMortal
        )
    }

    /// Does this opcode have 'HAS_EVAL_BREAK_FLAG' set.
    #[must_use]
    pub const fn has_eval_break(self) -> bool {
        matches!(
            self,
            Self::CallFunctionEx
                | Self::Call
                | Self::JumpBackward
                | Self::Resume
                | Self::CallBuiltinClass
                | Self::CallBuiltinFast
                | Self::CallBuiltinFastWithKeywords
                | Self::CallBuiltinO
                | Self::CallKwNonPy
                | Self::CallMethodDescriptorFast
                | Self::CallMethodDescriptorFastWithKeywords
                | Self::CallMethodDescriptorNoargs
                | Self::CallMethodDescriptorO
                | Self::CallNonPyGeneral
                | Self::CallStr1
                | Self::CallTuple1
                | Self::JumpBackwardJit
                | Self::JumpBackwardNoJit
                | Self::InstrumentedResume
                | Self::InstrumentedCall
                | Self::InstrumentedCallFunctionEx
                | Self::InstrumentedJumpBackward
        )
    }

    /// Does this opcode have 'HAS_FREE_FLAG' set.
    #[must_use]
    pub const fn has_free(self) -> bool {
        matches!(
            self,
            Self::DeleteDeref | Self::LoadFromDictOrDeref | Self::MakeCell | Self::StoreDeref
        )
    }

    /// Does this opcode have 'HAS_JUMP_FLAG' set.
    #[must_use]
    pub const fn has_jump(self) -> bool {
        matches!(
            self,
            Self::EndAsyncFor
                | Self::ForIter
                | Self::JumpBackward
                | Self::JumpBackwardNoInterrupt
                | Self::JumpForward
                | Self::PopJumpIfFalse
                | Self::PopJumpIfNone
                | Self::PopJumpIfNotNone
                | Self::PopJumpIfTrue
                | Self::Send
                | Self::ForIterList
                | Self::ForIterRange
                | Self::ForIterTuple
                | Self::JumpBackwardJit
                | Self::JumpBackwardNoJit
                | Self::InstrumentedForIter
                | Self::InstrumentedEndAsyncFor
        )
    }

    /// Does this opcode have 'HAS_LOCAL_FLAG' set.
    #[must_use]
    pub const fn has_local(self) -> bool {
        matches!(
            self,
            Self::BinaryOpInplaceAddUnicode
                | Self::DeleteFast
                | Self::LoadDeref
                | Self::LoadFast
                | Self::LoadFastAndClear
                | Self::LoadFastBorrow
                | Self::LoadFastBorrowLoadFastBorrow
                | Self::LoadFastCheck
                | Self::LoadFastLoadFast
                | Self::StoreFast
                | Self::StoreFastLoadFast
                | Self::StoreFastStoreFast
        )
    }

    /// Does this opcode have 'HAS_NAME_FLAG' set.
    #[must_use]
    pub const fn has_name(self) -> bool {
        matches!(
            self,
            Self::DeleteAttr
                | Self::DeleteGlobal
                | Self::DeleteName
                | Self::ImportFrom
                | Self::ImportName
                | Self::LoadAttr
                | Self::LoadFromDictOrGlobals
                | Self::LoadGlobal
                | Self::LoadName
                | Self::LoadSuperAttr
                | Self::StoreAttr
                | Self::StoreGlobal
                | Self::StoreName
                | Self::LoadAttrGetattributeOverridden
                | Self::LoadAttrWithHint
                | Self::LoadSuperAttrAttr
                | Self::LoadSuperAttrMethod
                | Self::StoreAttrWithHint
                | Self::InstrumentedLoadSuperAttr
        )
    }

    #[must_use]
    pub const fn is_instrumented(self) -> bool {
        matches!(
            self,
            Self::InstrumentedEndFor
                | Self::InstrumentedPopIter
                | Self::InstrumentedEndSend
                | Self::InstrumentedForIter
                | Self::InstrumentedInstruction
                | Self::InstrumentedJumpForward
                | Self::InstrumentedNotTaken
                | Self::InstrumentedPopJumpIfTrue
                | Self::InstrumentedPopJumpIfFalse
                | Self::InstrumentedPopJumpIfNone
                | Self::InstrumentedPopJumpIfNotNone
                | Self::InstrumentedResume
                | Self::InstrumentedReturnValue
                | Self::InstrumentedYieldValue
                | Self::InstrumentedEndAsyncFor
                | Self::InstrumentedLoadSuperAttr
                | Self::InstrumentedCall
                | Self::InstrumentedCallKw
                | Self::InstrumentedCallFunctionEx
                | Self::InstrumentedJumpBackward
                | Self::InstrumentedLine
        )
    }

    #[must_use]
    pub fn stack_effect_info(&self, oparg: u32) -> StackEffect {
        // Reason for converting oparg to i32 is because of expressions like `1 + (oparg -1)`
        // that causes underflow errors.
        let oparg = i32::try_from(oparg).expect("oparg does not fit in an `i32`");

        let (pushed, popped) = match self {
            Self::Cache => (0, 0),
            Self::BinarySlice => (1, 3),
            Self::BuildTemplate => (1, 2),
            Self::BinaryOpInplaceAddUnicode => (0, 2),
            Self::CallFunctionEx => (1, 4),
            Self::CheckEgMatch => (2, 2),
            Self::CheckExcMatch => (2, 2),
            Self::CleanupThrow => (2, 3),
            Self::DeleteSubscr => (0, 2),
            Self::EndFor => (0, 1),
            Self::EndSend => (1, 2),
            Self::ExitInitCheck => (0, 1),
            Self::FormatSimple => (1, 1),
            Self::FormatWithSpec => (1, 2),
            Self::GetAiter => (1, 1),
            Self::GetAnext => (2, 1),
            Self::GetIter => (1, 1),
            Self::Reserved => (0, 0),
            Self::GetLen => (2, 1),
            Self::GetYieldFromIter => (1, 1),
            Self::InterpreterExit => (0, 1),
            Self::LoadBuildClass => (1, 0),
            Self::LoadLocals => (1, 0),
            Self::MakeFunction => (1, 1),
            Self::MatchKeys => (3, 2),
            Self::MatchMapping => (2, 1),
            Self::MatchSequence => (2, 1),
            Self::Nop => (0, 0),
            Self::NotTaken => (0, 0),
            Self::PopExcept => (0, 1),
            Self::PopIter => (0, 1),
            Self::PopTop => (0, 1),
            Self::PushExcInfo => (2, 1),
            Self::PushNull => (1, 0),
            Self::ReturnGenerator => (1, 0),
            Self::ReturnValue => (1, 1),
            Self::SetupAnnotations => (0, 0),
            Self::StoreSlice => (0, 4),
            Self::StoreSubscr => (0, 3),
            Self::ToBool => (1, 1),
            Self::UnaryInvert => (1, 1),
            Self::UnaryNegative => (1, 1),
            Self::UnaryNot => (1, 1),
            Self::WithExceptStart => (6, 5),
            Self::BinaryOp => (1, 2),
            Self::BuildInterpolation => (1, 2 + (oparg & 1)),
            Self::BuildList => (1, oparg),
            Self::BuildMap => (1, oparg * 2),
            Self::BuildSet => (1, oparg),
            Self::BuildSlice => (1, oparg),
            Self::BuildString => (1, oparg),
            Self::BuildTuple => (1, oparg),
            Self::Call => (1, 2 + oparg),
            Self::CallIntrinsic1 => (1, 1),
            Self::CallIntrinsic2 => (1, 2),
            Self::CallKw => (1, 3 + oparg),
            Self::CompareOp => (1, 2),
            Self::ContainsOp => (1, 2),
            Self::ConvertValue => (1, 1),
            Self::Copy => (2 + (oparg - 1), 1 + (oparg - 1)),
            Self::CopyFreeVars => (0, 0),
            Self::DeleteAttr => (0, 1),
            Self::DeleteDeref => (0, 0),
            Self::DeleteFast => (0, 0),
            Self::DeleteGlobal => (0, 0),
            Self::DeleteName => (0, 0),
            Self::DictMerge => (4 + (oparg - 1), 5 + (oparg - 1)),
            Self::DictUpdate => (1 + (oparg - 1), 2 + (oparg - 1)),
            Self::EndAsyncFor => (0, 2),
            Self::ExtendedArg => (0, 0),
            Self::ForIter => (2, 1),
            Self::GetAwaitable => (1, 1),
            Self::ImportFrom => (2, 1),
            Self::ImportName => (1, 2),
            Self::IsOp => (1, 2),
            Self::JumpBackward => (0, 0),
            Self::JumpBackwardNoInterrupt => (0, 0),
            Self::JumpForward => (0, 0),
            Self::ListAppend => (1 + (oparg - 1), 2 + (oparg - 1)),
            Self::ListExtend => (1 + (oparg - 1), 2 + (oparg - 1)),
            Self::LoadAttr => (1 + (oparg & 1), 1),
            Self::LoadCommonConstant => (1, 0),
            Self::LoadConst => (1, 0),
            Self::LoadDeref => (1, 0),
            Self::LoadFast => (1, 0),
            Self::LoadFastAndClear => (1, 0),
            Self::LoadFastBorrow => (1, 0),
            Self::LoadFastBorrowLoadFastBorrow => (2, 0),
            Self::LoadFastCheck => (1, 0),
            Self::LoadFastLoadFast => (2, 0),
            Self::LoadFromDictOrDeref => (1, 1),
            Self::LoadFromDictOrGlobals => (1, 1),
            Self::LoadGlobal => (1 + (oparg & 1), 0),
            Self::LoadName => (1, 0),
            Self::LoadSmallInt => (1, 0),
            Self::LoadSpecial => (2, 1),
            Self::LoadSuperAttr => (1 + (oparg & 1), 3),
            Self::MakeCell => (0, 0),
            Self::MapAdd => (1 + (oparg - 1), 3 + (oparg - 1)),
            Self::MatchClass => (1, 3),
            Self::PopJumpIfFalse => (0, 1),
            Self::PopJumpIfNone => (0, 1),
            Self::PopJumpIfNotNone => (0, 1),
            Self::PopJumpIfTrue => (0, 1),
            Self::RaiseVarargs => (0, oparg),
            Self::Reraise => (oparg, 1 + oparg),
            Self::Send => (2, 2),
            Self::SetAdd => (1 + (oparg - 1), 2 + (oparg - 1)),
            Self::SetFunctionAttribute => (1, 2),
            Self::SetUpdate => (1 + (oparg - 1), 2 + (oparg - 1)),
            Self::StoreAttr => (0, 2),
            Self::StoreDeref => (0, 1),
            Self::StoreFast => (0, 1),
            Self::StoreFastLoadFast => (1, 1),
            Self::StoreFastStoreFast => (0, 2),
            Self::StoreGlobal => (0, 1),
            Self::StoreName => (0, 1),
            Self::Swap => (2 + (oparg - 2), 2 + (oparg - 2)),
            Self::UnpackEx => (1 + (oparg & 0xFF) + (oparg >> 8), 1),
            Self::UnpackSequence => (oparg, 1),
            Self::YieldValue => (1, 1),
            Self::Resume => (0, 0),
            Self::BinaryOpAddFloat => (1, 2),
            Self::BinaryOpAddInt => (1, 2),
            Self::BinaryOpAddUnicode => (1, 2),
            Self::BinaryOpExtend => (1, 2),
            Self::BinaryOpMultiplyFloat => (1, 2),
            Self::BinaryOpMultiplyInt => (1, 2),
            Self::BinaryOpSubscrDict => (1, 2),
            Self::BinaryOpSubscrGetitem => (0, 2),
            Self::BinaryOpSubscrListInt => (1, 2),
            Self::BinaryOpSubscrListSlice => (1, 2),
            Self::BinaryOpSubscrStrInt => (1, 2),
            Self::BinaryOpSubscrTupleInt => (1, 2),
            Self::BinaryOpSubtractFloat => (1, 2),
            Self::BinaryOpSubtractInt => (1, 2),
            Self::CallAllocAndEnterInit => (0, 2 + oparg),
            Self::CallBoundMethodExactArgs => (0, 2 + oparg),
            Self::CallBoundMethodGeneral => (0, 2 + oparg),
            Self::CallBuiltinClass => (1, 2 + oparg),
            Self::CallBuiltinFast => (1, 2 + oparg),
            Self::CallBuiltinFastWithKeywords => (1, 2 + oparg),
            Self::CallBuiltinO => (1, 2 + oparg),
            Self::CallIsinstance => (1, 2 + oparg),
            Self::CallKwBoundMethod => (0, 3 + oparg),
            Self::CallKwNonPy => (1, 3 + oparg),
            Self::CallKwPy => (0, 3 + oparg),
            Self::CallLen => (1, 3),
            Self::CallListAppend => (0, 3),
            Self::CallMethodDescriptorFast => (1, 2 + oparg),
            Self::CallMethodDescriptorFastWithKeywords => (1, 2 + oparg),
            Self::CallMethodDescriptorNoargs => (1, 2 + oparg),
            Self::CallMethodDescriptorO => (1, 2 + oparg),
            Self::CallNonPyGeneral => (1, 2 + oparg),
            Self::CallPyExactArgs => (0, 2 + oparg),
            Self::CallPyGeneral => (0, 2 + oparg),
            Self::CallStr1 => (1, 3),
            Self::CallTuple1 => (1, 3),
            Self::CallType1 => (1, 3),
            Self::CompareOpFloat => (1, 2),
            Self::CompareOpInt => (1, 2),
            Self::CompareOpStr => (1, 2),
            Self::ContainsOpDict => (1, 2),
            Self::ContainsOpSet => (1, 2),
            Self::ForIterGen => (1, 1),
            Self::ForIterList => (2, 1),
            Self::ForIterRange => (2, 1),
            Self::ForIterTuple => (2, 1),
            Self::JumpBackwardJit => (0, 0),
            Self::JumpBackwardNoJit => (0, 0),
            Self::LoadAttrClass => (1 + (oparg & 1), 1),
            Self::LoadAttrClassWithMetaclassCheck => (1 + (oparg & 1), 1),
            Self::LoadAttrGetattributeOverridden => (1, 1),
            Self::LoadAttrInstanceValue => (1 + (oparg & 1), 1),
            Self::LoadAttrMethodLazyDict => (2, 1),
            Self::LoadAttrMethodNoDict => (2, 1),
            Self::LoadAttrMethodWithValues => (2, 1),
            Self::LoadAttrModule => (1 + (oparg & 1), 1),
            Self::LoadAttrNondescriptorNoDict => (1, 1),
            Self::LoadAttrNondescriptorWithValues => (1, 1),
            Self::LoadAttrProperty => (0, 1),
            Self::LoadAttrSlot => (1 + (oparg & 1), 1),
            Self::LoadAttrWithHint => (1 + (oparg & 1), 1),
            Self::LoadConstImmortal => (1, 0),
            Self::LoadConstMortal => (1, 0),
            Self::LoadGlobalBuiltin => (1 + (oparg & 1), 0),
            Self::LoadGlobalModule => (1 + (oparg & 1), 0),
            Self::LoadSuperAttrAttr => (1, 3),
            Self::LoadSuperAttrMethod => (2, 3),
            Self::ResumeCheck => (0, 0),
            Self::SendGen => (1, 2),
            Self::StoreAttrInstanceValue => (0, 2),
            Self::StoreAttrSlot => (0, 2),
            Self::StoreAttrWithHint => (0, 2),
            Self::StoreSubscrDict => (0, 3),
            Self::StoreSubscrListInt => (0, 3),
            Self::ToBoolAlwaysTrue => (1, 1),
            Self::ToBoolBool => (1, 1),
            Self::ToBoolInt => (1, 1),
            Self::ToBoolList => (1, 1),
            Self::ToBoolNone => (1, 1),
            Self::ToBoolStr => (1, 1),
            Self::UnpackSequenceList => (oparg, 1),
            Self::UnpackSequenceTuple => (oparg, 1),
            Self::UnpackSequenceTwoTuple => (2, 1),
            Self::InstrumentedEndFor => (1, 2),
            Self::InstrumentedPopIter => (0, 1),
            Self::InstrumentedEndSend => (1, 2),
            Self::InstrumentedForIter => (2, 1),
            Self::InstrumentedInstruction => (0, 0),
            Self::InstrumentedJumpForward => (0, 0),
            Self::InstrumentedNotTaken => (0, 0),
            Self::InstrumentedPopJumpIfTrue => (0, 1),
            Self::InstrumentedPopJumpIfFalse => (0, 1),
            Self::InstrumentedPopJumpIfNone => (0, 1),
            Self::InstrumentedPopJumpIfNotNone => (0, 1),
            Self::InstrumentedResume => (0, 0),
            Self::InstrumentedReturnValue => (1, 1),
            Self::InstrumentedYieldValue => (1, 1),
            Self::InstrumentedEndAsyncFor => (0, 2),
            Self::InstrumentedLoadSuperAttr => (1 + (oparg & 1), 3),
            Self::InstrumentedCall => (1, 2 + oparg),
            Self::InstrumentedCallKw => (1, 3 + oparg),
            Self::InstrumentedCallFunctionEx => (1, 4),
            Self::InstrumentedJumpBackward => (0, 0),
            Self::InstrumentedLine => (0, 0),
            Self::EnterExecutor => (0, 0),
        };

        debug_assert!(u32::try_from(pushed).is_ok());
        debug_assert!(u32::try_from(popped).is_ok());

        StackEffect::new(pushed as u32, popped as u32)
    }

    #[must_use]
    #[inline]
    pub const fn to_base(self) -> Option<Self> {
        Some(match self {
            Self::InstrumentedCall => Self::Call,
            Self::InstrumentedCallFunctionEx => Self::CallFunctionEx,
            Self::InstrumentedCallKw => Self::CallKw,
            Self::InstrumentedEndAsyncFor => Self::EndAsyncFor,
            Self::InstrumentedEndFor => Self::EndFor,
            Self::InstrumentedEndSend => Self::EndSend,
            Self::InstrumentedForIter => Self::ForIter,
            Self::InstrumentedJumpBackward => Self::JumpBackward,
            Self::InstrumentedJumpForward => Self::JumpForward,
            Self::InstrumentedLoadSuperAttr => Self::LoadSuperAttr,
            Self::InstrumentedNotTaken => Self::NotTaken,
            Self::InstrumentedPopIter => Self::PopIter,
            Self::InstrumentedPopJumpIfFalse => Self::PopJumpIfFalse,
            Self::InstrumentedPopJumpIfNone => Self::PopJumpIfNone,
            Self::InstrumentedPopJumpIfNotNone => Self::PopJumpIfNotNone,
            Self::InstrumentedPopJumpIfTrue => Self::PopJumpIfTrue,
            Self::InstrumentedResume => Self::Resume,
            Self::InstrumentedReturnValue => Self::ReturnValue,
            Self::InstrumentedYieldValue => Self::YieldValue,
            _ => return None,
        })
    }

    #[must_use]
    pub const fn to_instrumented(self) -> Option<Self> {
        Some(match self {
            Self::Call => Self::InstrumentedCall,
            Self::CallFunctionEx => Self::InstrumentedCallFunctionEx,
            Self::CallKw => Self::InstrumentedCallKw,
            Self::EndAsyncFor => Self::InstrumentedEndAsyncFor,
            Self::EndFor => Self::InstrumentedEndFor,
            Self::EndSend => Self::InstrumentedEndSend,
            Self::ForIter => Self::InstrumentedForIter,
            Self::JumpBackward => Self::InstrumentedJumpBackward,
            Self::JumpForward => Self::InstrumentedJumpForward,
            Self::LoadSuperAttr => Self::InstrumentedLoadSuperAttr,
            Self::NotTaken => Self::InstrumentedNotTaken,
            Self::PopIter => Self::InstrumentedPopIter,
            Self::PopJumpIfFalse => Self::InstrumentedPopJumpIfFalse,
            Self::PopJumpIfNone => Self::InstrumentedPopJumpIfNone,
            Self::PopJumpIfNotNone => Self::InstrumentedPopJumpIfNotNone,
            Self::PopJumpIfTrue => Self::InstrumentedPopJumpIfTrue,
            Self::Resume => Self::InstrumentedResume,
            Self::ReturnValue => Self::InstrumentedReturnValue,
            Self::YieldValue => Self::InstrumentedYieldValue,
            _ => return None,
        })
    }

    pub const fn try_from_u8(value: u8) -> Result<Self, MarshalError> {
        Self::try_from_numeric(value)
    }
}

impl super::PseudoOpcode {
    /// Returns [`Self`] as [`u16`].
    #[must_use]
    #[inline]
    pub const fn as_u16(self) -> u16 {
        self.as_numeric()
    }

    #[must_use]
    #[inline]
    pub const fn cache_entries(self) -> usize {
        0
    }

    #[must_use]
    #[inline]
    pub const fn deopt(self) -> Option<Self> {
        None
    }

    /// Does this opcode have 'HAS_ARG_FLAG' set.
    #[must_use]
    pub const fn has_arg(self) -> bool {
        matches!(
            self,
            Self::Jump
                | Self::JumpIfFalse
                | Self::JumpIfTrue
                | Self::JumpNoInterrupt
                | Self::LoadClosure
                | Self::StoreFastMaybeNull
        )
    }

    /// Does this opcode have 'HAS_CONST_FLAG' set.
    #[must_use]
    pub const fn has_const(self) -> bool {
        false
    }

    /// Does this opcode have 'HAS_EVAL_BREAK_FLAG' set.
    #[must_use]
    pub const fn has_eval_break(self) -> bool {
        matches!(self, Self::Jump)
    }

    /// Does this opcode have 'HAS_FREE_FLAG' set.
    #[must_use]
    pub const fn has_free(self) -> bool {
        false
    }

    /// Does this opcode have 'HAS_JUMP_FLAG' set.
    #[must_use]
    pub const fn has_jump(self) -> bool {
        matches!(
            self,
            Self::Jump | Self::JumpIfFalse | Self::JumpIfTrue | Self::JumpNoInterrupt
        )
    }

    /// Does this opcode have 'HAS_LOCAL_FLAG' set.
    #[must_use]
    pub const fn has_local(self) -> bool {
        matches!(self, Self::LoadClosure | Self::StoreFastMaybeNull)
    }

    /// Does this opcode have 'HAS_NAME_FLAG' set.
    #[must_use]
    pub const fn has_name(self) -> bool {
        false
    }

    #[must_use]
    pub const fn is_instrumented(self) -> bool {
        false
    }

    #[must_use]
    pub fn stack_effect_info(&self, _oparg: u32) -> StackEffect {
        let (pushed, popped) = match self {
            Self::AnnotationsPlaceholder => (0, 0),
            Self::Jump => (0, 0),
            Self::JumpIfFalse => (1, 1),
            Self::JumpIfTrue => (1, 1),
            Self::JumpNoInterrupt => (0, 0),
            Self::LoadClosure => (1, 0),
            Self::PopBlock => (0, 0),
            Self::SetupCleanup => (2, 0),
            Self::SetupFinally => (1, 0),
            Self::SetupWith => (1, 0),
            Self::StoreFastMaybeNull => (0, 1),
        };

        debug_assert!(u32::try_from(pushed).is_ok());
        debug_assert!(u32::try_from(popped).is_ok());

        StackEffect::new(pushed as u32, popped as u32)
    }

    #[must_use]
    #[inline]
    pub const fn to_base(self) -> Option<Self> {
        None
    }

    #[must_use]
    pub const fn to_instrumented(self) -> Option<Self> {
        None
    }

    pub const fn try_from_u16(value: u16) -> Result<Self, MarshalError> {
        Self::try_from_numeric(value)
    }
}
