@@ -30,14 +30,68 @@ class Serializer(ABC, Generic[Serializable]):
3030 def serialize (self , _ : Serializable ) -> bytes :
3131 pass
3232
33- # Unfortunately xdrlib is deprecated in Python 3.11, so we implement the following serialization methods
34- # to be used by descendants of the Serializer class.
35- # See https://datatracker.ietf.org/doc/html/rfc1014 for the XDR specification.
36- def _write_uint32 (self , i : int ) -> bytes :
33+
34+ class Deserializer (ABC , Generic [Serializable ]):
35+ def deserialize_from_bytes (self , payload : bytes ) -> Serializable :
36+ return self .deserialize (io .BytesIO (payload ))
37+
38+ @abstractmethod
39+ def deserialize (self , _ : io .BytesIO ) -> Serializable :
40+ pass
41+
42+
43+ # Unfortunately xd)rlib is deprecated in Python 3.11, so we implement the following serialization methods
44+ # to be used by descendants of the Serializer class.
45+ # See https://datatracker.ietf.org/doc/html/rfc1014 for the XDR specification.
46+
47+
48+ class Int32Serializer (Serializer [int ], Deserializer [int ]):
49+ def serialize (self , i : int ) -> bytes :
50+ return i .to_bytes (length = 4 , byteorder = "big" , signed = True )
51+
52+ def deserialize (self , payload : io .BytesIO ) -> int :
53+ return int .from_bytes (payload .read (4 ), byteorder = "big" , signed = True )
54+
55+
56+ class UInt32Serializer (Serializer [int ], Deserializer [int ]):
57+ def serialize (self , i : int ) -> bytes :
3758 return i .to_bytes (length = 4 , byteorder = "big" , signed = False )
3859
60+ def deserialize (self , payload : io .BytesIO ) -> int :
61+ return int .from_bytes (payload .read (4 ), byteorder = "big" , signed = False )
62+
63+
64+ class OpaqueVarLengthSerializer (Serializer [bytes ], Deserializer [bytes ]):
65+ def serialize (self , body : bytes ) -> bytes :
66+ length = len (body )
67+ result = UInt32Serializer ().serialize (length )
68+ result += body
69+
70+ padding_bytes = (ALIGNMENT - (length % ALIGNMENT )) % ALIGNMENT
71+ return result + b"\x00 " * padding_bytes
72+
73+ def deserialize (self , payload : io .BytesIO ) -> bytes :
74+ length = UInt32Serializer ().deserialize (payload )
75+ result = payload .read (length )
76+ padding_bytes = (ALIGNMENT - (length % ALIGNMENT )) % ALIGNMENT
77+ payload .read (padding_bytes )
78+ return result
79+
80+
81+ class StringSerializer (Serializer [str ], Deserializer [str ]):
82+ def serialize (self , s : str ) -> bytes :
83+ return OpaqueVarLengthSerializer ().serialize (s .encode ("ascii" ))
84+
85+ def deserialize (self , payload : io .BytesIO ) -> str :
86+ return OpaqueVarLengthSerializer ().deserialize (payload ).decode ("ascii" )
87+
88+
89+ class XdrSerializer (Generic [Serializable ], Serializer [Serializable ]):
90+ def _write_uint32 (self , i : int ) -> bytes :
91+ return UInt32Serializer ().serialize (i )
92+
3993 def _write_int32 (self , i : int ) -> bytes :
40- return i . to_bytes ( length = 4 , byteorder = "big" , signed = True )
94+ return Int32Serializer (). serialize ( i )
4195
4296 def _write_uint64 (self , i : int ) -> bytes :
4397 return i .to_bytes (length = 8 , byteorder = "big" , signed = False )
@@ -51,33 +105,18 @@ def _write_var_length(self, elements: list[ElementType], serializer: Serializer[
51105 return result + b"" .join (payload )
52106
53107 def _write_var_length_opaque (self , body : bytes ) -> bytes :
54- length = len (body )
55- result = self ._write_uint32 (length )
56- result += body
57-
58- padding_bytes = (ALIGNMENT - (length % ALIGNMENT )) % ALIGNMENT
59- return result + b"\x00 " * padding_bytes
108+ return OpaqueVarLengthSerializer ().serialize (body )
60109
61110 def _write_string (self , s : str ) -> bytes :
62- return self . _write_var_length_opaque ( s . encode ( "ascii" ) )
111+ return StringSerializer (). serialize ( s )
63112
64113
65- class Deserializer (ABC , Generic [Serializable ]):
66- def deserialize_from_bytes (self , payload : bytes ) -> Serializable :
67- return self .deserialize (io .BytesIO (payload ))
68-
69- @abstractmethod
70- def deserialize (self , _ : io .BytesIO ) -> Serializable :
71- pass
72-
73- # Unfortunately xdrlib is deprecated in Python 3.11, so we implement the following serialization methods
74- # to be used by descendants of the Serializer class.
75- # See https://datatracker.ietf.org/doc/html/rfc1014 for the XDR specification.
114+ class XdrDeserializer (Generic [Serializable ], Deserializer [Serializable ]):
76115 def _read_uint32 (self , payload : io .BytesIO ) -> int :
77- return int . from_bytes ( payload . read ( 4 ), byteorder = "big" , signed = False )
116+ return UInt32Serializer (). deserialize ( payload )
78117
79118 def _read_int32 (self , payload : io .BytesIO ) -> int :
80- return int . from_bytes ( payload . read ( 4 ), byteorder = "big" , signed = True )
119+ return Int32Serializer (). deserialize ( payload )
81120
82121 def _read_uint64 (self , payload : io .BytesIO ) -> int :
83122 return int .from_bytes (payload .read (8 ), byteorder = "big" , signed = False )
@@ -86,19 +125,15 @@ def _read_enum(self, payload: io.BytesIO, enum: EnumType) -> EnumType:
86125 value = self ._read_int32 (payload )
87126 return enum (value )
88127
89- def _read_var_length_opaque (self , payload : io .BytesIO ) -> bytes :
90- length = self ._read_uint32 (payload )
91- result = payload .read (length )
92- padding_bytes = (ALIGNMENT - (length % ALIGNMENT )) % ALIGNMENT
93- payload .read (padding_bytes )
94- return result
95-
96128 def _read_var_length (self , payload : io .BytesIO , deserializer : Deserializer [ElementType ]) -> list [ElementType ]:
97129 length = self ._read_uint32 (payload )
98130 return [deserializer .deserialize (payload ) for _ in range (length )]
99131
132+ def _read_var_length_opaque (self , payload : io .BytesIO ) -> bytes :
133+ return OpaqueVarLengthSerializer ().deserialize (payload )
134+
100135 def _read_string (self , payload : io .BytesIO ) -> str :
101- return self . _read_var_length_opaque ( payload ). decode ( "ascii" )
136+ return StringSerializer (). deserialize ( payload )
102137
103138 def _read_optional (self , payload : io .BytesIO , deserializer : Deserializer [ElementType ]) -> ElementType | None :
104139 has_value = self ._read_enum (payload , sunrpc .Bool )
@@ -107,42 +142,6 @@ def _read_optional(self, payload: io.BytesIO, deserializer: Deserializer[Element
107142 return deserializer .deserialize (payload )
108143
109144
110- # RdJ: A bit clunky having to lift the primitives inside the Serializer/Deserializer class
111- # to enable composition.
112- # Possible design mistake, Alternatively, make serializers functions, since no state is kept.
113- # But most of our stuff is OOP, so it would be inconsistent.
114- class Int32Serializer (Serializer [int ], Deserializer [int ]):
115- def serialize (self , i : int ) -> bytes :
116- return self ._write_int32 (i )
117-
118- def deserialize (self , payload : io .BytesIO ) -> int :
119- return self ._read_int32 (payload )
120-
121-
122- class UInt32Serializer (Serializer [int ], Deserializer [int ]):
123- def serialize (self , i : int ) -> bytes :
124- return self ._write_uint32 (i )
125-
126- def deserialize (self , payload : io .BytesIO ) -> int :
127- return self ._read_uint32 (payload )
128-
129-
130- class StringSerializer (Serializer [str ], Deserializer [str ]):
131- def serialize (self , s : str ) -> bytes :
132- return self ._write_string (s )
133-
134- def deserialize (self , payload : io .BytesIO ) -> str :
135- return self ._read_string (payload )
136-
137-
138- class OpaqueVarLengthSerializer (Serializer [bytes ], Deserializer [bytes ]):
139- def serialize (self , body : bytes ) -> bytes :
140- return self ._write_var_length_opaque (body )
141-
142- def deserialize (self , payload : io .BytesIO ) -> bytes :
143- return self ._read_var_length_opaque (payload )
144-
145-
146145class ReplyStat (Enum ):
147146 MSG_ACCEPTED = 0
148147 MSG_DENIED = 1
@@ -155,7 +154,7 @@ class AuthFlavor(Enum):
155154 AUTH_DES = 3
156155
157156
158- class AuthSerializer (Generic [AuthProtocol ], Serializer [AuthProtocol ], Deserializer [AuthProtocol ]):
157+ class AuthSerializer (Generic [AuthProtocol ], XdrSerializer [AuthProtocol ], XdrDeserializer [AuthProtocol ]):
159158 def serialize (self , protocol : AuthProtocol ) -> bytes :
160159 flavor = self ._flavor ()
161160 result = self ._write_int32 (flavor )
@@ -219,13 +218,13 @@ def _read_body(self, payload: io.BytesIO) -> sunrpc.AuthUnix:
219218
220219class MessageSerializer (
221220 Generic [ProcedureParams , ProcedureResults , Credentials , Verifier ],
222- Serializer [sunrpc .Message [ProcedureParams , ProcedureResults , Credentials , Verifier ]],
223- Deserializer [sunrpc .Message [ProcedureParams , ProcedureResults , Credentials , Verifier ]],
221+ XdrSerializer [sunrpc .Message [ProcedureParams , ProcedureResults , Credentials , Verifier ]],
222+ XdrDeserializer [sunrpc .Message [ProcedureParams , ProcedureResults , Credentials , Verifier ]],
224223):
225224 def __init__ (
226225 self ,
227- paramsSerializer : Serializer [ProcedureParams ],
228- resultsDeserializer : Deserializer [ProcedureResults ],
226+ paramsSerializer : XdrSerializer [ProcedureParams ],
227+ resultsDeserializer : XdrDeserializer [ProcedureResults ],
229228 credentialsSerializer : AuthSerializer [Credentials ],
230229 verifierSerializer : AuthSerializer [Verifier ],
231230 ):
@@ -296,7 +295,7 @@ def _read_mismatch(self, payload: io.BytesIO) -> sunrpc.Mismatch:
296295 return sunrpc .Mismatch (low , high )
297296
298297
299- class PortMappingSerializer (Serializer [sunrpc .PortMapping ]):
298+ class PortMappingSerializer (XdrSerializer [sunrpc .PortMapping ]):
300299 def serialize (self , port_mapping : sunrpc .PortMapping ) -> bytes :
301300 result = self ._write_uint32 (port_mapping .program )
302301 result += self ._write_uint32 (port_mapping .version )
0 commit comments