xdrgen: Prevent reordering of encoder and decoder functions
authorChuck Lever <chuck.lever@oracle.com>
Fri, 13 Sep 2024 17:50:56 +0000 (13:50 -0400)
committerChuck Lever <chuck.lever@oracle.com>
Fri, 20 Sep 2024 23:31:41 +0000 (19:31 -0400)
I noticed that "xdrgen source" reorders the procedure encoder and
decoder functions every time it is run. I would prefer that the
generated code be more deterministic: it enables a reader to better
see exactly what has changed between runs of the tool.

The problem is that Python sets are not ordered. I use a Python set
to ensure that, when multiple procedures use a particular argument or
result type, the encoder/decoder for that type is emitted only once.

Sets aren't ordered, but I can use Python dictionaries for this
purpose to ensure the procedure functions are always emitted in the
same order if the .x file does not change.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
tools/net/sunrpc/xdrgen/generators/program.py

index 83b0ecbae86fdd63560134f057bd83a917d6db6a..ac3cf1694b68b6f0d4db24b51377054a518dd4e9 100644 (file)
@@ -34,20 +34,20 @@ def emit_version_declarations(
     environment: Environment, program: str, version: _RpcVersion
 ) -> None:
     """Emit declarations for each RPC version's procedures"""
-    arguments = set()
+    arguments = dict.fromkeys([])
     for procedure in version.procedures:
         if procedure.name not in excluded_apis:
-            arguments.add(procedure.argument.type_name)
+            arguments[procedure.argument.type_name] = None
     if len(arguments) > 0:
         print("")
         template = environment.get_template("declaration/argument.j2")
         for argument in arguments:
             print(template.render(program=program, argument=argument))
 
-    results = set()
+    results = dict.fromkeys([])
     for procedure in version.procedures:
         if procedure.name not in excluded_apis:
-            results.add(procedure.result.type_name)
+            results[procedure.result.type_name] = None
     if len(results) > 0:
         print("")
         template = environment.get_template("declaration/result.j2")
@@ -59,10 +59,10 @@ def emit_version_argument_decoders(
     environment: Environment, program: str, version: _RpcVersion
 ) -> None:
     """Emit server argument decoders for each RPC version's procedures"""
-    arguments = set()
+    arguments = dict.fromkeys([])
     for procedure in version.procedures:
         if procedure.name not in excluded_apis:
-            arguments.add(procedure.argument.type_name)
+            arguments[procedure.argument.type_name] = None
 
     template = environment.get_template("decoder/argument.j2")
     for argument in arguments:
@@ -73,10 +73,10 @@ def emit_version_result_decoders(
     environment: Environment, program: str, version: _RpcVersion
 ) -> None:
     """Emit client result decoders for each RPC version's procedures"""
-    results = set()
+    results = dict.fromkeys([])
     for procedure in version.procedures:
         if procedure.name not in excluded_apis:
-            results.add(procedure.result.type_name)
+            results[procedure.result.type_name] = None
 
     template = environment.get_template("decoder/result.j2")
     for result in results:
@@ -87,10 +87,10 @@ def emit_version_argument_encoders(
     environment: Environment, program: str, version: _RpcVersion
 ) -> None:
     """Emit client argument encoders for each RPC version's procedures"""
-    arguments = set()
+    arguments = dict.fromkeys([])
     for procedure in version.procedures:
         if procedure.name not in excluded_apis:
-            arguments.add(procedure.argument.type_name)
+            arguments[procedure.argument.type_name] = None
 
     template = environment.get_template("encoder/argument.j2")
     for argument in arguments:
@@ -101,10 +101,10 @@ def emit_version_result_encoders(
     environment: Environment, program: str, version: _RpcVersion
 ) -> None:
     """Emit server result encoders for each RPC version's procedures"""
-    results = set()
+    results = dict.fromkeys([])
     for procedure in version.procedures:
         if procedure.name not in excluded_apis:
-            results.add(procedure.result.type_name)
+            results[procedure.result.type_name] = None
 
     template = environment.get_template("encoder/result.j2")
     for result in results: