Added "TFlagsEnum" and "FlagsEnumBase"

This commit is contained in:
Tim Rid 2021-01-02 12:01:20 +01:00
parent def9e93da7
commit ac8800943a
3 changed files with 78 additions and 27 deletions

View file

@ -7,7 +7,7 @@ from .generic_wrapper import (
PathType,
)
from .tarray import TArray
from .tenum import TEnum, EnumBase
from .tenum import TEnum, EnumBase, TFlagsEnum, FlagsEnumBase
from .tstruct import TBitStruct, TStruct, TStructField
from .tunion import TUnion, TUnionField
@ -26,4 +26,6 @@ __all__ = [
"Context",
"ConstantOrContextLambda",
"PathType",
"TFlagsEnum",
"FlagsEnumBase"
]

View file

@ -4,6 +4,7 @@ import typing as t
from .generic_wrapper import *
# ## TEnum ############################################################################################################
class EnumBase(enum.IntEnum):
"""
Base class for an Enum used in `construct_typed.TEnum`.
@ -58,8 +59,46 @@ class TEnum(Adapter[int, int, EnumType, EnumType]):
def _encode(
self,
obj: EnumType,
context: "cs.Context",
path: "cs.PathType",
context: Context,
path: PathType,
) -> int:
if isinstance(obj, self.enum_type):
return int(obj)
raise TypeError("'{}' has to be of type {}".format(repr(obj), repr(self.enum_type)))
# ## TFlagsEnum #######################################################################################################
class FlagsEnumBase(enum.IntFlag):
pass
FlagsEnumType = t.TypeVar("FlagsEnumType", bound=FlagsEnumBase)
class TFlagsEnum(Adapter[int, int, FlagsEnumType, FlagsEnumType]):
"""
Typed enum.
"""
def __init__(self, subcon: Construct[int, int], enum_type: t.Type[FlagsEnumType]):
if not issubclass(enum_type, FlagsEnumBase):
raise TypeError(
"'{}' has to be a '{}'".format(repr(enum_type), repr(FlagsEnumBase))
)
# save enum type
self.enum_type = enum_type
# init adatper
super(TFlagsEnum, self).__init__(subcon)
def _decode(self, obj: int, context: Context, path: PathType) -> FlagsEnumType:
return self.enum_type(obj) # type: ignore
def _encode(
self,
obj: FlagsEnumType,
context: Context,
path: PathType,
) -> int:
if isinstance(obj, self.enum_type):
return int(obj)

View file

@ -151,29 +151,23 @@ def test_tbitstruct() -> None:
def test_tenum() -> None:
class E(cst.EnumBase):
a = 1
b = 2
class TestEnum(cst.EnumBase):
one = 1
two = 2
four = 4
eight = 8
common(cst.TEnum(cs.Byte, E), b"\x01", E.a, 1)
common(cst.TEnum(cs.Byte, E), b"\x02", E.b, 1)
common(cst.TEnum(cs.Byte, E), b"\x03", E(3), 1)
common(cst.TEnum(cs.Byte, E), b"\xff", E(255), 1)
format = cst.TEnum(cs.Byte, E)
obj = format.parse(b"\x01")
assert obj == E.a
assert obj == 1
obj = format.parse(b"\x02")
assert obj == E.b
assert obj == 2
obj = format.parse(b"\x03")
assert obj == E(3)
assert obj == 3
obj = format.parse(b"\xff")
assert obj == E(255)
assert obj == 255
d = cst.TEnum(cs.Byte, TestEnum)
common(d, b"\x01", TestEnum.one, 1)
common(d, b"\xff", TestEnum(255), 1)
assert d.parse(b"\x01") == TestEnum.one
assert d.parse(b"\x01") == 1
assert int(d.parse(b"\x01")) == 1
assert d.parse(b"\xff") == TestEnum(255)
assert d.parse(b"\xff") == 255
assert int(d.parse(b"\xff")) == 255
assert raises(d.build, 8) == TypeError
def test_tenum_no_enumbase() -> None:
@ -193,9 +187,7 @@ def test_tstruct_wrong_enumbase() -> None:
a = 1
b = 2
assert (
raises(cst.TEnum(cs.Byte, E1).build, E2.a) == TypeError
)
assert raises(cst.TEnum(cs.Byte, E1).build, E2.a) == TypeError
def test_tenum_in_tstruct() -> None:
@ -218,3 +210,21 @@ def test_tenum_in_tstruct() -> None:
assert (
raises(cst.TEnum(cs.Byte, TestEnum).build, TestDataclass(a=1, b=2)) == TypeError # type: ignore
)
def test_tenum_flags() -> None:
class TestEnum(cst.FlagsEnumBase):
one = 1
two = 2
four = 4
eight = 8
d = cst.TFlagsEnum(cs.Byte, TestEnum)
common(d, b"\x03", TestEnum.one | TestEnum.two, 1)
assert d.build(TestEnum(0)) == b"\x00"
assert d.build(TestEnum.one | TestEnum.two) == b"\x03"
assert d.build(TestEnum(8)) == b"\x08"
assert d.build(TestEnum(1 | 2)) == b"\x03"
assert d.build(TestEnum(255)) == b"\xff"
assert d.build(TestEnum.eight) == b"\x08"
assert raises(d.build, 2) == TypeError