c-struct-data-parser 0.2.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: c-struct-data-parser
3
- Version: 0.2.0
3
+ Version: 0.4.0
4
4
  Summary: Declaratively define and parse C data structures
5
5
  Author: Gregory.Kuhn
6
6
  Author-email: Gregory.Kuhn <gregory.kuhn@analog.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "c-struct-data-parser"
3
- version = "0.2.0"
3
+ version = "0.4.0"
4
4
  description = "Declaratively define and parse C data structures"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -11,7 +11,7 @@ class BytesReader(Reader):
11
11
  read_bytes = self.bs[current : current + size]
12
12
  if len(read_bytes) < size:
13
13
  raise ValueError(f"Failed to read requested number of bytes: {size}")
14
- return (self.address + current, read_bytes), self.new_reader(self.address + size)
14
+ return (self.address, read_bytes), self.new_reader(self.address + size)
15
15
 
16
16
  def new_reader(self, address: int) -> Reader:
17
17
  delta = address - self.address
@@ -35,7 +35,7 @@ class DataDefinition(ABC):
35
35
 
36
36
  def __init__(
37
37
  self,
38
- metadata: Optional[Metadata],
38
+ metadata: Metadata,
39
39
  ):
40
40
  self.metadata = metadata
41
41
 
@@ -60,9 +60,8 @@ class IntDefinition(DataDefinition):
60
60
  def __init__(
61
61
  self,
62
62
  value: int | Enum,
63
- metadata: Optional[Metadata] = None,
63
+ metadata: Metadata = None,
64
64
  ):
65
-
66
65
  super().__init__(metadata)
67
66
  if isinstance(value, int):
68
67
  self.value = value
@@ -74,7 +73,13 @@ class IntDefinition(DataDefinition):
74
73
  @classmethod
75
74
  def parser(cls, reader: Reader) -> Tuple[IntDefinition, Reader]:
76
75
  (address, data_bytes), new_reader = reader.read(cls.size)
77
- return cls(int.from_bytes(data_bytes, byteorder=cls.byteorder), metadata=Metadata(address)), new_reader
76
+ return (
77
+ cls(
78
+ int.from_bytes(data_bytes, byteorder=cls.byteorder),
79
+ metadata=Metadata(address),
80
+ ),
81
+ new_reader,
82
+ )
78
83
 
79
84
  def __repr__(self) -> str:
80
85
  cls_name = type(self).__name__
@@ -96,9 +101,13 @@ class IntDefinition(DataDefinition):
96
101
  enum_type = self._enum_type
97
102
  if enum_type:
98
103
  try:
99
- val_str = repr(enum_type(val)) # repr(Enum(<num>)) looks more like str(Enum(<num>)) and vice versa
104
+ val_str = repr(
105
+ enum_type(val)
106
+ ) # repr(Enum(<num>)) looks more like str(Enum(<num>)) and vice versa
100
107
  except ValueError:
101
- val_str = f"{val:#x} ({val}) not a valid Enumeration of type: {enum_type}"
108
+ val_str = (
109
+ f"{val:#x} ({val}) not a valid Enumeration of type: {enum_type}"
110
+ )
102
111
  else:
103
112
  val_str = hex(val)
104
113
 
@@ -137,26 +146,32 @@ class StructDefinition(DataDefinition):
137
146
  def __init__(
138
147
  self,
139
148
  fields: Sequence[DataDefinition],
140
- metadata: Optional[Metadata] = None,
149
+ metadata: Metadata,
141
150
  ):
142
151
  super().__init__(metadata)
143
152
  self.fields = tuple(fields)
144
153
  fields_len = len(fields)
145
154
  field_types_len = len(self.field_types)
146
155
  if fields_len != field_types_len:
147
- raise ValueError(f"Supplied number of fields: {fields_len} doesn't match expectation: {field_types_len}")
156
+ raise ValueError(
157
+ f"Supplied number of fields: {fields_len} doesn't match expectation: {field_types_len}"
158
+ )
148
159
  for (k, t), v in zip(self.field_types.items(), fields):
149
160
  if not isinstance(v, t):
150
- raise ValueError(f"Got unexpected value: {v} for type: {t}")
161
+ raise ValueError(f"Got unexpected value: {v} for type: {t!r}")
151
162
  setattr(self, k, v)
152
163
 
153
164
  def __str__(self) -> str:
154
165
  cls_name = type(self).__name__
155
166
 
156
- fields_strs = map(lambda k, v: f"{k}: {v}", self.field_types.keys(), map(str, self.fields))
167
+ fields_strs = map(
168
+ lambda k, v: f"{k}: {v}", self.field_types.keys(), map(str, self.fields)
169
+ )
157
170
  fields_strs_indented = map(indent_4, fields_strs)
158
171
  fields_str = "\n".join(fields_strs_indented)
159
- return f"{cls_name} (size: {self.size}) {self.add_metadata_repr()}:\n{fields_str}"
172
+ return (
173
+ f"{cls_name} (size: {self.size}) {self.add_metadata_repr()}:\n{fields_str}"
174
+ )
160
175
 
161
176
  @classmethod
162
177
  def parser(cls, reader: Reader) -> Tuple[StructDefinition, Reader]:
@@ -187,18 +202,23 @@ def create_struct_definition(
187
202
  struct_name: str,
188
203
  field_types: Dict[str, Type[DataDefinition] | ForwardPointer],
189
204
  ) -> Type[StructDefinition]:
190
-
191
205
  new_struct = type(
192
206
  struct_name,
193
207
  (StructDefinition,),
194
208
  {},
195
209
  )
196
210
 
197
- normalized_field_types = {k: replace_forward_pointer(new_struct, v) for (k, v) in field_types.items()}
198
- sequence_parser = create_sequence_parser(*map(get_parser, normalized_field_types.values()))
211
+ normalized_field_types = {
212
+ k: replace_forward_pointer(new_struct, v) for (k, v) in field_types.items()
213
+ }
214
+ sequence_parser = create_sequence_parser(
215
+ *map(get_parser, normalized_field_types.values())
216
+ )
199
217
 
200
218
  @classmethod
201
- def parser(cls: Type[StructDefinition], reader: Reader) -> Tuple[StructDefinition, Reader]:
219
+ def parser(
220
+ cls: Type[StructDefinition], reader: Reader
221
+ ) -> Tuple[StructDefinition, Reader]:
202
222
  parsed_field_results, new_reader = sequence_parser(reader)
203
223
  metadata = Metadata(parsed_field_results[0].metadata.address)
204
224
  return cls(parsed_field_results, metadata=metadata), new_reader
@@ -220,7 +240,9 @@ class BitFieldDefinition:
220
240
  value: int,
221
241
  ):
222
242
  if value > self.mask:
223
- raise ValueError(f"Passed in value: {value:#x} greater than mask: {self.mask:#x}")
243
+ raise ValueError(
244
+ f"Passed in value: {value:#x} greater than mask: {self.mask:#x}"
245
+ )
224
246
  self.value = value
225
247
 
226
248
  def __repr__(self):
@@ -244,7 +266,7 @@ class BitFieldsDefinition(DataDefinition):
244
266
  def __init__(
245
267
  self,
246
268
  value: int,
247
- metadata: Optional[Metadata],
269
+ metadata: Metadata,
248
270
  ):
249
271
  super().__init__(metadata)
250
272
  self.value = value
@@ -253,7 +275,9 @@ class BitFieldsDefinition(DataDefinition):
253
275
  field_types_len = len(self.field_types)
254
276
 
255
277
  if fields_len != field_types_len:
256
- raise ValueError(f"Supplied number of fields: {fields_len} doesn't match expectation: {field_types_len}")
278
+ raise ValueError(
279
+ f"Supplied number of fields: {fields_len} doesn't match expectation: {field_types_len}"
280
+ )
257
281
  for (k, t), v in zip(self.field_types.items(), self.fields):
258
282
  if not isinstance(v, t):
259
283
  raise ValueError(f"Got unexpected value: {v} for type: {t}")
@@ -286,7 +310,9 @@ BitFieldDef = Tuple[str, int]
286
310
  BitFieldDefs = Dict[str, int]
287
311
 
288
312
 
289
- def _create_bit_field_definition_from_bit_field_def(position: int, bf_def: BitFieldDef) -> Type[BitFieldDefinition]:
313
+ def _create_bit_field_definition_from_bit_field_def(
314
+ position: int, bf_def: BitFieldDef
315
+ ) -> Type[BitFieldDefinition]:
290
316
  name, size = bf_def
