Skip to content

Commit 78afe41

Browse files
committed
feat: implement enums, make field chains work
1 parent 14122c7 commit 78afe41

21 files changed

Lines changed: 318 additions & 47 deletions

libdestruct/__init__.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,23 @@
1414
from libdestruct.c import c_int, c_long, c_str, c_uint, c_ulong
1515
from libdestruct.common import ptr
1616
from libdestruct.common.array import array, array_of
17+
from libdestruct.common.enum import enum, enum_of
1718
from libdestruct.common.struct import ptr_to, ptr_to_self, struct
1819
from libdestruct.libdestruct import inflater
1920

20-
__all__ = ["array", "array_of", "c_int", "c_long", "c_str", "c_uint", "c_ulong", "inflater", "struct", "ptr", "ptr_to", "ptr_to_self"]
21+
__all__ = [
22+
"array",
23+
"array_of",
24+
"c_int",
25+
"c_long",
26+
"c_str",
27+
"c_uint",
28+
"c_ulong",
29+
"enum",
30+
"enum_of",
31+
"inflater",
32+
"struct",
33+
"ptr",
34+
"ptr_to",
35+
"ptr_to_self",
36+
]

libdestruct/c/base_type_inflater.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66

77
from __future__ import annotations
88

9-
from libdestruct.c.c_integer_types import c_char, c_int, c_long, c_short, c_uchar, c_uint, c_ulong, c_ushort
9+
from libdestruct.c.c_integer_types import _c_integer, c_char, c_int, c_long, c_short, c_uchar, c_uint, c_ulong, c_ushort
1010
from libdestruct.c.c_str import c_str
1111
from libdestruct.common.type_registry import TypeRegistry
1212

1313
registry = TypeRegistry()
1414

1515

16+
registry.register_mapping(_c_integer, _c_integer)
1617
registry.register_mapping(c_char, c_char)
1718
registry.register_mapping(c_uchar, c_uchar)
1819
registry.register_mapping(c_short, c_short)

libdestruct/common/array/array.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ def __getitem__(self: array, index: int) -> object:
3030
"""Return the element at the given index."""
3131
return self.get(index)
3232

33-
@abstractmethod
34-
def set(self: array, index: int, value: object) -> None:
35-
"""Set the element at the given index to the given value."""
36-
3733
def __setitem__(self: array, index: int, value: object) -> None:
3834
"""Set the element at the given index to the given value."""
3935
self.set(index, value)

libdestruct/common/array/array_field.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@
66

77
from __future__ import annotations
88

9-
from abc import ABC, abstractmethod
9+
from abc import abstractmethod
1010
from typing import TYPE_CHECKING
1111

12+
from libdestruct.common.field import Field
13+
1214
if TYPE_CHECKING:
1315
from collections.abc import MutableSequence
1416

1517
from libdestruct.common.array import array
1618
from libdestruct.common.obj import obj
1719

1820

19-
class ArrayField(ABC):
21+
class ArrayField(Field):
2022
"""A generator for an array of items."""
2123

2224
@abstractmethod

libdestruct/common/array/array_field_inflater.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
from typing import TYPE_CHECKING
1111

1212
from libdestruct.common.array.linear_array_field import LinearArrayField
13-
from libdestruct.common.struct.struct import struct
14-
from libdestruct.common.struct.struct_impl import struct_impl
1513
from libdestruct.common.type_registry import TypeRegistry
1614

1715
if TYPE_CHECKING:
@@ -28,8 +26,7 @@ def linear_array_field_inflater(
2826
__: tuple[obj, type[obj]] | None,
2927
) -> Callable[[MutableSequence, int | tuple[obj, int]], obj]:
3028
"""Returns the inflater for an array field of a struct."""
31-
if issubclass(field.item, struct) and not issubclass(field.item, struct_impl):
32-
field.item = registry.inflater_for(field.item)
29+
field.item = registry.inflater_for(field.item)
3330

3431
return field.inflate
3532

libdestruct/common/array/array_impl.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,10 @@ def __init__(
3131
count: int,
3232
) -> None:
3333
"""Initialize the array."""
34-
self.memory = memory
34+
super().__init__(memory, address)
35+
3536
self.backing_type = backing_type
3637
self.count = count
37-
38-
if isinstance(address, tuple):
39-
self._address = None
40-
self._reference = address[0]
41-
self._offset = address[1]
42-
else:
43-
self._address = address
44-
4538
self.size = self.backing_type.size * self.count
4639

