Skip to content

Commit 0b92cf6

Browse files
committed
feat: add support for ctypes
1 parent 2e16fd0 commit 0b92cf6

4 files changed

Lines changed: 73 additions & 2 deletions

File tree

libdestruct/c/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
__all__ = ["c_char", "c_uchar", "c_short", "c_ushort", "c_int", "c_uint", "c_long", "c_ulong", "c_str"]
1111

1212
import libdestruct.c.base_type_inflater # noqa: F401
13+
import libdestruct.c.ctypes_generic_field # noqa: F401

libdestruct/c/ctypes_generic.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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 Any
10+
11+
from libdestruct.common.obj import obj
12+
13+
14+
class _ctypes_generic(obj):
15+
"""A generic holder for a ctypes object."""
16+
17+
size: int
18+
"""The size of the type in bytes."""
19+
20+
_frozen_value: bytes | None = None
21+
"""The frozen value of the type."""
22+
23+
backing_type: type
24+
"""The backing ctypes object."""
25+
26+
def get(self: _ctypes_generic) -> Any:
27+
"""Return the value of the type."""
28+
return self.backing_type.from_buffer_copy(self.resolver.resolve(self.size, 0)).value
29+
30+
def _set(self: _ctypes_generic, value: Any) -> None:
31+
"""Set the value of the type to the given value."""
32+
self.resolver.modify(self.size, 0, bytes(self.backing_type(value)))
33+
34+
def to_bytes(self: _ctypes_generic) -> bytes:
35+
"""Serialize the type to bytes."""
36+
if self._frozen:
37+
return bytes(self._frozen_value)
38+
39+
return self.resolver.resolve(self.size, 0)
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 ctypes import _SimpleCData, sizeof
10+
11+
from libdestruct.c.ctypes_generic import _ctypes_generic
12+
from libdestruct.common.type_registry import TypeRegistry
13+
14+
15+
def ctypes_type_handler(obj_type: type) -> type[_ctypes_generic]:
16+
"""Return the ctypes type handler for the given object type.
17+
18+
Args:
19+
obj_type: The object type to handle.
20+
"""
21+
if not issubclass(obj_type, _SimpleCData):
22+
raise TypeError(f"Unsupported object type: {obj_type}.")
23+
24+
return type(
25+
f"ctypes_{obj_type.__name__}",
26+
(_ctypes_generic,),
27+
{"backing_type": obj_type, "size": sizeof(obj_type)},
28+
)
29+
30+
31+
TypeRegistry().register_type_handler(_SimpleCData, ctypes_type_handler)

libdestruct/common/type_registry.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from libdestruct.common.field import Field
1212

13-
if TYPE_CHECKING: # pragma: no cover
13+
if TYPE_CHECKING: # pragma: no cover
1414
from collections.abc import Callable
1515

1616
from typing_extensions import Self
@@ -25,7 +25,7 @@ class TypeRegistry:
2525
mapping: dict[type[obj], type[obj]]
2626
"""The mapping of object types to their implementations."""
2727

28-
type_handlers: dict[type[obj], list[Callable[[type[obj]], type[obj] | None]]]
28+
type_handlers: dict[type, list[Callable[[type[obj]], type[obj] | None]]]
2929
"""The handlers for generic object types, with basic inheritance support."""
3030

3131
instance_handlers: dict[

0 commit comments

Comments
 (0)