1
1
import enum as py_enum
2
2
import warnings
3
+ import operator
3
4
4
- from ..hdl .ast import Value , Shape , ShapeCastable , Const
5
+ from ..hdl .ast import Value , ValueCastable , Shape , ShapeCastable , Const
5
6
6
7
7
- __all__ = py_enum .__all__
8
+ __all__ = py_enum .__all__ + [ "EnumView" , "FlagView" ]
8
9
9
10
10
11
for _member in py_enum .__all__ :
@@ -136,7 +137,12 @@ def __call__(cls, value, *args, **kwargs):
136
137
# and is backwards-compatible but is limiting in that it does not allow us to e.g. catch
137
138
# comparisons with enum members of the wrong type.
138
139
if isinstance (value , Value ):
139
- return value
140
+ if issubclass (cls , (IntEnum , IntFlag )):
141
+ return value
142
+ elif issubclass (cls , Flag ):
143
+ return FlagView (cls , value )
144
+ else :
145
+ return EnumView (cls , value )
140
146
return super ().__call__ (value , * args , ** kwargs )
141
147
142
148
def const (cls , init ):
@@ -148,7 +154,7 @@ def const(cls, init):
148
154
member = cls (0 )
149
155
else :
150
156
member = cls (init )
151
- return Const (member .value , cls .as_shape ())
157
+ return cls ( Const (member .value , cls .as_shape () ))
152
158
153
159
154
160
class Enum (py_enum .Enum ):
@@ -176,3 +182,114 @@ class IntFlag(py_enum.IntFlag):
176
182
IntEnum .__class__ = EnumMeta
177
183
Flag .__class__ = EnumMeta
178
184
IntFlag .__class__ = EnumMeta
185
+
186
+
187
+ class EnumView (ValueCastable ):
188
+ def __init__ (self , enum , target ):
189
+ if not isinstance (enum , EnumMeta ) or not hasattr (enum , "_amaranth_shape_" ):
190
+ raise TypeError (f"EnumView enum must be an enum, not { enum !r} " )
191
+ try :
192
+ cast_target = Value .cast (target )
193
+ except TypeError as e :
194
+ raise TypeError ("EnumView target must be a value-castable object, not {!r}"
195
+ .format (target )) from e
196
+ if cast_target .shape () != enum .as_shape ():
197
+ raise TypeError ("EnumView target must have the same shape as the enum" )
198
+ self .enum = enum
199
+ self .target = cast_target
200
+
201
+ def shape (self ):
202
+ return self .enum
203
+
204
+ @ValueCastable .lowermethod
205
+ def as_value (self ):
206
+ return self .target
207
+
208
+ def eq (self , other ):
209
+ """Assign to the underlying value.
210
+
211
+ Returns
212
+ -------
213
+ :class:`Assign`
214
+ ``self.as_value().eq(other)``
215
+ """
216
+ return self .as_value ().eq (other )
217
+
218
+ def __add__ (self , other ):
219
+ raise TypeError ("cannot perform arithmetic operations on non-IntEnum enum" )
220
+
221
+ __radd__ = __add__
222
+ __sub__ = __add__
223
+ __rsub__ = __add__
224
+ __mul__ = __add__
225
+ __rmul__ = __add__
226
+ __floordiv__ = __add__
227
+ __rfloordiv__ = __add__
228
+ __mod__ = __add__
229
+ __rmod__ = __add__
230
+ __lshift__ = __add__
231
+ __rlshift__ = __add__
232
+ __rshift__ = __add__
233
+ __rrshift__ = __add__
234
+ __lt__ = __add__
235
+ __le__ = __add__
236
+ __gt__ = __add__
237
+ __ge__ = __add__
238
+
239
+ def __and__ (self , other ):
240
+ raise TypeError ("cannot perform bitwise operations on non-IntEnum non-Flag enum" )
241
+
242
+ __rand__ = __and__
243
+ __or__ = __and__
244
+ __ror__ = __and__
245
+ __xor__ = __and__
246
+ __rxor__ = __and__
247
+
248
+ def __eq__ (self , other ):
249
+ if isinstance (other , self .enum ):
250
+ other = self .enum (Value .cast (other ))
251
+ if not isinstance (other , EnumView ) or other .enum is not self .enum :
252
+ raise TypeError ("an EnumView can only be compared to value or other EnumView of the same enum type" )
253
+ return self .target == other .target
254
+
255
+ def __ne__ (self , other ):
256
+ if isinstance (other , self .enum ):
257
+ other = self .enum (Value .cast (other ))
258
+ if not isinstance (other , EnumView ) or other .enum is not self .enum :
259
+ raise TypeError ("an EnumView can only be compared to value or other EnumView of the same enum type" )
260
+ return self .target != other .target
261
+
262
+ def __repr__ (self ):
263
+ return f"({ type (self ).__name__ } { self .enum .__name__ } { self .target !r} )"
264
+
265
+
266
+ class FlagView (EnumView ):
267
+ def __invert__ (self ):
268
+ if hasattr (self .enum , "_boundary_" ) and self .enum ._boundary_ in (EJECT , KEEP ):
269
+ return FlagView (self .enum , ~ self .target )
270
+ else :
271
+ singles_mask = 0
272
+ for flag in self .enum :
273
+ if (flag .value & (flag .value - 1 )) == 0 :
274
+ singles_mask |= flag .value
275
+ return FlagView (self .enum , ~ self .target & singles_mask )
276
+
277
+ def __bitop (self , other , op ):
278
+ if isinstance (other , self .enum ):
279
+ other = self .enum (Value .cast (other ))
280
+ if not isinstance (other , FlagView ) or other .enum is not self .enum :
281
+ raise TypeError ("a FlagView can only perform bitwise operation with a value or other FlagView of the same enum type" )
282
+ return FlagView (self .enum , op (self .target , other .target ))
283
+
284
+ def __and__ (self , other ):
285
+ return self .__bitop (other , operator .__and__ )
286
+
287
+ def __or__ (self , other ):
288
+ return self .__bitop (other , operator .__or__ )
289
+
290
+ def __xor__ (self , other ):
291
+ return self .__bitop (other , operator .__xor__ )
292
+
293
+ __rand__ = __and__
294
+ __ror__ = __or__
295
+ __rxor__ = __xor__
0 commit comments