291
317
  bit_field_definition = type(
292
318
  name,
@@ -304,7 +330,9 @@ def _create_bit_field_definition_from_bit_field_def(position: int, bf_def: BitFi
304
330
  PosFieldsTup = Tuple[int, Tuple[Type[BitFieldDefinition], ...]]
305
331
 
306
332
 
307
- def _create_fields_reducer(pos_fields_tup: PosFieldsTup, field_def: BitFieldDef) -> PosFieldsTup:
333
+ def _create_fields_reducer(
334
+ pos_fields_tup: PosFieldsTup, field_def: BitFieldDef
335
+ ) -> PosFieldsTup:
308
336
  pos, fields = pos_fields_tup
309
337
  name, size = field_def
310
338
  new_field = _create_bit_field_definition_from_bit_field_def(pos, field_def)
@@ -340,7 +368,7 @@ class PointerDefinition(DataDefinition):
340
368
  def __init__(
341
369
  self,
342
370
  address: int,
343
- metadata: Optional[Metadata],
371
+ metadata: Metadata,
344
372
  ):
345
373
  super().__init__(metadata)
346
374
  self.address = address
@@ -379,7 +407,7 @@ def create_pointer_definition(
379
407
  {
380
408
  "target_type": target_type,
381
409
  "address_type": address_type,
382
- "size": target_type.size,
410
+ "size": address_type.size,
383
411
  },
384
412
  )
385
413
 
@@ -397,13 +425,14 @@ def _create_pointer_definition_from_forward_pointer(
397
425
  class ArrayDefinition(DataDefinition):
398
426
  target_type: Type[DataDefinition]
399
427
  size: int
428
+ num_elems: int
400
429
  _fields_parser: Parser
401
430
  _array_splitter = "\n" + 80 * "=" + "\n"
402
431
 
403
432
  def __init__(
404
433
  self,
405
434
  fields: Sequence[DataDefinition],
406
- metadata: Optional[Metadata],
435
+ metadata: Metadata,
407
436
  ):
408
437
  super().__init__(metadata)
409
438
  self.fields = fields
@@ -414,7 +443,7 @@ class ArrayDefinition(DataDefinition):
414
443
  fields_strs = map(str, self.fields)
415
444
  fields_strs_indented = map(indent_4, fields_strs)
416
445
  fields_str = self._array_splitter.join(fields_strs_indented)
417
- return f"{cls_name}:: {target_cls}[{self.size}] {self.add_metadata_repr()}:\n{fields_str}"
446
+ return f"{cls_name}:: {target_cls}[{self.num_elems}] {self.add_metadata_repr()}:\n{fields_str}"
418
447
 
419
448
  @classmethod
420
449
  def parser(cls, reader: Reader) -> Tuple[ArrayDefinition, Reader]:
@@ -427,16 +456,18 @@ class ArrayDefinition(DataDefinition):
427
456
 
428
457
 
429
458
  def create_array_definition(
459
+ name: str,
430
460
  target_type: Type[DataDefinition],
431
- size: int,
461
+ num_elems: int,
432
462
  ) -> Type[ArrayDefinition]:
433
- fields_parser = create_repeat_parser(size, target_type.parser)
463
+ fields_parser = create_repeat_parser(num_elems, target_type.parser)
434
464
  return type(
435
- f"{target_type.__name__}Array",
465
+ name,
436
466
  (ArrayDefinition,),
437
467
  {
438
468
  "target_type": target_type,
439
- "size": size,
469
+ "num_elems": num_elems,
470
+ "size": target_type.size * num_elems,
440
471
  "_fields_parser": fields_parser,
441
472
  },
442
473
  )
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- from abc import ABC, abstractmethod
4
3
  from functools import reduce
5
4
  from itertools import chain, repeat
6
5
  from typing import (
@@ -8,7 +8,6 @@ AddressData = Tuple[int, bytes | memoryview]
8
8
 
9
9
 
10
10
  class Reader(ABC):
11
-
12
11
  def __init__(self, address: int, offset: int = 0):
13
12
  self.address = address
14
13
  self.offset = offset
@@ -24,5 +23,8 @@ class Reader(ABC):
24
23
  def new_reader(self, address: int) -> Reader:
25
24
  return type(self)(address)
26
25
 
26
+ def __repr__(self) -> str:
27
+ return f"{type(self).__name__}({self.address:#x})"
28
+
27
29
 
28
30
  ReaderData = Tuple[AddressData, Reader]