Skip to content

Commit 2daa0f8

Browse files
committed
feat: refactor library to remove circular imports
As a side-effect, registering new types is much easier
1 parent 4464e5c commit 2daa0f8

15 files changed

Lines changed: 375 additions & 123 deletions

libdestruct/c/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@
1111
from libdestruct.c.c_ulong import c_ulong
1212

1313
__all__ = ["c_int", "c_long", "c_str", "c_uint", "c_ulong"]
14+
15+
import libdestruct.c.base_type_inflater
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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 libdestruct.c.c_int import c_int
10+
from libdestruct.c.c_long import c_long
11+
from libdestruct.c.c_str import c_str
12+
from libdestruct.c.c_uint import c_uint
13+
from libdestruct.c.c_ulong import c_ulong
14+
from libdestruct.common.type_registry import TypeRegistry
15+
16+
registry = TypeRegistry()
17+
18+
19+
registry.register_mapping(c_int, c_int)
20+
registry.register_mapping(c_uint, c_uint)
21+
registry.register_mapping(c_long, c_long)
22+
registry.register_mapping(c_ulong, c_ulong)
23+
registry.register_mapping(c_str, c_str)

libdestruct/c/c_str.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from __future__ import annotations
88

9-
from libdestruct.common.array import array
9+
from libdestruct.common.array.array import array
1010
from libdestruct.common.obj import obj
1111

1212

libdestruct/common/array/__init__.py

Whitespace-only changes.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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.array.array import array
12+
13+
if TYPE_CHECKING:
14+
from collections.abc import MutableSequence
15+
16+
from libdestruct.common.obj import obj
17+
18+
19+
class arr_impl(array):
20+
"""A linear sequential array."""
21+
22+
size: int
23+
"""The size of the array."""
24+
25+
def __init__(
26+
self: arr_impl,
27+
memory: MutableSequence,
28+
address: int | tuple[obj, int],
29+
backing_type: obj,
30+
count: int,
31+
) -> None:
32+
"""Initialize the array."""
33+
self.memory = memory
34+
self.address = address
35+
self.backing_type = backing_type
36+
self.count = count
37+
38+
self.size = self.backing_type.size * self.count
39+
40+
def __getitem__(self: arr_impl, index: int) -> obj:
41+
"""Get an item from the array."""
42+
return self.backing_type(self.memory, (self.address, index * self.backing_type.size))
43+
44+
def __setitem__(self: arr_impl, index: int, value: obj) -> None:
45+
"""Set an item in the array."""
46+
raise NotImplementedError("Cannot set items in an array.")

libdestruct/common/inflater.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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.type_registry import TypeRegistry
12+
13+
if TYPE_CHECKING:
14+
from collections.abc import MutableSequence
15+
16+
from libdestruct.common.obj import obj
17+
18+
19+
class Inflater:
20+
"""The memory manager, which inflates any memory-referencing type."""
21+
22+
def __init__(self: Inflater, memory: MutableSequence) -> None:
23+
"""Initialize the memory manager."""
24+
self.memory = memory
25+
self.type_registry = TypeRegistry()
26+
27+
def inflate(self: Inflater, item: type, address: int | tuple[obj, int]) -> obj:
28+
"""Inflate a memory-referencing type.
29+
30+
Args:
31+
item: The type to inflate.
32+
address: The address of the object in the memory view.
33+
34+
Returns:
35+
The inflated object.
36+
"""
37+
return self.type_registry.inflater_for(item)(self.memory, address)

libdestruct/common/struct/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@
99
from libdestruct.common.struct.struct_impl import struct_impl
1010

1111
__all__ = ["struct", "struct_impl", "ptr_to", "ptr_to_self"]
12+
13+
import libdestruct.common.struct.field_inflater
14+
import libdestruct.common.struct.struct_inflater
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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.struct.ptr_struct_field import PtrStructField
12+
from libdestruct.common.struct.struct import struct
13+
from libdestruct.common.struct.struct_impl import struct_impl
14+
from libdestruct.common.type_registry import TypeRegistry
15+
16+
if TYPE_CHECKING:
17+
from libdestruct.common.obj import obj
18+
19+
registry = TypeRegistry()
20+
21+
22+
def inflate_ptr_field(
23+
field: PtrStructField,
24+
_: type[obj],
25+
owner: tuple[obj, type[obj]] | None,
26+
) -> obj:
27+
"""Inflate a field of a struct that has an associated generator."""
28+
if not field.backing_type:
29+
if owner:
30+
_, owner_type = owner
31+
field.backing_type = owner_type
32+
elif issubclass(field.backing_type, struct) and not issubclass(field.backing_type, struct_impl):
33+
field.backing_type = registry.inflater_for(field.backing_type)
34+
35+
return field.inflate
36+
37+
38+
registry.register_instance_handler(PtrStructField, inflate_ptr_field)

libdestruct/common/struct/struct.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from typing import TYPE_CHECKING
1010

1111
from libdestruct.common.obj import obj
12+
from libdestruct.libdestruct import inflater
1213

1314
if TYPE_CHECKING:
1415
from libdestruct.common.struct.struct_impl import struct_impl
@@ -17,18 +18,16 @@
1718
class struct(obj):
1819
"""A C struct."""
1920

20-
def __init__(self: obj) -> None:
21+
def __init__(self: struct) -> None:
2122
"""Initialize the struct."""
2223
raise RuntimeError("This type should not be directly instantiated.")
2324

2425
@classmethod
2526
def from_bytes(cls: type[struct], data: bytes) -> struct_impl:
2627
"""Create a struct from a serialized representation."""
27-
from libdestruct import inflater
28-
2928
type_inflater = inflater(data)
3029

31-
result = type_inflater.inflate_struct(cls, 0)
30+
result = type_inflater.inflate(cls, 0)
3231

3332
if result.size != len(data):
3433
raise ValueError("The length of the serialized struct does not match the struct size.")

0 commit comments

Comments
 (0)