Use num_enum crate for oparg types (#6980)

* Use `num_enum` crate for oparg types

* Fix doctest

* Make opargs `#[repr(u8)]`

* BuildSliceArgCount optimized
This commit is contained in:
Shahar Naveh authored and GitHub committed 2026-02-06 09:00:38 +09:00
1 parent 19db8d0b9f
commit 956f471013
4 files changed
+336 -336

No files matched your search

Generated
+1
View File
@@ -3161,6 +3161,7 @@ dependencies = [
"lz4_flex",
"malachite-bigint",
"num-complex",
"num_enum",
"ruff_source_file",
"rustpython-wtf8",
]
+1
View File
@@ -17,6 +17,7 @@ bitflags = { workspace = true }
itertools = { workspace = true }
malachite-bigint = { workspace = true }
num-complex = { workspace = true }
num_enum = { workspace = true }
lz4_flex = "0.12"
@@ -1249,7 +1249,7 @@ impl<T: OpArgType> Arg<T> {
#[inline]
pub fn new(arg: T) -> (Self, OpArg) {
(Self(PhantomData), OpArg(arg.to_op_arg()))
(Self(PhantomData), OpArg(arg.into()))
}
#[inline]
@@ -1267,7 +1267,7 @@ impl<T: OpArgType> Arg<T> {
#[inline(always)]
pub fn try_get(self, arg: OpArg) -> Result<T, MarshalError> {
T::from_op_arg(arg.0)
T::try_from(arg.0).map_err(|_| MarshalError::InvalidBytecode)
}
/// # Safety
@@ -1275,7 +1275,7 @@ impl<T: OpArgType> Arg<T> {
#[inline(always)]
pub unsafe fn get_unchecked(self, arg: OpArg) -> T {
// SAFETY: requirements forwarded from caller
unsafe { T::from_op_arg(arg.0).unwrap_unchecked() }
unsafe { T::try_from(arg.0).unwrap_unchecked() }
}
}
+331 -333
View File
@@ -1,17 +1,14 @@
use bitflags::bitflags;
use num_enum::{IntoPrimitive, TryFromPrimitive};
use core::{fmt, num::NonZeroU8};
use core::fmt;
use crate::{
bytecode::{CodeUnit, instruction::Instruction},
marshal::MarshalError,
};
pub trait OpArgType: Copy {
fn from_op_arg(x: u32) -> Result<Self, MarshalError>;
fn to_op_arg(self) -> u32;
}
pub trait OpArgType: Copy + Into<u32> + TryFrom<u32> {}
/// Opcode argument that may be extended by a prior ExtendedArg.
#[derive(Copy, Clone, PartialEq, Eq)]
@@ -107,13 +104,34 @@ impl OpArgState {
}
}
macro_rules! impl_oparg_enum_traits {
($name:ty) => {
impl From<$name> for u32 {
fn from(value: $name) -> Self {
Self::from(u8::from(value))
}
}
impl TryFrom<u32> for $name {
type Error = $crate::marshal::MarshalError;
fn try_from(value: u32) -> Result<Self, Self::Error> {
u8::try_from(value)
.map_err(|_| Self::Error::InvalidBytecode)
.map(TryInto::try_into)?
}
}
};
}
/// Oparg values for [`Instruction::ConvertValue`].
///
/// ## See also
///
/// - [CPython FVC_* flags](https://github.com/python/cpython/blob/8183fa5e3f78ca6ab862de7fb8b14f3d929421e0/Include/ceval.h#L129-L132)
#[repr(u8)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, Eq, Hash, IntoPrimitive, PartialEq, TryFromPrimitive)]
#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))]
pub enum ConvertValueOparg {
/// No conversion.
///
@@ -121,6 +139,8 @@ pub enum ConvertValueOparg {
/// f"{x}"
/// f"{x:4}"
/// ```
// Ruff `ConversionFlag::None` is `-1i8`, when its converted to `u8` its value is `u8::MAX`.
#[num_enum(alternatives = [255])]
None = 0,
/// Converts by calling `str(<value>)`.
///
@@ -145,6 +165,8 @@ pub enum ConvertValueOparg {
Ascii = 3,
}
impl_oparg_enum_traits!(ConvertValueOparg);
impl fmt::Display for ConvertValueOparg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let out = match self {
@@ -159,29 +181,12 @@ impl fmt::Display for ConvertValueOparg {
}
}
impl OpArgType for ConvertValueOparg {
#[inline]
fn from_op_arg(x: u32) -> Result<Self, MarshalError> {
Ok(match x {
// Ruff `ConversionFlag::None` is `-1i8`,
// when its converted to `u8` its value is `u8::MAX`
0 | 255 => Self::None,
1 => Self::Str,
2 => Self::Repr,
3 => Self::Ascii,
_ => return Err(MarshalError::InvalidBytecode),
})
}
#[inline]
fn to_op_arg(self) -> u32 {
self as u32
}
}
impl OpArgType for ConvertValueOparg {}
/// Resume type for the RESUME instruction
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
#[repr(u32)]
#[repr(u8)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, IntoPrimitive, TryFromPrimitive)]
#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))]
pub enum ResumeType {
AtFuncStart = 0,
AfterYield = 1,
@@ -189,145 +194,108 @@ pub enum ResumeType {
AfterAwait = 3,
}
impl OpArgType for u32 {
#[inline(always)]
fn from_op_arg(x: u32) -> Result<Self, MarshalError> {
Ok(x)
}
#[inline(always)]
fn to_op_arg(self) -> u32 {
self
}
}
impl OpArgType for bool {
#[inline(always)]
fn from_op_arg(x: u32) -> Result<Self, MarshalError> {
Ok(x != 0)
}
#[inline(always)]
fn to_op_arg(self) -> u32 {
self as u32
}
}
macro_rules! op_arg_enum_impl {
(enum $name:ident { $($(#[$var_attr:meta])* $var:ident = $value:literal,)* }) => {
impl OpArgType for $name {
fn to_op_arg(self) -> u32 {
self as u32
}
fn from_op_arg(x: u32) -> Result<Self, MarshalError> {
Ok(match u8::try_from(x).map_err(|_| MarshalError::InvalidBytecode)? {
$($value => Self::$var,)*
_ => return Err(MarshalError::InvalidBytecode),
})
}
}
};
}
macro_rules! op_arg_enum {
($(#[$attr:meta])* $vis:vis enum $name:ident { $($(#[$var_attr:meta])* $var:ident = $value:literal,)* }) => {
$(#[$attr])*
$vis enum $name {
$($(#[$var_attr])* $var = $value,)*
}
op_arg_enum_impl!(enum $name {
$($(#[$var_attr])* $var = $value,)*
});
};
}
pub type NameIdx = u32;
impl OpArgType for u32 {}
//impl OpArgType for bool {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
#[repr(transparent)]
pub struct Label(pub u32);
impl OpArgType for Label {
#[inline(always)]
fn from_op_arg(x: u32) -> Result<Self, MarshalError> {
Ok(Self(x))
}
#[inline(always)]
fn to_op_arg(self) -> u32 {
self.0
impl Label {
pub const fn new(value: u32) -> Self {
Self(value)
}
}
impl From<u32> for Label {
fn from(value: u32) -> Self {
Self::new(value)
}
}
impl From<Label> for u32 {
fn from(value: Label) -> Self {
value.0
}
}
impl OpArgType for Label {}
impl fmt::Display for Label {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
op_arg_enum!(
/// The kind of Raise that occurred.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum RaiseKind {
/// Bare `raise` statement with no arguments.
/// Gets the current exception from VM state (topmost_exception).
/// Maps to RAISE_VARARGS with oparg=0.
BareRaise = 0,
/// `raise exc` - exception is on the stack.
/// Maps to RAISE_VARARGS with oparg=1.
Raise = 1,
/// `raise exc from cause` - exception and cause are on the stack.
/// Maps to RAISE_VARARGS with oparg=2.
RaiseCause = 2,
/// Reraise exception from the stack top.
/// Used in exception handler cleanup blocks (finally, except).
/// Gets exception from stack, not from VM state.
/// Maps to the RERAISE opcode.
ReraiseFromStack = 3,
}
);
/// The kind of Raise that occurred.
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, TryFromPrimitive, IntoPrimitive, Eq)]
#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))]
pub enum RaiseKind {
/// Bare `raise` statement with no arguments.
/// Gets the current exception from VM state (topmost_exception).
/// Maps to RAISE_VARARGS with oparg=0.
BareRaise = 0,
/// `raise exc` - exception is on the stack.
/// Maps to RAISE_VARARGS with oparg=1.
Raise = 1,
/// `raise exc from cause` - exception and cause are on the stack.
/// Maps to RAISE_VARARGS with oparg=2.
RaiseCause = 2,
/// Reraise exception from the stack top.
/// Used in exception handler cleanup blocks (finally, except).
/// Gets exception from stack, not from VM state.
/// Maps to the RERAISE opcode.
ReraiseFromStack = 3,
}
op_arg_enum!(
/// Intrinsic function for CALL_INTRINSIC_1
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum IntrinsicFunction1 {
// Invalid = 0,
Print = 1,
/// Import * operation
ImportStar = 2,
/// Convert StopIteration to RuntimeError in async context
StopIterationError = 3,
AsyncGenWrap = 4,
UnaryPositive = 5,
/// Convert list to tuple
ListToTuple = 6,
/// Type parameter related
TypeVar = 7,
ParamSpec = 8,
TypeVarTuple = 9,
/// Generic subscript for PEP 695
SubscriptGeneric = 10,
TypeAlias = 11,
}
);
impl_oparg_enum_traits!(RaiseKind);
impl OpArgType for RaiseKind {}
op_arg_enum!(
/// Intrinsic function for CALL_INTRINSIC_2
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum IntrinsicFunction2 {
PrepReraiseStar = 1,
TypeVarWithBound = 2,
TypeVarWithConstraint = 3,
SetFunctionTypeParams = 4,
/// Set default value for type parameter (PEP 695)
SetTypeparamDefault = 5,
}
);
/// Intrinsic function for CALL_INTRINSIC_1
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, IntoPrimitive, TryFromPrimitive)]
#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))]
pub enum IntrinsicFunction1 {
// Invalid = 0,
Print = 1,
/// Import * operation
ImportStar = 2,
/// Convert StopIteration to RuntimeError in async context
StopIterationError = 3,
AsyncGenWrap = 4,
UnaryPositive = 5,
/// Convert list to tuple
ListToTuple = 6,
/// Type parameter related
TypeVar = 7,
ParamSpec = 8,
TypeVarTuple = 9,
/// Generic subscript for PEP 695
SubscriptGeneric = 10,
TypeAlias = 11,
}
impl_oparg_enum_traits!(IntrinsicFunction1);
impl OpArgType for IntrinsicFunction1 {}
/// Intrinsic function for CALL_INTRINSIC_2
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))]
pub enum IntrinsicFunction2 {
PrepReraiseStar = 1,
TypeVarWithBound = 2,
TypeVarWithConstraint = 3,
SetFunctionTypeParams = 4,
/// Set default value for type parameter (PEP 695)
SetTypeparamDefault = 5,
}
impl_oparg_enum_traits!(IntrinsicFunction2);
impl OpArgType for IntrinsicFunction2 {}
bitflags! {
#[derive(Copy, Clone, Debug, PartialEq)]
@@ -342,106 +310,111 @@ bitflags! {
}
}
impl OpArgType for MakeFunctionFlags {
#[inline(always)]
fn from_op_arg(x: u32) -> Result<Self, MarshalError> {
Self::from_bits(x as u8).ok_or(MarshalError::InvalidBytecode)
}
impl TryFrom<u32> for MakeFunctionFlags {
type Error = MarshalError;
#[inline(always)]
fn to_op_arg(self) -> u32 {
self.bits().into()
fn try_from(value: u32) -> Result<Self, Self::Error> {
Self::from_bits(value as u8).ok_or(Self::Error::InvalidBytecode)
}
}
op_arg_enum!(
/// The possible comparison operators
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum ComparisonOperator {
// be intentional with bits so that we can do eval_ord with just a bitwise and
// bits: | Equal | Greater | Less |
Less = 0b001,
Greater = 0b010,
NotEqual = 0b011,
Equal = 0b100,
LessOrEqual = 0b101,
GreaterOrEqual = 0b110,
impl From<MakeFunctionFlags> for u32 {
fn from(value: MakeFunctionFlags) -> Self {
value.bits().into()
}
);
}
op_arg_enum!(
/// The possible Binary operators
///
/// # Examples
///
/// ```rust
/// use rustpython_compiler_core::bytecode::{Arg, BinaryOperator, Instruction};
/// let (op, _) = Arg::new(BinaryOperator::Add);
/// let instruction = Instruction::BinaryOp { op };
/// ```
///
/// See also:
/// - [_PyEval_BinaryOps](https://github.com/python/cpython/blob/8183fa5e3f78ca6ab862de7fb8b14f3d929421e0/Python/ceval.c#L316-L343)
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BinaryOperator {
/// `+`
Add = 0,
/// `&`
And = 1,
/// `//`
FloorDivide = 2,
/// `<<`
Lshift = 3,
/// `@`
MatrixMultiply = 4,
/// `*`
Multiply = 5,
/// `%`
Remainder = 6,
/// `|`
Or = 7,
/// `**`
Power = 8,
/// `>>`
Rshift = 9,
/// `-`
Subtract = 10,
/// `/`
TrueDivide = 11,
/// `^`
Xor = 12,
/// `+=`
InplaceAdd = 13,
/// `&=`
InplaceAnd = 14,
/// `//=`
InplaceFloorDivide = 15,
/// `<<=`
InplaceLshift = 16,
/// `@=`
InplaceMatrixMultiply = 17,
/// `*=`
InplaceMultiply = 18,
/// `%=`
InplaceRemainder = 19,
/// `|=`
InplaceOr = 20,
/// `**=`
InplacePower = 21,
/// `>>=`
InplaceRshift = 22,
/// `-=`
InplaceSubtract = 23,
/// `/=`
InplaceTrueDivide = 24,
/// `^=`
InplaceXor = 25,
/// `[]` subscript
Subscr = 26,
}
);
impl OpArgType for MakeFunctionFlags {}
/// The possible comparison operators.
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))]
pub enum ComparisonOperator {
// be intentional with bits so that we can do eval_ord with just a bitwise and
// bits: | Equal | Greater | Less |
Less = 0b001,
Greater = 0b010,
NotEqual = 0b011,
Equal = 0b100,
LessOrEqual = 0b101,
GreaterOrEqual = 0b110,
}
impl_oparg_enum_traits!(ComparisonOperator);
impl OpArgType for ComparisonOperator {}
/// The possible Binary operators
///
/// # Examples
///
/// ```rust
/// use rustpython_compiler_core::bytecode::{Arg, BinaryOperator, Instruction};
/// let (op, _) = Arg::new(BinaryOperator::Add);
/// let instruction = Instruction::BinaryOp { op };
/// ```
///
/// See also:
/// - [_PyEval_BinaryOps](https://github.com/python/cpython/blob/8183fa5e3f78ca6ab862de7fb8b14f3d929421e0/Python/ceval.c#L316-L343)
#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))]
pub enum BinaryOperator {
/// `+`
Add = 0,
/// `&`
And = 1,
/// `//`
FloorDivide = 2,
/// `<<`
Lshift = 3,
/// `@`
MatrixMultiply = 4,
/// `*`
Multiply = 5,
/// `%`
Remainder = 6,
/// `|`
Or = 7,
/// `**`
Power = 8,
/// `>>`
Rshift = 9,
/// `-`
Subtract = 10,
/// `/`
TrueDivide = 11,
/// `^`
Xor = 12,
/// `+=`
InplaceAdd = 13,
/// `&=`
InplaceAnd = 14,
/// `//=`
InplaceFloorDivide = 15,
/// `<<=`
InplaceLshift = 16,
/// `@=`
InplaceMatrixMultiply = 17,
/// `*=`
InplaceMultiply = 18,
/// `%=`
InplaceRemainder = 19,
/// `|=`
InplaceOr = 20,
/// `**=`
InplacePower = 21,
/// `>>=`
InplaceRshift = 22,
/// `-=`
InplaceSubtract = 23,
/// `/=`
InplaceTrueDivide = 24,
/// `^=`
InplaceXor = 25,
/// `[]` subscript
Subscr = 26,
}
impl BinaryOperator {
/// Get the "inplace" version of the operator.
@@ -476,6 +449,9 @@ impl BinaryOperator {
}
}
impl_oparg_enum_traits!(BinaryOperator);
impl OpArgType for BinaryOperator {}
impl fmt::Display for BinaryOperator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let op = match self {
@@ -511,39 +487,43 @@ impl fmt::Display for BinaryOperator {
}
}
op_arg_enum!(
/// Whether or not to invert the operation.
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Invert {
/// ```py
/// foo is bar
/// x in lst
/// ```
No = 0,
/// ```py
/// foo is not bar
/// x not in lst
/// ```
Yes = 1,
}
);
/// Whether or not to invert the operation.
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))]
pub enum Invert {
/// ```py
/// foo is bar
/// x in lst
/// ```
No = 0,
/// ```py
/// foo is not bar
/// x not in lst
/// ```
Yes = 1,
}
op_arg_enum!(
/// Special method for LOAD_SPECIAL opcode (context managers).
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum SpecialMethod {
/// `__enter__` for sync context manager
Enter = 0,
/// `__exit__` for sync context manager
Exit = 1,
/// `__aenter__` for async context manager
AEnter = 2,
/// `__aexit__` for async context manager
AExit = 3,
}
);
impl_oparg_enum_traits!(Invert);
impl OpArgType for Invert {}
/// Special method for LOAD_SPECIAL opcode (context managers).
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))]
pub enum SpecialMethod {
/// `__enter__` for sync context manager
Enter = 0,
/// `__exit__` for sync context manager
Exit = 1,
/// `__aenter__` for async context manager
AEnter = 2,
/// `__aexit__` for async context manager
AExit = 3,
}
impl_oparg_enum_traits!(SpecialMethod);
impl OpArgType for SpecialMethod {}
impl fmt::Display for SpecialMethod {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -557,24 +537,26 @@ impl fmt::Display for SpecialMethod {
}
}
op_arg_enum!(
/// Common constants for LOAD_COMMON_CONSTANT opcode.
/// pycore_opcode_utils.h CONSTANT_*
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CommonConstant {
/// `AssertionError` exception type
AssertionError = 0,
/// `NotImplementedError` exception type
NotImplementedError = 1,
/// Built-in `tuple` type
BuiltinTuple = 2,
/// Built-in `all` function
BuiltinAll = 3,
/// Built-in `any` function
BuiltinAny = 4,
}
);
/// Common constants for LOAD_COMMON_CONSTANT opcode.
/// pycore_opcode_utils.h CONSTANT_*
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))]
pub enum CommonConstant {
/// `AssertionError` exception type
AssertionError = 0,
/// `NotImplementedError` exception type
NotImplementedError = 1,
/// Built-in `tuple` type
BuiltinTuple = 2,
/// Built-in `all` function
BuiltinAll = 3,
/// Built-in `any` function
BuiltinAny = 4,
}
impl_oparg_enum_traits!(CommonConstant);
impl OpArgType for CommonConstant {}
impl fmt::Display for CommonConstant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -602,54 +584,60 @@ pub enum BuildSliceArgCount {
Three,
}
impl OpArgType for BuildSliceArgCount {
#[inline(always)]
fn from_op_arg(x: u32) -> Result<Self, MarshalError> {
Ok(match x {
impl TryFrom<u8> for BuildSliceArgCount {
type Error = MarshalError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
Ok(match value {
2 => Self::Two,
3 => Self::Three,
_ => return Err(MarshalError::InvalidBytecode),
_ => return Err(Self::Error::InvalidBytecode),
})
}
}
#[inline(always)]
fn to_op_arg(self) -> u32 {
u32::from(self.argc().get())
impl TryFrom<u32> for BuildSliceArgCount {
type Error = MarshalError;
fn try_from(value: u32) -> Result<Self, Self::Error> {
u8::try_from(value)
.map_err(|_| Self::Error::InvalidBytecode)
.map(TryInto::try_into)?
}
}
impl BuildSliceArgCount {
/// Get the numeric value of `Self`.
#[must_use]
pub const fn argc(self) -> NonZeroU8 {
let inner = match self {
Self::Two => 2,
Self::Three => 3,
};
// Safety: `inner` can be either 2 or 3.
unsafe { NonZeroU8::new_unchecked(inner) }
impl From<BuildSliceArgCount> for u32 {
fn from(value: BuildSliceArgCount) -> Self {
match value {
BuildSliceArgCount::Two => 2,
BuildSliceArgCount::Three => 3,
}
}
}
impl OpArgType for BuildSliceArgCount {}
#[derive(Copy, Clone)]
pub struct UnpackExArgs {
pub before: u8,
pub after: u8,
}
impl OpArgType for UnpackExArgs {
#[inline(always)]
fn from_op_arg(x: u32) -> Result<Self, MarshalError> {
let [before, after, ..] = x.to_le_bytes();
Ok(Self { before, after })
}
#[inline(always)]
fn to_op_arg(self) -> u32 {
u32::from_le_bytes([self.before, self.after, 0, 0])
impl From<u32> for UnpackExArgs {
fn from(value: u32) -> Self {
let [before, after, ..] = value.to_le_bytes();
Self { before, after }
}
}
impl From<UnpackExArgs> for u32 {
fn from(value: UnpackExArgs) -> Self {
Self::from_le_bytes([value.before, value.after, 0, 0])
}
}
impl OpArgType for UnpackExArgs {}
impl fmt::Display for UnpackExArgs {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "before: {}, after: {}", self.before, self.after)
@@ -686,17 +674,7 @@ impl LoadSuperAttr {
}
}
impl OpArgType for LoadSuperAttr {
#[inline(always)]
fn from_op_arg(x: u32) -> Result<Self, MarshalError> {
Ok(x.into())
}
#[inline(always)]
fn to_op_arg(self) -> u32 {
self.into()
}
}
impl OpArgType for LoadSuperAttr {}
impl From<u32> for LoadSuperAttr {
fn from(value: u32) -> Self {
@@ -749,3 +727,23 @@ impl From<LoadSuperAttrBuilder> for LoadSuperAttr {
builder.build()
}
}
/// Helper function for `num_enum` derive macro.
///
/// # Examples
///
/// ```ignore
/// use num_enum::TryFromPrimitive;
///
/// use rustpython_compiler_core::marshal::MarshalError;
///
/// #[repr(u8)]
/// #[derive(TryFromPrimitive)]
/// #[num_enum(error_type(name = MarshalError, constructor = new_invalid_bytecode))]
/// enum Foo {
/// A = 1,
/// B = 2
/// }
fn new_invalid_bytecode<T>(_: T) -> MarshalError {
MarshalError::InvalidBytecode
}