11"""Serialization Strategy."""
22from __future__ import annotations
33
4- import sys
5- import typing
6- from typing import Any , Callable , Dict , Optional , cast
4+ from typing import Any , Optional , cast
75
86from google .protobuf import type_pb2
9- from google .protobuf .descriptor import FieldDescriptor
107from google .protobuf .internal import decoder , encoder
118from google .protobuf .message import Message
129
13- if typing .TYPE_CHECKING :
14- if sys .version_info >= (3 , 10 ):
15- from typing import TypeAlias
16- else :
17- from typing_extensions import TypeAlias
18-
19- Key : TypeAlias = FieldDescriptor
20- WriteFunction : TypeAlias = Callable [[bytes ], int ]
21- Encoder : TypeAlias = Callable [[WriteFunction , bytes , bool ], int ]
22- PartialEncoderConstructor : TypeAlias = Callable [[int ], Encoder ]
23- EncoderConstructor : TypeAlias = Callable [[int , bool , bool ], Encoder ]
24-
25- Decoder : TypeAlias = Callable [[memoryview , int , int , Message , Dict [Key , Any ]], int ]
26- PartialDecoderConstructor : TypeAlias = Callable [[int , Key ], Decoder ]
27- NewDefault : TypeAlias = Callable [[Message ], Message ]
28- DecoderConstructor : TypeAlias = Callable [[int , bool , bool , Key , NewDefault ], Decoder ]
10+ from ni_measurementlink_service ._internal .parameter import _message
11+ from ni_measurementlink_service ._internal .parameter ._serializer_types import (
12+ Decoder ,
13+ DecoderConstructor ,
14+ Encoder ,
15+ EncoderConstructor ,
16+ Key ,
17+ PartialDecoderConstructor ,
18+ PartialEncoderConstructor ,
19+ )
20+ from ni_measurementlink_service ._internal .stubs .ni .protobuf .types import xydata_pb2
2921
3022
3123def _scalar_encoder (encoder : EncoderConstructor ) -> PartialEncoderConstructor :
@@ -63,6 +55,10 @@ def vector_encoder(field_index: int) -> Encoder:
6355 return vector_encoder
6456
6557
58+ def _unsupported_encoder (field_index : int , is_repeated : bool , is_packed : bool ) -> Encoder :
59+ raise NotImplementedError (f"Unsupported data type for field { field_index } " )
60+
61+
6662def _scalar_decoder (decoder : DecoderConstructor ) -> PartialDecoderConstructor :
6763 """Constructs a scalar decoder constructor.
6864
@@ -106,6 +102,23 @@ def vector_decoder(field_index: int, key: Key) -> Decoder:
106102 return vector_decoder
107103
108104
105+ def _double_xy_data_decoder (decoder : DecoderConstructor ) -> PartialDecoderConstructor :
106+ """Constructs a DoubleXYData decoder constructor.
107+
108+ Takes a field index and a key and returns a Decoder for DoubleXYData.
109+ """
110+
111+ def _new_default (unused_message : Optional [Message ] = None ) -> Any :
112+ return xydata_pb2 .DoubleXYData ()
113+
114+ def message_decoder (field_index : int , key : Key ) -> Decoder :
115+ is_repeated = True
116+ is_packed = True
117+ return decoder (field_index , is_repeated , is_packed , key , _new_default )
118+
119+ return message_decoder
120+
121+
109122# Cast works around this issue in typeshed
110123# https://github.com/python/typeshed/issues/10695
111124FloatEncoder = _scalar_encoder (cast (EncoderConstructor , encoder .FloatEncoder ))
@@ -114,13 +127,15 @@ def vector_decoder(field_index: int, key: Key) -> Decoder:
114127UIntEncoder = _scalar_encoder (cast (EncoderConstructor , encoder .UInt32Encoder ))
115128BoolEncoder = _scalar_encoder (encoder .BoolEncoder )
116129StringEncoder = _scalar_encoder (encoder .StringEncoder )
130+ MessageEncoder = _scalar_encoder (cast (EncoderConstructor , _message ._message_encoder_constructor ))
117131
118132FloatArrayEncoder = _vector_encoder (cast (EncoderConstructor , encoder .FloatEncoder ))
119133DoubleArrayEncoder = _vector_encoder (cast (EncoderConstructor , encoder .DoubleEncoder ))
120134IntArrayEncoder = _vector_encoder (cast (EncoderConstructor , encoder .Int32Encoder ))
121135UIntArrayEncoder = _vector_encoder (cast (EncoderConstructor , encoder .UInt32Encoder ))
122136BoolArrayEncoder = _vector_encoder (encoder .BoolEncoder )
123137StringArrayEncoder = _vector_encoder (encoder .StringEncoder , is_packed = False )
138+ UnsupportedMessageArrayEncoder = _vector_encoder (_unsupported_encoder )
124139
125140# Cast works around this issue in typeshed
126141# https://github.com/python/typeshed/issues/10697
@@ -132,6 +147,7 @@ def vector_decoder(field_index: int, key: Key) -> Decoder:
132147UInt64Decoder = _scalar_decoder (cast (DecoderConstructor , decoder .UInt64Decoder ))
133148BoolDecoder = _scalar_decoder (cast (DecoderConstructor , decoder .BoolDecoder ))
134149StringDecoder = _scalar_decoder (cast (DecoderConstructor , decoder .StringDecoder ))
150+ XYDataDecoder = _double_xy_data_decoder (_message ._message_decoder_constructor )
135151
136152FloatArrayDecoder = _vector_decoder (cast (DecoderConstructor , decoder .FloatDecoder ))
137153DoubleArrayDecoder = _vector_decoder (cast (DecoderConstructor , decoder .DoubleDecoder ))
@@ -155,6 +171,7 @@ def vector_decoder(field_index: int, key: Key) -> Decoder:
155171 type_pb2 .Field .TYPE_BOOL : (BoolEncoder , BoolArrayEncoder ),
156172 type_pb2 .Field .TYPE_STRING : (StringEncoder , StringArrayEncoder ),
157173 type_pb2 .Field .TYPE_ENUM : (IntEncoder , IntArrayEncoder ),
174+ type_pb2 .Field .TYPE_MESSAGE : (MessageEncoder , UnsupportedMessageArrayEncoder ),
158175}
159176
160177_FIELD_TYPE_TO_DECODER_MAPPING = {
@@ -181,6 +198,10 @@ def vector_decoder(field_index: int, key: Key) -> Decoder:
181198 type_pb2 .Field .TYPE_ENUM : int (),
182199}
183200
201+ _MESSAGE_TYPE_TO_DECODER = {
202+ xydata_pb2 .DoubleXYData .DESCRIPTOR .full_name : XYDataDecoder ,
203+ }
204+
184205
185206def get_encoder (type : type_pb2 .Field .Kind .ValueType , repeated : bool ) -> PartialEncoderConstructor :
186207 """Get the appropriate partial encoder constructor for the specified type.
@@ -195,17 +216,23 @@ def get_encoder(type: type_pb2.Field.Kind.ValueType, repeated: bool) -> PartialE
195216 return scalar
196217
197218
198- def get_decoder (type : type_pb2 .Field .Kind .ValueType , repeated : bool ) -> PartialDecoderConstructor :
199- """Get the appropriate partial decoder constructor for the specified type.
200-
201- A scalar or vector constructor is returned based on the 'repeated' parameter.
202- """
203- if type not in _FIELD_TYPE_TO_DECODER_MAPPING :
219+ def get_decoder (
220+ type : type_pb2 .Field .Kind .ValueType , repeated : bool , message_type : str = ""
221+ ) -> PartialDecoderConstructor :
222+ """Get the appropriate partial decoder constructor for the specified type."""
223+ decoder_mapping = _FIELD_TYPE_TO_DECODER_MAPPING .get (type )
224+ if decoder_mapping is not None :
225+ scalar_decoder , array_decoder = decoder_mapping
226+ return array_decoder if repeated else scalar_decoder
227+ elif type == type_pb2 .Field .Kind .TYPE_MESSAGE :
228+ if repeated :
229+ raise ValueError (f"Repeated message types are not supported '{ message_type } '" )
230+ decoder = _MESSAGE_TYPE_TO_DECODER .get (message_type )
231+ if decoder is None :
232+ raise ValueError (f"Unknown message type '{ message_type } '" )
233+ return decoder
234+ else :
204235 raise ValueError (f"Error can not decode type '{ type } '" )
205- scalar , array = _FIELD_TYPE_TO_DECODER_MAPPING [type ]
206- if repeated :
207- return array
208- return scalar
209236
210237
211238def get_type_default (type : type_pb2 .Field .Kind .ValueType , repeated : bool ) -> Any :
0 commit comments