Skip to content

Commit ff9d01f

Browse files
committed
patches with bindings
1 parent 2bf120f commit ff9d01f

File tree

4 files changed

+58
-11
lines changed

4 files changed

+58
-11
lines changed

src/pointers/_cstd.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ class lconv(ctypes.Structure):
523523
dll.difftime.argtypes = (ctypes.c_int, ctypes.c_int)
524524
dll.difftime.restype = ctypes.c_double
525525
# struct tm* gmtime(const time_t* timer)
526-
dll.gmtime.argtypes = (ctypes.c_int,)
526+
dll.gmtime.argtypes = (ctypes.POINTER(ctypes.c_int),)
527527
dll.gmtime.restype = ctypes.POINTER(tm)
528528
# struct tm* localtime(const time_t* timer)
529529
dll.localtime.argtypes = (ctypes.c_int,)

src/pointers/bindings.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
T = TypeVar("T")
3939
PointerLike = Union[TypedCPointer[Any], VoidPointer]
40-
StringLike = Union[str, bytes, VoidPointer]
40+
StringLike = Union[str, bytes, VoidPointer, TypedCPointer[bytes]]
4141
Format = Union[str, bytes, PointerLike]
4242

4343
__all__ = (
@@ -149,6 +149,7 @@
149149
"c_calloc",
150150
"c_realloc",
151151
"c_free",
152+
"gmtime",
152153
)
153154

154155

@@ -176,7 +177,7 @@ def _decode_response(
176177
res = (
177178
TypedCPointer(ctypes.addressof(res), res_typ, ctypes.sizeof(res))
178179
if not issubclass(type(res.contents), ctypes.Structure)
179-
else StructPointer(id(struct), type(_not_null(struct)))
180+
else StructPointer(id(struct), type(_not_null(struct)), struct)
180181
)
181182
# type safety gets mad if i dont use elif here
182183
elif fn.restype is ctypes.c_void_p:
@@ -229,15 +230,22 @@ def _base(
229230

230231

231232
def _make_char_pointer(data: StringLike) -> Union[bytes, ctypes.c_char_p]:
232-
if type(data) not in {VoidPointer, str, bytes}:
233+
if type(data) not in {VoidPointer, str, bytes, TypedCPointer}:
233234
raise InvalidBindingParameter(
234235
f"expected a string-like object, got {repr(data)}" # noqa
235236
)
236237

237238
if isinstance(data, bytes):
238239
return data
239240

240-
if isinstance(data, VoidPointer):
241+
is_typed_ptr: bool = isinstance(data, TypedCPointer)
242+
243+
if isinstance(data, VoidPointer) or is_typed_ptr:
244+
if is_typed_ptr and (data.type is not bytes):
245+
raise InvalidBindingParameter(
246+
f"{data} does not point to bytes",
247+
)
248+
241249
return ctypes.c_char_p(data.address)
242250

243251
return data.encode()
@@ -809,12 +817,18 @@ def mktime(timeptr: StructPointer[Tm]) -> int:
809817

810818

811819
def strftime(
812-
string: str,
820+
string: StringLike,
813821
maxsize: int,
814-
fmt: TypedCPointer[str],
822+
fmt: StringLike,
815823
timeptr: StructPointer[Tm],
816824
) -> int:
817-
return _base(dll.strftime, string, maxsize, fmt, timeptr)
825+
return _base(
826+
dll.strftime,
827+
_make_char_pointer(string),
828+
maxsize,
829+
_make_char_pointer(fmt),
830+
timeptr,
831+
)
818832

819833

820834
def time(timer: TypedCPointer[int]) -> int:
@@ -851,3 +865,7 @@ def c_realloc(ptr: PointerLike, size: int) -> VoidPointer:
851865

852866
def c_free(ptr: PointerLike) -> None:
853867
return _base(_free, ptr)
868+
869+
870+
def gmtime(timer: PointerLike) -> StructPointer[Tm]:
871+
return _base(dll.gmtime, timer)

src/pointers/c_pointer.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,27 @@ def attempt_decode(data: bytes) -> Union[str, bytes]:
6262
class StructPointer(Pointer[A]):
6363
"""Class representing a pointer to a struct."""
6464

65-
def __init__(self, address: int, data_type: Type[A]):
65+
def __init__(
66+
self,
67+
address: int,
68+
data_type: Type[A],
69+
existing: Optional["Struct"] = None,
70+
):
6671
super().__init__(address, data_type, True)
72+
self._existing = existing
6773

6874
@property
69-
def _as_parameter_(self):
75+
def _as_parameter_(self) -> Union[int, ctypes.pointer]:
76+
existing = self._existing
77+
78+
if existing:
79+
return ctypes.pointer(existing.struct)
80+
7081
return self._address
7182

83+
def __repr__(self) -> str:
84+
return f"<pointer to struct at {hex(self.address)}>"
85+
7286

7387
class _BaseCPointer(Pointer[Any], Generic[T]):
7488
def __init__(self, address: int, size: int):
@@ -80,6 +94,11 @@ def size(self):
8094
"""Size of the pointer."""
8195
return self._size
8296

97+
@property
98+
def type(self) -> T:
99+
"""Type of the pointer."""
100+
return self._type
101+
83102
# i need to repeat these for type safety
84103
def __iter__(self) -> Iterator[T]:
85104
"""Dereference the pointer."""
@@ -147,8 +166,13 @@ def is_mappable(cls, typ: Any) -> bool:
147166
return False
148167

149168
@staticmethod
150-
def get_py(data: Type["ctypes._CData"]) -> type:
169+
def get_py(
170+
data: Type["ctypes._CData"],
171+
) -> Type[Any]:
151172
"""Map the specified C type to a Python type."""
173+
if data.__name__.startswith("LP_"):
174+
return Pointer
175+
152176
types: Dict[Type["ctypes._CData"], type] = {
153177
ctypes.c_bool: bool,
154178
ctypes.c_char: bytes,

src/pointers/struct.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,8 @@ def _sync(self):
5858

5959
def __repr__(self) -> str:
6060
return f"<struct {self.__class__.__name__} at {hex(ctypes.addressof(self._struct))}>" # noqa
61+
62+
@property
63+
def struct(self) -> ctypes.Structure:
64+
"""Raw internal Structure object."""
65+
return self._struct

0 commit comments

Comments
 (0)