Coverage for src/evutils/io/_native_dat.py: 100%
39 statements
« prev ^ index » next coverage.py v7.15.1, created at 2026-07-15 09:33 +0000
« prev ^ index » next coverage.py v7.15.1, created at 2026-07-15 09:33 +0000
1"""ctypes bindings for the native Prophesee DAT parser.
3:class:`DatInput` views the 2x-uint32 records zero-copy; :class:`DatParser`
4owns the opaque C state (tracks the 32-bit timestamp overflow). Shared SoA
5buffers and parse helpers live in :mod:`evutils.io._native_core`.
6"""
7from __future__ import annotations
8import ctypes
9from ctypes import POINTER, c_uint32, cast as c_cast, c_char, c_void_p, byref
10from typing import cast
11import numpy as np
12from ._native_core import register_bindings, NativeError, EventSoABuffers, TriggerSoABuffers, ParserResult, lib
14class DatInputBuffer(ctypes.Structure):
15 _fields_ = [("begin", POINTER(c_uint32)), ("end", POINTER(c_uint32))]
17class DatInput:
18 __slots__ = ("arr", "c")
19 def __init__(self, words: np.ndarray):
20 if words.dtype != np.uint32 or not words.flags["C_CONTIGUOUS"]: raise NativeError("DatInput needs a C-contiguous uint32 array")
21 self.arr = words
22 base = words.ctypes.data
23 self.c = DatInputBuffer()
24 self.c.begin = c_cast(base, POINTER(c_uint32))
25 self.c.end = c_cast(base + words.nbytes, POINTER(c_uint32))
26 def consumed(self, result: ParserResult) -> int:
27 cur = c_cast(result.current, c_void_p).value or self.arr.ctypes.data
28 return (cur - self.arr.ctypes.data) // 4
30def _bind_dat(handle: ctypes.CDLL) -> None:
31 from ._native_core import EventBufferSOA, TriggerBufferSOA, ParserResult
32 if hasattr(handle, "DAT_state_size"):
33 handle.DAT_state_size.argtypes = []
34 handle.DAT_state_size.restype = ctypes.c_size_t
35 if hasattr(handle, "DAT_parse_chunk_soa"):
36 handle.DAT_parse_chunk_soa.argtypes = [c_void_p, POINTER(DatInputBuffer), POINTER(EventBufferSOA), POINTER(TriggerBufferSOA)]
37 handle.DAT_parse_chunk_soa.restype = ParserResult
39register_bindings(_bind_dat)
41class DatParser:
42 __slots__ = ("_state", "_buf")
43 def __init__(self) -> None:
44 self._buf = (c_char * int(lib().DAT_state_size()))()
45 self._state = c_cast(self._buf, c_void_p)
46 def reset(self) -> None:
47 ctypes.memset(self._buf, 0, len(self._buf))
48 def parse_chunk_soa(self, inp: DatInput, events: EventSoABuffers, triggers: TriggerSoABuffers) -> ParserResult:
49 return cast(ParserResult, lib().DAT_parse_chunk_soa(self._state, byref(inp.c), byref(events.c), byref(triggers.c)))
50 def __enter__(self) -> "DatParser": return self