|
13 | 13 | from enum import Enum, IntEnum, StrEnum, auto |
14 | 14 | from math import ceil, floor |
15 | 15 | from typing import ( |
16 | | - Any, Annotated, NamedTuple, Self, TYPE_CHECKING |
| 16 | + Any, Annotated, NamedTuple, Self, Iterator, Type, |
| 17 | + TYPE_CHECKING |
17 | 18 | ) |
18 | 19 | from typing_extensions import ( |
19 | 20 | TypedDict, Unpack, NotRequired |
@@ -129,32 +130,47 @@ class IOModel(IOModelOptions): |
129 | 130 | width: int |
130 | 131 | direction: Annotated[io.Direction, PlainSerializer(lambda x: x.value)] |
131 | 132 |
|
132 | | -def io_annotation_schema(): |
133 | | - class Model(pydantic.BaseModel): |
134 | | - data_td: IOModel |
| 133 | +def amaranth_annotate(model: Type[TypedDict], schema_id: str): |
| 134 | + def annotation_schema(): |
| 135 | + class Model(pydantic.BaseModel): |
| 136 | + data_td: model |
135 | 137 |
|
136 | | - PydanticModel = TypeAdapter(IOModel) |
137 | | - schema = PydanticModel.json_schema() |
138 | | - schema['$schema'] = "https://json-schema.org/draft/2020-12/schema" |
139 | | - schema['$id'] = IO_ANNOTATION_SCHEMA |
140 | | - return schema |
| 138 | + PydanticModel = TypeAdapter(model) |
| 139 | + schema = PydanticModel.json_schema() |
| 140 | + schema['$schema'] = "https://json-schema.org/draft/2020-12/schema" |
| 141 | + schema['$id'] = schema_id |
| 142 | + return schema |
141 | 143 |
|
| 144 | + class Annotation(meta.Annotation): |
| 145 | + "Generated annotation class" |
| 146 | + schema = annotation_schema() |
142 | 147 |
|
143 | | -class _IOAnnotation(meta.Annotation): |
144 | | - "Infrastructure for `Amaranth annotations <amaranth.lib.meta.Annotation>`" |
145 | | - schema = io_annotation_schema() |
| 148 | + def __init__(self, model:IOModel): |
| 149 | + self._model = model |
146 | 150 |
|
147 | | - def __init__(self, model:IOModel): |
148 | | - self._model = model |
| 151 | + @property |
| 152 | + def origin(self): # type: ignore |
| 153 | + return self._model |
| 154 | + |
| 155 | + def as_json(self): # type: ignore |
| 156 | + return TypeAdapter(IOModel).dump_python(self._model) |
| 157 | + |
| 158 | + def annotations(self, *args): # type: ignore |
| 159 | + annotations = wiring.Signature.annotations(self, *args) # type: ignore |
| 160 | + |
| 161 | + io_annotation = Annotation(self._model) |
| 162 | + return annotations + (io_annotation,) # type: ignore |
149 | 163 |
|
150 | | - @property |
151 | | - def origin(self): # type: ignore |
152 | | - return self._model |
153 | 164 |
|
154 | | - def as_json(self): # type: ignore |
155 | | - return TypeAdapter(IOModel).dump_python(self._model) |
156 | 165 |
|
157 | 166 |
|
| 167 | + def decorator(klass): |
| 168 | + klass.annotations = annotations |
| 169 | + klass.__repr__ |
| 170 | + return klass |
| 171 | + return decorator |
| 172 | + |
| 173 | +@amaranth_annotate(IOModel, IO_ANNOTATION_SCHEMA) |
158 | 174 | class IOSignature(wiring.Signature): |
159 | 175 | """An :py:obj:`Amaranth Signature <amaranth.lib.wiring.Signature>` used to decorate wires that would usually be brought out onto a port on the package. |
160 | 176 | This class is generally not directly used. Instead, you would typically utilize the more specific |
@@ -224,17 +240,9 @@ def options(self) -> IOModelOptions: |
224 | 240 | """ |
225 | 241 | return self._model |
226 | 242 |
|
227 | | - def annotations(self, *args): # type: ignore |
228 | | - annotations = wiring.Signature.annotations(self, *args) # type: ignore |
229 | | - |
230 | | - io_annotation = _IOAnnotation(self._model) |
231 | | - return annotations + (io_annotation,) # type: ignore |
232 | | - |
233 | | - |
234 | 243 | def __repr__(self): |
235 | 244 | return f"IOSignature({','.join('{0}={1!r}'.format(k,v) for k,v in self._model.items())})" |
236 | 245 |
|
237 | | - |
238 | 246 | def OutputIOSignature(width: int, **kwargs: Unpack[IOModelOptions]): |
239 | 247 | """This creates an :py:obj:`Amaranth Signature <amaranth.lib.wiring.Signature>` which is then used to decorate package output signals |
240 | 248 | intended for connection to the physical pads of the integrated circuit package. |
|
0 commit comments