4740
def size(self: array_impl) -> int:
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#
2+
# This file is part of libdestruct (https://github.com/mrindeciso/libdestruct).
3+
# Copyright (c) 2024 Roberto Alessandro Bertolini. All rights reserved.
4+
# Licensed under the MIT license. See LICENSE file in the project root for details.
5+
#
6+
7+
from libdestruct.common.enum.enum import enum
8+
from libdestruct.common.enum.enum_of import enum_of
9+
10+
__all__ = ["enum", "enum_of"]
11+
12+
import libdestruct.common.enum.enum_field_inflater # noqa: F401

libdestruct/common/enum/enum.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#
2+
# This file is part of libdestruct (https://github.com/mrindeciso/libdestruct).
3+
# Copyright (c) 2024 Roberto Alessandro Bertolini. All rights reserved.
4+
# Licensed under the MIT license. See LICENSE file in the project root for details.
5+
#
6+
7+
from __future__ import annotations
8+
9+
from typing import TYPE_CHECKING
10+
11+
from libdestruct.common.obj import obj
12+
from libdestruct.common.type_registry import TypeRegistry
13+
14+
if TYPE_CHECKING:
15+
from collections.abc import MutableSequence
16+
from enum import Enum
17+
18+
19+
class enum(obj):
20+
"""A generic enum."""
21+
22+
python_enum: type[Enum]
23+
"""The backing Python enum."""
24+
25+
_backing_type: type[obj]
26+
"""The backing type."""
27+
28+
lenient: bool
29+
"""Whether the conversion is lenient or not."""
30+
31+
def __init__(
32+
self: enum,
33+
memory: MutableSequence,
34+
address: int | tuple[obj, int],
35+
python_enum: type[Enum],
36+
backing_type: type[obj],
37+
lenient: bool = True,
38+
) -> None:
39+
"""Initialize the enum object."""
40+
super().__init__(memory, address)
41+
42+
self.python_enum = python_enum
43+
self._backing_type = TypeRegistry().inflater_for(backing_type)(memory, address)
44+
self.lenient = lenient
45+
46+
self.size = self._backing_type.size
47+
48+
def get(self: enum) -> Enum:
49+
"""Return the value of the enum."""
50+
return self.python_enum(self._backing_type.get())
51+
52+
def _set(self: enum, value: Enum) -> None:
53+
"""Set the value of the enum."""
54+
self._backing_type.set(value.value)
55+
56+
def to_bytes(self: enum) -> bytes:
57+
"""Return the serialized representation of the enum."""
58+
return self._backing_type.to_bytes()
59+
60+
def to_str(self: obj, indent: int = 0) -> str:
61+
"""Return a string representation of the object."""
62+
return f"{' ' * indent}{self.get()!r}"
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#
2+
# This file is part of libdestruct (https://github.com/mrindeciso/libdestruct).
3+
# Copyright (c) 2024 Roberto Alessandro Bertolini. All rights reserved.
4+
# Licensed under the MIT license. See LICENSE file in the project root for details.
5+
#
6+
7+
from __future__ import annotations
8+
9+
from abc import abstractmethod
10+
from typing import TYPE_CHECKING
11+
12+
from libdestruct.common.field import Field
13+
14+
if TYPE_CHECKING:
15+
from collections.abc import MutableSequence
16+
17+
from libdestruct.common.enum import enum
18+
from libdestruct.common.obj import obj
19+
20+
21+
class EnumField(Field):
22+
"""A generator for an enum."""
23+
24+
@abstractmethod
25+
def inflate(self: EnumField, memory: MutableSequence, address: int | tuple[obj, int]) -> enum:
26+
"""Inflate the field.
27+
28+
Args:
29+
memory: The backing memory view.
30+
address: The address of the field in the memory view.
31+
"""
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#
2+
# This file is part of libdestruct (https://github.com/mrindeciso/libdestruct).
3+
# Copyright (c) 2024 Roberto Alessandro Bertolini. All rights reserved.
4+
# Licensed under the MIT license. See LICENSE file in the project root for details.
5+
#
6+
7+
from __future__ import annotations
8+
9+
from typing import TYPE_CHECKING
10+
11+
from libdestruct.common.enum.int_enum_field import IntEnumField
12+
from libdestruct.common.type_registry import TypeRegistry
13+
14+
if TYPE_CHECKING:
15+
from collections.abc import Callable, MutableSequence
16+
17+
from libdestruct.common.enum.enum_field import EnumField
18+
from libdestruct.common.obj import obj
19+
20+
registry = TypeRegistry()
21+
22+
23+
def generic_enum_field_inflater(
24+
field: EnumField,
25+
_: type[obj],
26+
__: tuple[obj, type[obj]] | None,
27+
) -> Callable[[MutableSequence, int | tuple[obj, int]], obj]:
28+
"""Returns the inflater for an enum field of a struct."""
29+
return field.inflate
30+
31+
32+
registry.register_instance_handler(IntEnumField, generic_enum_field_inflater)

0 commit comments

Comments
 (0)