2
2
3
3
__all__ = ["RustCodeGen" ]
4
4
5
- import dataclasses
6
5
import functools
7
6
import itertools
8
7
import json
11
10
import sys
12
11
from abc import ABC , abstractmethod
13
12
from collections .abc import Iterator , MutableMapping , MutableSequence , Sequence
14
- from dataclasses import dataclass
15
13
from importlib .resources import files as resource_files
16
14
from io import StringIO
17
15
from pathlib import Path
@@ -117,6 +115,7 @@ def to_rust_literal(value: Any) -> str:
117
115
118
116
def make_avro (items : MutableSequence [JsonDataType ]) -> MutableSequence [NamedSchema ]:
119
117
"""Process a list of dictionaries to generate a list of Avro schemas."""
118
+
120
119
# Same as `from .utils import convert_to_dict`, which, however, is not public
121
120
def convert_to_dict (j4 : Any ) -> Any :
122
121
"""Convert generic Mapping objects to dicts recursively."""
@@ -150,11 +149,13 @@ def convert_to_dict(j4: Any) -> Any:
150
149
RustIdent = str # alias
151
150
152
151
153
- @dataclass # ASSERT: Immutable class
154
152
class RustLifetime :
155
153
"""Represents a Rust lifetime parameter (e.g., `'a`)."""
156
154
157
- ident : RustIdent
155
+ __slots__ = ("ident" ,)
156
+
157
+ def __init__ (self , ident : RustIdent ):
158
+ self .ident = ident
158
159
159
160
def __hash__ (self ) -> int :
160
161
return hash (self .ident )
@@ -175,11 +176,16 @@ class RustMeta(ABC):
175
176
pass
176
177
177
178
178
- @dataclass (unsafe_hash = True ) # ASSERT: Immutable class
179
179
class RustAttribute :
180
180
"""Represents a Rust attribute (e.g., `#[derive(Debug)]`)."""
181
181
182
- meta : RustMeta
182
+ __slots__ = ("meta" ,)
183
+
184
+ def __init__ (self , meta : RustMeta ):
185
+ self .meta = meta
186
+
187
+ def __hash__ (self ) -> int :
188
+ return hash (self .meta )
183
189
184
190
def __str__ (self ) -> str :
185
191
return f"#[{ str (self .meta )} ]"
@@ -193,17 +199,22 @@ def __str__(self) -> str:
193
199
RustGenericsMut = MutableSequence [Union [RustLifetime , "RustPath" ]] # alias
194
200
195
201
196
- @dataclass (unsafe_hash = True ) # ASSERT: Immutable class
197
202
class RustPathSegment :
198
203
"""Represents a segment in a Rust path with optional generics."""
199
204
200
- ident : RustIdent
201
- generics : RustGenerics = dataclasses .field (default_factory = tuple )
205
+ __slots__ = ("ident" , "generics" )
202
206
203
207
REX : ClassVar [Pattern [str ]] = re .compile (
204
208
r"^([a-zA-Z_]\w*)(?:<([ \w\t,'<>]+)>)?$"
205
209
) # Using `re.Pattern[str]` raise CI build errors
206
210
211
+ def __init__ (self , ident : RustIdent , generics : Optional [RustGenerics ] = None ):
212
+ self .ident = ident
213
+ self .generics = () if generics is None else generics
214
+
215
+ def __hash__ (self ) -> int :
216
+ return hash ((self .ident , self .generics ))
217
+
207
218
def __str__ (self ) -> str :
208
219
if not self .generics :
209
220
return self .ident
@@ -256,13 +267,18 @@ def parse_generics_string(value_generics: str) -> RustGenerics:
256
267
RustPathSegmentsMut = MutableSequence [RustPathSegment ] # alias
257
268
258
269
259
- @dataclass (unsafe_hash = True ) # ASSERT: Immutable class
260
270
class RustPath (RustMeta ):
261
271
"""Represents a complete Rust path (e.g., `::std::vec::Vec<T>`)."""
262
272
273
+ __slots__ = ("segments" , "leading_colon" )
274
+
263
275
# ASSERT: Never initialized with an empty sequence
264
- segments : RustPathSegments
265
- leading_colon : bool = False
276
+ def __init__ (self , segments : RustPathSegments , leading_colon : bool = False ):
277
+ self .segments = segments
278
+ self .leading_colon = leading_colon
279
+
280
+ def __hash__ (self ) -> int :
281
+ return hash ((self .segments , self .leading_colon ))
266
282
267
283
def __truediv__ (self , other : Union ["RustPath" , RustPathSegment ]) -> "RustPath" :
268
284
if self .segments [- 1 ].generics :
@@ -304,24 +320,31 @@ def from_str(cls, value: str) -> "RustPath":
304
320
return cls (segments = tuple (segments ), leading_colon = leading_colon )
305
321
306
322
307
- @dataclass (unsafe_hash = True ) # ASSERT: Immutable class
308
323
class RustTypeTuple (RustType ):
309
324
"""Represents a Rust tuple type (e.g., `(T, U)`)."""
310
325
326
+ __slots__ = ("types" ,)
327
+
311
328
# ASSERT: Never initialized with an empty sequence
312
- types : Sequence [RustPath ]
329
+ def __init__ (self , types : Sequence [RustPath ]):
330
+ self .types = types
331
+
332
+ def __hash__ (self ) -> int :
333
+ return hash (self .types )
313
334
314
335
def __str__ (self ) -> str :
315
336
types_str = ", " .join (str (ty ) for ty in self .types )
316
337
return f"({ types_str } )"
317
338
318
339
319
- @dataclass # ASSERT: Immutable class
320
340
class RustMetaList (RustMeta ):
321
341
"""Represents attribute meta list information (e.g., `derive(Debug, Clone)`).."""
322
342
323
- path : RustPath
324
- metas : Sequence [RustMeta ] = tuple ()
343
+ __slots__ = ("path" , "metas" )
344
+
345
+ def __init__ (self , path : RustPath , metas : Optional [Sequence [RustMeta ]] = None ):
346
+ self .path = path
347
+ self .metas = () if metas is None else metas
325
348
326
349
def __hash__ (self ) -> int :
327
350
return hash (self .path )
@@ -331,12 +354,14 @@ def __str__(self) -> str:
331
354
return f"{ str (self .path )} (" + meta_str + ")"
332
355
333
356
334
- @dataclass # ASSERT: Immutable class
335
357
class RustMetaNameValue (RustMeta ):
336
358
"""Represents attribute meta name-value information (e.g., `key = value`)."""
337
359
338
- path : RustPath
339
- value : Any = True
360
+ __slots__ = ("path" , "value" )
361
+
362
+ def __init__ (self , path : RustPath , value : Any = True ):
363
+ self .path = path
364
+ self .value = value
340
365
341
366
def __hash__ (self ) -> int :
342
367
return hash (self .path )
@@ -350,13 +375,17 @@ def __str__(self) -> str:
350
375
#
351
376
352
377
353
- @dataclass
354
378
class RustNamedType (ABC ): # ABC class
355
379
"""Abstract class for Rust struct and enum types."""
356
380
357
- ident : RustIdent
358
- attrs : RustAttributes = dataclasses .field (default_factory = list )
359
- visibility : str = "pub"
381
+ __slots__ = ("ident" , "attrs" , "visibility" )
382
+
383
+ def __init__ (
384
+ self , ident : RustIdent , attrs : Optional [RustAttributes ] = None , visibility : str = "pub"
385
+ ):
386
+ self .ident = ident
387
+ self .attrs = () if attrs is None else attrs
388
+ self .visibility = visibility
360
389
361
390
def __hash__ (self ) -> int :
362
391
return hash (self .ident )
@@ -371,13 +400,15 @@ def __str__(self) -> str:
371
400
return output .getvalue ()
372
401
373
402
374
- @dataclass # ASSERT: Immutable class
375
403
class RustField :
376
404
"""Represents a field in a Rust struct."""
377
405
378
- ident : RustIdent
379
- type : RustPath
380
- attrs : RustAttributes = dataclasses .field (default_factory = list )
406
+ __slots__ = ("ident" , "type" , "attrs" )
407
+
408
+ def __init__ (self , ident : RustIdent , type : RustPath , attrs : Optional [RustAttributes ] = None ):
409
+ self .ident = ident
410
+ self .type = type
411
+ self .attrs = () if attrs is None else attrs
381
412
382
413
def __hash__ (self ) -> int :
383
414
return hash (self .ident )
@@ -394,11 +425,21 @@ def write_to(self, writer: IO[str], depth: int = 0) -> None:
394
425
RustFieldsMut = Union [MutableSequence [RustField ], RustTypeTuple ] # alias
395
426
396
427
397
- @dataclass
398
428
class RustStruct (RustNamedType ):
399
429
"""Represents a Rust struct definition."""
400
430
401
- fields : Optional [RustFields ] = None
431
+ __slots__ = ("fields" ,)
432
+
433
+ def __init__ (
434
+ self ,
435
+ ident : RustIdent ,
436
+ fields : Optional [RustFields ] = None ,
437
+ attrs : Optional [RustAttributes ] = None ,
438
+ visibility : str = "pub" ,
439
+ ):
440
+ _attrs = () if attrs is None else attrs
441
+ super ().__init__ (ident , _attrs , visibility )
442
+ self .fields = fields
402
443
403
444
def write_to (self , writer : IO [str ], depth : int = 0 ) -> None :
404
445
indent = " " * depth
@@ -419,13 +460,20 @@ def write_to(self, writer: IO[str], depth: int = 0) -> None:
419
460
writer .write (f"{ indent } }}\n " )
420
461
421
462
422
- @dataclass # ASSERT: Immutable class
423
463
class RustVariant :
424
464
"""Represents a variant in a Rust enum."""
425
465
426
- ident : RustIdent
427
- tuple : Optional [RustTypeTuple ] = None
428
- attrs : RustAttributes = dataclasses .field (default_factory = list )
466
+ __slots__ = ("ident" , "tuple" , "attrs" )
467
+
468
+ def __init__ (
469
+ self ,
470
+ ident : RustIdent ,
471
+ tuple : Optional [RustTypeTuple ] = None ,
472
+ attrs : Optional [RustAttributes ] = None ,
473
+ ):
474
+ self .ident = ident
475
+ self .tuple = tuple
476
+ self .attrs = () if attrs is None else attrs
429
477
430
478
def __hash__ (self ) -> int :
431
479
return hash (self .ident )
@@ -435,7 +483,6 @@ def write_to(self, writer: IO[str], depth: int = 0) -> None:
435
483
436
484
if self .attrs :
437
485
writer .write ("\n " .join (f"{ indent } { str (attr )} " for attr in self .attrs ) + "\n " )
438
-
439
486
writer .write (f"{ indent } { self .ident } " )
440
487
if self .tuple :
441
488
writer .write (str (self .tuple ))
@@ -462,11 +509,21 @@ def from_path(cls, path: RustPath) -> "RustVariant":
462
509
RustVariantsMut = MutableSequence [RustVariant ] # alias
463
510
464
511
465
- @dataclass
466
512
class RustEnum (RustNamedType ):
467
513
"""Represents a Rust enum definition."""
468
514
469
- variants : RustVariants = dataclasses .field (default_factory = tuple )
515
+ __slots__ = ("variants" ,)
516
+
517
+ def __init__ (
518
+ self ,
519
+ ident : RustIdent ,
520
+ variants : Optional [RustVariants ] = None ,
521
+ attrs : Optional [RustAttributes ] = None ,
522
+ visibility : str = "pub" ,
523
+ ):
524
+ _attrs = () if attrs is None else attrs
525
+ super ().__init__ (ident , _attrs , visibility )
526
+ self .variants = () if variants is None else variants
470
527
471
528
def write_to (self , writer : IO [str ], depth : int = 0 ) -> None :
472
529
indent = " " * depth
@@ -495,16 +552,22 @@ def salad_macro_write_to(ty: RustNamedType, writer: IO[str], depth: int = 0) ->
495
552
#
496
553
497
554
498
- @dataclass
499
555
class RustModuleTree :
500
556
"""Represents a Rust module with submodules and named types."""
501
557
502
- ident : RustIdent # ASSERT: Immutable field
503
- parent : Optional ["RustModuleTree" ] # ASSERT: Immutable field
504
- named_types : MutableMapping [RustIdent , RustNamedType ] = dataclasses .field (default_factory = dict )
505
- submodules : MutableMapping [RustIdent , "RustModuleTree" ] = dataclasses .field (
506
- default_factory = dict
507
- )
558
+ __slots__ = ("ident" , "parent" , "named_types" , "submodules" )
559
+
560
+ def __init__ (
561
+ self ,
562
+ ident : RustIdent , # ASSERT: Immutable field
563
+ parent : Optional ["RustModuleTree" ] = None , # ASSERT: Immutable field
564
+ named_types : Optional [MutableMapping [RustIdent , RustNamedType ]] = None ,
565
+ submodules : Optional [MutableMapping [RustIdent , "RustModuleTree" ]] = None ,
566
+ ):
567
+ self .ident = ident
568
+ self .parent = parent
569
+ self .named_types = {} if named_types is None else named_types
570
+ self .submodules = {} if submodules is None else submodules
508
571
509
572
def __hash__ (self ) -> int :
510
573
return hash ((self .ident , self .parent ))
0 commit comments