4"""Port-kind strategy table for the C++ module generator.
6Centralises everything that varies between the ESI port kinds (function,
7callback, to-host / from-host channel, MMIO region, telemetry metric, plain
8bundle) into a single `CppPortKind` record per kind plus two pure rendering
9functions, so the generator drives every port kind from one table. The
10renderers are pure functions of a `CppPortKind`, so they are golden-tested
11without a live accelerator.
14from dataclasses
import dataclass, field
as _dc_field
15from typing
import List, Optional, Tuple
17from ..types
import (BundlePort
as _BundlePort, FunctionPort
as _FunctionPort,
18 CallbackPort
as _CallbackPort, ToHostPort
as _ToHostPort,
19 FromHostPort
as _FromHostPort, MMIORegion
as
20 _MMIORegionPort, MetricPort
as _MetricPort)
25 """All strings needed to emit one port slot (member + ctor + find) in Connected."""
26 struct_decls: List[str] = _dc_field(default_factory=list)
28 ctor_params: List[str] = _dc_field(default_factory=list)
31 make_unique_args: List[str] = _dc_field(default_factory=list)
32 post_connect: str =
""
33 using_aliases: List[Tuple[str, str]] = _dc_field(default_factory=list)
36@dataclass(frozen=True)
38 """Per-port-kind constants for generating a module's typed port slots.
40 Holds everything that varies between port kinds in one record.
41 `member_template` (typed channel/func ports) and `member_ref` (service /
42 bundle ports) are mutually exclusive. `find_style` / `indexed_find` select
43 the `connect()` resolution snippet for scalar and indexed ports
44 respectively; `alias_kind` selects which `using` aliases to emit for the
45 typed template parameters.
47 service_type: Optional[
53 member_template: Optional[
55 member_ref: Optional[str]
56 indexed_elem: Optional[
58 alias_kind: Optional[str]
61 def member_type(self, alias_prefix: Optional[str] =
None) -> str:
62 """Return the C++ member type string for this kind (no member name).
64 For typed ports (function/callback/to-host/from-host channels)
65 `alias_prefix` is required; the returned template parameters are written
66 using the alias names (`<prefix>Args`, `<prefix>Result`, `<prefix>Data`)
67 that should be emitted at module-class scope. For non-typed ports (MMIO
68 regions, telemetry metrics, plain bundles) `alias_prefix` is ignored and
69 the runtime reference/pointer type is returned directly.
72 assert alias_prefix
is not None, (
73 "alias_prefix is required for typed ports to avoid emitting long "
74 "mangled type names inline (which would also collide across "
75 "modules' `using` declarations)")
82 """Return the storage type used inside an `IndexedPorts<T>` for this kind.
84 Typed ports use the same `TypedFunction<...>` / `TypedReadPort<...>` etc.
85 that `member_type` produces. MMIO regions, telemetry metrics, and plain
86 bundle ports are stored as raw pointers because `std::map<int, T&>` is
94 """Render the connect()-body snippet that resolves one scalar port into the
95 local `v`. Pure function of the kind so it can be golden-tested without a
96 live accelerator (see `test_port_find_code_golden`)."""
98 return (f
"auto *{v} =\n"
99 f
" esi::findPortAsOrThrow<{self.service_type}>(\n"
100 f
" rawModule, {appid_expr});")
102 return (f
"auto &{v} =\n"
103 f
" esi::findPortAsOrThrow<{self.service_type}>(\n"
104 f
' rawModule, {appid_expr})->getRawRead("data");')
106 return (f
"auto &{v} =\n"
107 f
" esi::findPortAsOrThrow<{self.service_type}>(\n"
108 f
' rawModule, {appid_expr})->getRawWrite("data");')
110 return (f
"auto &{v} =\n"
111 f
" *esi::findPortAsOrThrow<{self.service_type}>(\n"
112 f
" rawModule, {appid_expr});")
115 return f
"auto &{v} = esi::findPortOrThrow(rawModule, {appid_expr});"
116 raise ValueError(f
"unknown find_style: {self.find_style!r}")
119 """Render the per-index `try_emplace` body for an `IndexedPorts<T>` group.
120 Pure function of the kind (golden-tested alongside `scalar_find_code`)."""
122 return (f
" {map_var}.try_emplace(\n"
123 f
" static_cast<int>(idx),\n"
124 f
" esi::findPortAsOrThrow<{self.service_type}>(\n"
125 f
" rawModule, {appid_expr}));")
127 return (f
" auto *svc =\n"
128 f
" esi::findPortAsOrThrow<{self.service_type}>(\n"
129 f
" rawModule, {appid_expr});\n"
130 f
" {map_var}.try_emplace(\n"
131 f
" static_cast<int>(idx),\n"
132 f
' svc->getRawRead("data"));')
134 return (f
" auto *svc =\n"
135 f
" esi::findPortAsOrThrow<{self.service_type}>(\n"
136 f
" rawModule, {appid_expr});\n"
137 f
" {map_var}.try_emplace(\n"
138 f
" static_cast<int>(idx),\n"
139 f
' svc->getRawWrite("data"));')
141 return (f
" {map_var}.try_emplace(\n"
142 f
" static_cast<int>(idx),\n"
143 f
" &esi::findPortOrThrow(rawModule, {appid_expr}));")
144 raise ValueError(f
"unknown indexed_find: {self.indexed_find!r}")
149CPP_PORT_KINDS: List[Tuple[type, CppPortKind]] = [
151 CppPortKind(service_type=
"esi::services::FuncService::Function",
153 indexed_find=
"as_ptr",
154 param_type=
"esi::services::FuncService::Function *",
155 param_suffix=
"_port",
156 member_template=
"esi::TypedFunction<{p}Args, {p}Result>",
162 CppPortKind(service_type=
"esi::services::CallService::Callback",
164 indexed_find=
"as_ptr",
165 param_type=
"esi::services::CallService::Callback *",
166 param_suffix=
"_port",
167 member_template=
"esi::TypedCallback<{p}Args, {p}Result>",
173 CppPortKind(service_type=
"esi::services::ChannelService::ToHost",
174 find_style=
"read_chan",
175 indexed_find=
"chan_read",
176 param_type=
"esi::ReadChannelPort &",
177 param_suffix=
"_chan",
178 member_template=
"esi::TypedReadPort<{p}Data>",
184 CppPortKind(service_type=
"esi::services::ChannelService::FromHost",
185 find_style=
"write_chan",
186 indexed_find=
"chan_write",
187 param_type=
"esi::WriteChannelPort &",
188 param_suffix=
"_chan",
189 member_template=
"esi::TypedWritePort<{p}Data>",
195 CppPortKind(service_type=
"esi::services::MMIO::MMIORegion",
197 indexed_find=
"as_ptr",
198 param_type=
"esi::services::MMIO::MMIORegion &",
200 member_template=
None,
201 member_ref=
"esi::services::MMIO::MMIORegion &",
202 indexed_elem=
"esi::services::MMIO::MMIORegion *",
206 CppPortKind(service_type=
"esi::services::TelemetryService::Metric",
208 indexed_find=
"as_ptr",
209 param_type=
"esi::services::TelemetryService::Metric &",
211 member_template=
None,
212 member_ref=
"esi::services::TelemetryService::Metric &",
213 indexed_elem=
"esi::services::TelemetryService::Metric *",
222 indexed_find=
"bundle_addr",
223 param_type=
"esi::BundlePort &",
224 param_suffix=
"_port",
225 member_template=
None,
226 member_ref=
"esi::BundlePort &",
227 indexed_elem=
"esi::BundlePort *",
232def cpp_port_kind(port: _BundlePort) -> CppPortKind:
233 """Return the `CppPortKind` describing `port`, or `CPP_BUNDLE_KIND` as fallback."""
234 for cls, kind
in CPP_PORT_KINDS:
235 if isinstance(port, cls):
237 return CPP_BUNDLE_KIND
str indexed_elem_type(self, Optional[str] alias_prefix=None)
str indexed_find_code(self, str map_var, str appid_expr)
str scalar_find_code(self, str v, str appid_expr)
str member_type(self, Optional[str] alias_prefix=None)