Source code for libretro.api.memory

"""Types that describe the address space of the :class:`.Core`'s emulated memory."""

from __future__ import annotations

from ctypes import POINTER, Structure, c_char_p, c_size_t, c_uint, c_uint64
from dataclasses import dataclass
from enum import IntFlag
from typing import overload

from libretro.ctypes import TypedPointer, c_void_ptr

from ._utils import MemoDict, deepcopy_array

RETRO_MEMORY_MASK = 0xFF
"""Mask for extracting the memory type from a memory ID."""

RETRO_MEMORY_SAVE_RAM = 0
"""Identifier for save RAM (battery-backed SRAM)."""

RETRO_MEMORY_RTC = 1
"""Identifier for real-time clock memory."""

RETRO_MEMORY_SYSTEM_RAM = 2
"""Identifier for main system RAM."""

RETRO_MEMORY_VIDEO_RAM = 3
"""Identifier for video RAM."""


RETRO_MEMDESC_CONST = 1 << 0
RETRO_MEMDESC_BIGENDIAN = 1 << 1
RETRO_MEMDESC_SYSTEM_RAM = 1 << 2
RETRO_MEMDESC_SAVE_RAM = 1 << 3
RETRO_MEMDESC_VIDEO_RAM = 1 << 4
RETRO_MEMDESC_ALIGN_2 = 1 << 16
RETRO_MEMDESC_ALIGN_4 = 2 << 16
RETRO_MEMDESC_ALIGN_8 = 3 << 16
RETRO_MEMDESC_MINSIZE_2 = 1 << 24
RETRO_MEMDESC_MINSIZE_4 = 2 << 24
RETRO_MEMDESC_MINSIZE_8 = 3 << 24


[docs] class MemoryDescriptorFlag(IntFlag): """ Flags that describe properties of a :class:`retro_memory_descriptor`. Corresponds to the ``RETRO_MEMDESC_*`` constants in ``libretro.h``. >>> from libretro.api import MemoryDescriptorFlag >>> MemoryDescriptorFlag.CONST <MemoryDescriptorFlag.CONST: 1> >>> MemoryDescriptorFlag.BIGENDIAN | MemoryDescriptorFlag.SAVE_RAM <MemoryDescriptorFlag.SAVE_RAM|BIGENDIAN: 10> """ CONST = RETRO_MEMDESC_CONST BIGENDIAN = RETRO_MEMDESC_BIGENDIAN SYSTEM_RAM = RETRO_MEMDESC_SYSTEM_RAM SAVE_RAM = RETRO_MEMDESC_SAVE_RAM VIDEO_RAM = RETRO_MEMDESC_VIDEO_RAM ALIGN_2 = RETRO_MEMDESC_ALIGN_2 ALIGN_4 = RETRO_MEMDESC_ALIGN_4 ALIGN_8 = RETRO_MEMDESC_ALIGN_8 MINSIZE_2 = RETRO_MEMDESC_MINSIZE_2 MINSIZE_4 = RETRO_MEMDESC_MINSIZE_4 MINSIZE_8 = RETRO_MEMDESC_MINSIZE_8
[docs] @dataclass(init=False, slots=True) class retro_memory_descriptor(Structure): """ Describes a region of emulated memory. Corresponds to :c:type:`retro_memory_descriptor` in ``libretro.h``. >>> from libretro.api import retro_memory_descriptor >>> desc = retro_memory_descriptor() >>> desc.start 0 >>> desc.ptr is None True """ flags: MemoryDescriptorFlag """Bitwise OR of :class:`MemoryDescriptorFlag` values describing this region.""" ptr: c_void_ptr | None """Pointer to the start of this memory region in the host's address space.""" offset: int """Offset relative to :attr:`ptr`.""" start: int """ Starting address within the emulated hardware's address space. .. note:: This is not represented as a pointer because it's not necessarily valid in the host's address space. """ select: int """Bitmask of address bits that must match :attr:`start`.""" disconnect: int """Bitmask of address bits not used for addressing.""" len: int """Length of this memory region in bytes.""" addrspace: bytes | None """Short name for this address space.""" _fields_ = ( ("flags", c_uint64), ("ptr", c_void_ptr), ("offset", c_size_t), ("start", c_size_t), ("select", c_size_t), ("disconnect", c_size_t), ("len", c_size_t), ("addrspace", c_char_p), )
[docs] def __deepcopy__(self, _): """ Return a deep copy of this object, including all subobjects and strings. Intended for use with :func:`copy.deepcopy`. >>> import copy >>> from libretro.api import retro_memory_descriptor >>> copy.deepcopy(retro_memory_descriptor()).start 0 """ return retro_memory_descriptor( flags=self.flags, ptr=self.ptr, offset=self.offset, start=self.start, select=self.select, disconnect=self.disconnect, len=self.len, addrspace=self.addrspace, )
# TODO: Implement __getitem__, __setitem__ # TODO: Implement a buffer property (not __buffer__ because Structure provides that)
[docs] @dataclass(init=False, slots=True) class retro_memory_map(Structure): r""" A collection of :class:`retro_memory_descriptor`\s that define the address space of the :class:`.Core`'s emulated memory. Corresponds to :c:type:`retro_memory_map` in ``libretro.h``. >>> from libretro.api import retro_memory_map >>> m = retro_memory_map() >>> len(m) 0 """ descriptors: TypedPointer[retro_memory_descriptor] | None """Array of memory descriptors.""" num_descriptors: int """Number of entries in :attr:`descriptors`.""" _fields_ = ( ("descriptors", POINTER(retro_memory_descriptor)), ("num_descriptors", c_uint), )
[docs] def __len__(self): """ Return the number of memory descriptors. >>> from libretro.api import retro_memory_map >>> len(retro_memory_map()) 0 """ return self.num_descriptors
@overload def __getitem__(self, item: int) -> retro_memory_descriptor: ... @overload def __getitem__( self, item: slice[retro_memory_descriptor] ) -> list[retro_memory_descriptor]: ...
[docs] def __getitem__( self, item: int | slice[retro_memory_descriptor] ) -> retro_memory_descriptor | list[retro_memory_descriptor]: """ Return a descriptor by index or a list of descriptors by slice. :param item: An integer index or slice. :returns: A single :class:`retro_memory_descriptor` or a list of them. :raises IndexError: If the index is out of range. :raises RuntimeError: If no descriptors are available. """ if isinstance(item, int): if item < 0 or item >= self.num_descriptors: raise IndexError(f"Expected 0 <= index < {self.num_descriptors}, got {item}") # TODO: Validate the slice (not just the start and stop, but also the step) if not self.descriptors: raise RuntimeError("Memory map has no descriptors") return self.descriptors[item]
[docs] def __deepcopy__(self, memodict: MemoDict = None): """ Return a deep copy of this object, including all subobjects and strings. Intended for use with :func:`copy.deepcopy`. >>> import copy >>> from libretro.api import retro_memory_map >>> copy.deepcopy(retro_memory_map()).num_descriptors 0 """ return retro_memory_map( descriptors=deepcopy_array(self.descriptors, self.num_descriptors, memodict), num_descriptors=self.num_descriptors, )
__all__ = [ "retro_memory_descriptor", "retro_memory_map", "MemoryDescriptorFlag", "RETRO_MEMORY_MASK", "RETRO_MEMORY_SAVE_RAM", "RETRO_MEMORY_RTC", "RETRO_MEMORY_SYSTEM_RAM", "RETRO_MEMORY_VIDEO_RAM", ]