Coverage for src/evutils/io/_native_aer.py: 100%
48 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 AER parser.
3AER records carry no timestamps; :class:`AerParser` configures how ``t`` is
4generated (``AER_TS_ZERO`` or ``AER_TS_SEQUENTIAL``, carried across chunks).
5Shared SoA buffers 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, c_uint64, byref
10from typing import cast
11import numpy as np
12from ._native_core import register_bindings, NativeError, EventSoABuffers, TriggerSoABuffers, ParserResult, lib
14class AerInputBuffer(ctypes.Structure):
15 _fields_ = [("begin", POINTER(c_uint32)), ("end", POINTER(c_uint32))]
17class AerInput:
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("AerInput needs a C-contiguous uint32 array")
21 self.arr = words
22 base = words.ctypes.data
23 self.c = AerInputBuffer()
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
30AER_TS_ZERO = 0
31AER_TS_SEQUENTIAL = 1
33def _bind_aer(handle: ctypes.CDLL) -> None:
34 from ._native_core import EventBufferSOA, TriggerBufferSOA, ParserResult
35 if hasattr(handle, "AER_state_size"):
36 handle.AER_state_size.argtypes = []
37 handle.AER_state_size.restype = ctypes.c_size_t
38 if hasattr(handle, "AER_state_configure"):
39 handle.AER_state_configure.argtypes = [c_void_p, ctypes.c_int32, c_uint64, c_uint64]
40 handle.AER_state_configure.restype = None
41 if hasattr(handle, "AER_parse_chunk_soa"):
42 handle.AER_parse_chunk_soa.argtypes = [c_void_p, POINTER(AerInputBuffer), POINTER(EventBufferSOA), POINTER(TriggerBufferSOA)]
43 handle.AER_parse_chunk_soa.restype = ParserResult
45register_bindings(_bind_aer)
47class AerParser:
48 __slots__ = ("_state", "_buf", "_mode", "_t_start", "_t_step")
49 def __init__(self, mode: int = AER_TS_ZERO, t_start: int = 0, t_step: int = 1):
50 self._buf = (c_char * int(lib().AER_state_size()))()
51 self._state = c_cast(self._buf, c_void_p)
52 self._mode = mode
53 self._t_start = t_start
54 self._t_step = t_step
55 lib().AER_state_configure(self._state, mode, t_start, t_step)
56 def reset(self) -> None:
57 lib().AER_state_configure(self._state, self._mode, self._t_start, self._t_step)
58 def parse_chunk_soa(self, inp: AerInput, events: EventSoABuffers, triggers: TriggerSoABuffers) -> ParserResult:
59 return cast(ParserResult, lib().AER_parse_chunk_soa(self._state, byref(inp.c), byref(events.c), byref(triggers.c)))
60 def __enter__(self) -> "AerParser": return self