Skip to content

Commit 7455a55

Browse files
authored
Use enum.Flag for qualities in IDL parsing - clearer than using a set (project-chip#23020)
* Use enum.Flag for qualities in IDL parsing - clearer than using a set * Update the syntax of union a bit: accept None and use or syntax to specify default value
1 parent d1ceab1 commit 7455a55

File tree

7 files changed

+95
-87
lines changed

7 files changed

+95
-87
lines changed

scripts/idl/generators/java/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ def FieldToGlobalName(field: Field, context: TypeLookupContext) -> Union[str, No
3131
if field.is_list:
3232
return None # lists are always specific per cluster
3333

34-
if FieldQuality.NULLABLE in field.qualities:
34+
if FieldQuality.NULLABLE & field.qualities:
3535
return None
3636

37-
if FieldQuality.OPTIONAL in field.qualities:
37+
if FieldQuality.OPTIONAL & field.qualities:
3838
return None
3939

4040
actual = ParseDataType(field.data_type, context)

scripts/idl/matter_idl_parser.py

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/env python
22

33
import enum
4+
import functools
45
import logging
56

67
from lark import Lark
@@ -16,6 +17,12 @@
1617
from matter_idl_types import *
1718

1819

20+
def UnionOfAllFlags(flags_list):
21+
if not flags_list:
22+
return None
23+
return functools.reduce(lambda a, b: a | b, flags_list)
24+
25+
1926
class AddServerClusterToEndpointTransform:
2027
"""Provides an 'apply' method that can be run on endpoints
2128
to add a server cluster to the given endpoint.
@@ -164,13 +171,13 @@ def attr_nosubscribe(self, _):
164171
return AttributeQuality.NOSUBSCRIBE
165172

166173
def attribute_qualities(self, qualities):
167-
return qualities
174+
return UnionOfAllFlags(qualities) or AttributeQuality.NONE
168175

169176
def struct_fabric_scoped(self, _):
170177
return StructQuality.FABRIC_SCOPED
171178

172179
def struct_qualities(self, qualities):
173-
return qualities
180+
return UnionOfAllFlags(qualities) or StructQuality.NONE
174181

175182
def critical_priority(self, _):
176183
return EventPriority.CRITICAL
@@ -185,7 +192,7 @@ def event_fabric_sensitive(self, _):
185192
return EventQuality.FABRIC_SENSITIVE
186193

187194
def event_qualities(selt, qualities):
188-
return set(qualities)
195+
return UnionOfAllFlags(qualities) or EventQuality.NONE
189196

190197
def timed_command(self, _):
191198
return CommandQuality.TIMED_INVOKE
@@ -194,14 +201,13 @@ def fabric_scoped_command(self, _):
194201
return CommandQuality.FABRIC_SCOPED
195202

196203
def command_qualities(self, attrs):
197-
# List because attrs is a tuple
198-
return set(list(attrs))
204+
return UnionOfAllFlags(attrs) or CommandQuality.NONE
199205

200206
def struct_field(self, args):
201207
# Last argument is the named_member, the rest
202208
# are qualities
203209
field = args[-1]
204-
field.qualities = set(args[:-1])
210+
field.qualities = UnionOfAllFlags(args[:-1]) or FieldQuality.NONE
205211
return field
206212

207213
def server_cluster(self, _):
@@ -317,22 +323,20 @@ def ESCAPED_STRING(self, s):
317323

318324
@v_args(inline=True)
319325
def attribute(self, qualities, definition_tuple):
320-
321-
qualities = set(qualities)
322326
(definition, acl) = definition_tuple
323327

324328
# until we support write only (and need a bit of a reshuffle)
325329
# if the 'attr_readonly == READABLE' is not in the list, we make things
326330
# read/write
327331
if AttributeQuality.READABLE not in qualities:
328-
qualities.add(AttributeQuality.READABLE)
329-
qualities.add(AttributeQuality.WRITABLE)
332+
qualities |= AttributeQuality.READABLE
333+
qualities |= AttributeQuality.WRITABLE
330334

331335
return Attribute(definition=definition, qualities=qualities, **acl)
332336

333337
@v_args(inline=True)
334338
def struct(self, qualities, id, *fields):
335-
return Struct(name=id, qualities=set(qualities), fields=list(fields))
339+
return Struct(name=id, qualities=qualities, fields=list(fields))
336340

337341
@v_args(inline=True)
338342
def request_struct(self, value):

scripts/idl/matter_idl_types.py

+22-17
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,26 @@ def __init__(self, meta: Meta = None, line: int = None, column: int = None):
2121
self.column = column
2222

2323

24-
class StructQuality(enum.Enum):
24+
class StructQuality(enum.Flag):
25+
NONE = 0
2526
FABRIC_SCOPED = enum.auto()
2627

2728

28-
class FieldQuality(enum.Enum):
29+
class FieldQuality(enum.Flag):
30+
NONE = 0
2931
OPTIONAL = enum.auto()
3032
NULLABLE = enum.auto()
3133
FABRIC_SENSITIVE = enum.auto()
3234

3335

34-
class CommandQuality(enum.Enum):
36+
class CommandQuality(enum.Flag):
37+
NONE = 0
3538
TIMED_INVOKE = enum.auto()
3639
FABRIC_SCOPED = enum.auto()
3740

3841

39-
class AttributeQuality(enum.Enum):
42+
class AttributeQuality(enum.Flag):
43+
NONE = 0
4044
READABLE = enum.auto()
4145
WRITABLE = enum.auto()
4246
NOSUBSCRIBE = enum.auto()
@@ -54,7 +58,8 @@ class EventPriority(enum.Enum):
5458
CRITICAL = enum.auto()
5559

5660

57-
class EventQuality(enum.Enum):
61+
class EventQuality(enum.Flag):
62+
NONE = 0
5863
FABRIC_SENSITIVE = enum.auto()
5964

6065

@@ -99,36 +104,36 @@ class Field:
99104
code: int
100105
name: str
101106
is_list: bool = False
102-
qualities: Set[FieldQuality] = field(default_factory=set)
107+
qualities: FieldQuality = FieldQuality.NONE
103108

104109
@property
105110
def is_optional(self):
106-
return FieldQuality.OPTIONAL in self.qualities
111+
return FieldQuality.OPTIONAL & self.qualities
107112

108113
@property
109114
def is_nullable(self):
110-
return FieldQuality.NULLABLE in self.qualities
115+
return FieldQuality.NULLABLE & self.qualities
111116

112117

113118
@dataclass
114119
class Attribute:
115120
definition: Field
116-
qualities: Set[AttributeQuality] = field(default_factory=set)
121+
qualities: AttributeQuality = AttributeQuality.NONE
117122
readacl: AccessPrivilege = AccessPrivilege.VIEW
118123
writeacl: AccessPrivilege = AccessPrivilege.OPERATE
119124
default: Optional[Union[str, int]] = None
120125

121126
@property
122127
def is_readable(self):
123-
return AttributeQuality.READABLE in self.qualities
128+
return AttributeQuality.READABLE & self.qualities
124129

125130
@property
126131
def is_writable(self):
127-
return AttributeQuality.WRITABLE in self.qualities
132+
return AttributeQuality.WRITABLE & self.qualities
128133

129134
@property
130135
def is_subscribable(self):
131-
return AttributeQuality.NOSUBSCRIBE not in self.qualities
136+
return not (AttributeQuality.NOSUBSCRIBE & self.qualities)
132137

133138

134139
@dataclass
@@ -137,7 +142,7 @@ class Struct:
137142
fields: List[Field]
138143
tag: Optional[StructTag] = None
139144
code: Optional[int] = None # for responses only
140-
qualities: Set[StructQuality] = field(default_factory=set)
145+
qualities: StructQuality = StructQuality.NONE
141146

142147

143148
@dataclass
@@ -147,11 +152,11 @@ class Event:
147152
code: int
148153
fields: List[Field]
149154
readacl: AccessPrivilege = AccessPrivilege.VIEW
150-
qualities: Set[EventQuality] = field(default_factory=set)
155+
qualities: EventQuality = EventQuality.NONE
151156

152157
@property
153158
def is_fabric_sensitive(self):
154-
return EventQuality.FABRIC_SENSITIVE in self.qualities
159+
return EventQuality.FABRIC_SENSITIVE & self.qualities
155160

156161

157162
@dataclass
@@ -180,12 +185,12 @@ class Command:
180185
code: int
181186
input_param: Optional[str]
182187
output_param: str
183-
qualities: Set[CommandQuality] = field(default_factory=set)
188+
qualities: CommandQuality = CommandQuality.NONE
184189
invokeacl: AccessPrivilege = AccessPrivilege.OPERATE
185190

186191
@property
187192
def is_timed_invoke(self):
188-
return CommandQuality.TIMED_INVOKE in self.qualities
193+
return CommandQuality.TIMED_INVOKE & self.qualities
189194

190195

191196
@dataclass

scripts/idl/test_matter_idl_parser.py

+28-29
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,11 @@ def test_global_struct(self):
7979
fields=[
8080
Field(
8181
data_type=DataType(name="CHAR_STRING"), code=1, name="astring", ),
82-
Field(data_type=DataType(name="CLUSTER_ID"), code=2, name="idlist", is_list=True, qualities=set(
83-
[FieldQuality.OPTIONAL])),
84-
Field(data_type=DataType(name="int"), code=0x123, name="valueThatIsNullable", qualities=set(
85-
[FieldQuality.NULLABLE])),
82+
Field(data_type=DataType(name="CLUSTER_ID"), code=2, name="idlist",
83+
is_list=True, qualities=FieldQuality.OPTIONAL),
84+
Field(data_type=DataType(name="int"), code=0x123, name="valueThatIsNullable", qualities=FieldQuality.NULLABLE),
8685
Field(data_type=DataType(name="char_string", max_length=123),
87-
code=222, name="sized_string", qualities=set()),
86+
code=222, name="sized_string"),
8887
])]
8988
)
9089
self.assertEqual(actual, expected)
@@ -100,14 +99,14 @@ def test_fabric_scoped_struct(self):
10099

101100
expected = Idl(structs=[
102101
Struct(name='FabricStruct',
103-
qualities={StructQuality.FABRIC_SCOPED},
102+
qualities=StructQuality.FABRIC_SCOPED,
104103
fields=[
105104
Field(
106105
data_type=DataType(name="CHAR_STRING"), code=1, name="astring", ),
107-
Field(data_type=DataType(name="CLUSTER_ID"), code=2, name="idlist", is_list=True, qualities=set(
108-
[FieldQuality.OPTIONAL])),
109-
Field(data_type=DataType(name="int"), code=0x123, name="nullablesensitive", qualities=set(
110-
[FieldQuality.NULLABLE, FieldQuality.FABRIC_SENSITIVE])),
106+
Field(data_type=DataType(name="CLUSTER_ID"), code=2, name="idlist",
107+
is_list=True, qualities=FieldQuality.OPTIONAL),
108+
Field(data_type=DataType(name="int"), code=0x123, name="nullablesensitive",
109+
qualities=FieldQuality.NULLABLE | FieldQuality.FABRIC_SENSITIVE),
111110
])]
112111
)
113112
self.assertEqual(actual, expected)
@@ -127,14 +126,14 @@ def test_cluster_attribute(self):
127126
name="MyCluster",
128127
code=0x321,
129128
attributes=[
130-
Attribute(qualities=set([AttributeQuality.READABLE]), definition=Field(
129+
Attribute(qualities=AttributeQuality.READABLE, definition=Field(
131130
data_type=DataType(name="int8u"), code=1, name="roAttr")),
132-
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
131+
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
133132
data_type=DataType(name="int32u"), code=123, name="rwAttr", is_list=True)),
134-
Attribute(qualities=set([AttributeQuality.NOSUBSCRIBE, AttributeQuality.READABLE]), definition=Field(
133+
Attribute(qualities=AttributeQuality.NOSUBSCRIBE | AttributeQuality.READABLE, definition=Field(
135134
data_type=DataType(name="int8s"), code=0xAA, name="nosub", is_list=True)),
136-
Attribute(qualities=set([AttributeQuality.READABLE]), definition=Field(
137-
data_type=DataType(name="int8s"), code=0xAB, name="isNullable", qualities=set([FieldQuality.NULLABLE]))),
135+
Attribute(qualities=AttributeQuality.READABLE, definition=Field(
136+
data_type=DataType(name="int8s"), code=0xAB, name="isNullable", qualities=FieldQuality.NULLABLE)),
138137
]
139138
)])
140139
self.assertEqual(actual, expected)
@@ -152,9 +151,9 @@ def test_sized_attribute(self):
152151
name="MyCluster",
153152
code=1,
154153
attributes=[
155-
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
154+
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
156155
data_type=DataType(name="char_string", max_length=11), code=1, name="attr1")),
157-
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
156+
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
158157
data_type=DataType(name="octet_string", max_length=33), code=2, name="attr2", is_list=True)),
159158
]
160159
)])
@@ -176,25 +175,25 @@ def test_attribute_access(self):
176175
name="MyCluster",
177176
code=1,
178177
attributes=[
179-
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
178+
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
180179
data_type=DataType(name="int8s"), code=1, name="attr1"),
181180
readacl=AccessPrivilege.VIEW,
182181
writeacl=AccessPrivilege.OPERATE
183182
),
184-
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
183+
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
185184
data_type=DataType(name="int8s"), code=2, name="attr2"),
186185
readacl=AccessPrivilege.VIEW,
187186
writeacl=AccessPrivilege.OPERATE
188187
),
189-
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
188+
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
190189
data_type=DataType(name="int8s"), code=3, name="attr3"),
191190
readacl=AccessPrivilege.MANAGE
192191
),
193-
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
192+
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
194193
data_type=DataType(name="int8s"), code=4, name="attr4"),
195194
writeacl=AccessPrivilege.ADMINISTER
196195
),
197-
Attribute(qualities=set([AttributeQuality.READABLE, AttributeQuality.WRITABLE]), definition=Field(
196+
Attribute(qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, definition=Field(
198197
data_type=DataType(name="int8s"), code=5, name="attr5"),
199198
readacl=AccessPrivilege.OPERATE,
200199
writeacl=AccessPrivilege.MANAGE
@@ -234,13 +233,13 @@ def test_cluster_commands(self):
234233
input_param="InParam", output_param="OutParam"),
235234
Command(name="TimedCommand", code=0xab,
236235
input_param="InParam", output_param="DefaultSuccess",
237-
qualities=set([CommandQuality.TIMED_INVOKE])),
236+
qualities=CommandQuality.TIMED_INVOKE),
238237
Command(name="FabricScopedCommand", code=0xac,
239238
input_param="InParam", output_param="DefaultSuccess",
240-
qualities=set([CommandQuality.FABRIC_SCOPED])),
239+
qualities=CommandQuality.FABRIC_SCOPED),
241240
Command(name="FabricScopedTimedCommand", code=0xad,
242241
input_param="InParam", output_param="DefaultSuccess",
243-
qualities=set([CommandQuality.TIMED_INVOKE, CommandQuality.FABRIC_SCOPED])),
242+
qualities=CommandQuality.TIMED_INVOKE | CommandQuality.FABRIC_SCOPED),
244243
],
245244
)])
246245
self.assertEqual(actual, expected)
@@ -272,7 +271,7 @@ def test_cluster_command_access(self):
272271
Command(name="TimedCommand", code=2,
273272
input_param="InParam", output_param="OutParam",
274273
invokeacl=AccessPrivilege.MANAGE,
275-
qualities=set([CommandQuality.TIMED_INVOKE])),
274+
qualities=CommandQuality.TIMED_INVOKE),
276275
Command(name="OutOnly", code=3,
277276
input_param=None, output_param="OutParam",
278277
invokeacl=AccessPrivilege.ADMINISTER,
@@ -387,11 +386,11 @@ def test_fabric_sensitive_event(self):
387386
code=0x123,
388387
events=[
389388
Event(priority=EventPriority.INFO, readacl=AccessPrivilege.VIEW,
390-
name="Hello", code=1, fields=[], qualities={EventQuality.FABRIC_SENSITIVE}),
389+
name="Hello", code=1, fields=[], qualities=EventQuality.FABRIC_SENSITIVE),
391390
Event(priority=EventPriority.DEBUG, readacl=AccessPrivilege.MANAGE,
392-
name="GoodBye", code=2, fields=[], qualities={EventQuality.FABRIC_SENSITIVE}),
391+
name="GoodBye", code=2, fields=[], qualities=EventQuality.FABRIC_SENSITIVE),
393392
Event(priority=EventPriority.DEBUG, readacl=AccessPrivilege.ADMINISTER,
394-
name="AdminEvent", code=3, fields=[], qualities={EventQuality.FABRIC_SENSITIVE}),
393+
name="AdminEvent", code=3, fields=[], qualities=EventQuality.FABRIC_SENSITIVE),
395394
])])
396395
self.assertEqual(actual, expected)
397396

0 commit comments

Comments
 (0)