@@ -36,7 +36,6 @@ class TypeIds(Enum):
3636
3737prefix = "DIDL"
3838
39- # TODO
4039class Pipe :
4140 def __init__ (self , buffer = b'' , length = 0 ):
4241 self ._buffer = buffer
@@ -66,12 +65,6 @@ def readbyte(self):
6665 self ._view = self ._view [1 :]
6766 return res
6867
69- def write (buf ):
70- pass
71-
72- def alloc (amount ):
73- pass
74-
7568
7669class ConstructType : pass
7770class TypeTable ():
@@ -614,7 +607,6 @@ def display(self):
614607 return 'opt ({})' .format (self ._type .display ())
615608
616609# Represents an IDL Record
617- # todo
618610class RecordClass (ConstructType ):
619611 def __init__ (self , field : dict ):
620612 super ().__init__ ()
@@ -696,7 +688,6 @@ def display(self):
696688 return "record {}" .format (d )
697689
698690# Represents Tuple, a syntactic sugar for Record.
699- # todo
700691class TupleClass (RecordClass ):
701692 def __init__ (self , * _components ):
702693 x = {}
@@ -750,7 +741,6 @@ def display(self):
750741 return "record {" + '{}' .format (';' .join (d )) + '}'
751742
752743# Represents an IDL Variant
753- # todo
754744class VariantClass (ConstructType ):
755745 def __init__ (self , field ):
756746 super ().__init__ ()
@@ -918,7 +908,151 @@ def name(self) -> str:
918908 def id (self ) -> int :
919909 return TypeIds .Principal .value
920910
921- # TODO class FunClass and ServiceClass
911+ #Represents an IDL Func reference
912+ class FuncClass (ConstructType ):
913+ def __init__ (self , argTypes : list , retTypes : list , annotations : list ):
914+ super ().__init__ ()
915+ self .argTypes = argTypes
916+ self .retTypes = argTypes
917+ self .annotations = annotations
918+
919+ def covariant (self , x ):
920+ return type (x ) == list and len (x ) == 2 and x [0 ] and \
921+ (P .from_str (x [0 ]) if type (x [0 ]) == str else P .from_hex (x [0 ].hex ())).isPrincipal \
922+ and type (x [1 ]) == str
923+
924+ def encodeValue (self , vals ):
925+ principal = vals [0 ]
926+ methodName = vals [1 ]
927+ tag = int .to_bytes (1 , 1 , byteorder = 'big' )
928+ if isinstance (principal , str ):
929+ buf = P .from_str (principal ).bytes
930+ elif isinstance (principal , bytes ):
931+ buf = principal
932+ else :
933+ raise ValueError ("Principal should be string or bytes." )
934+ l = leb128 .u .encode (len (buf ))
935+ canister = tag + l + buf
936+
937+ method = methodName .encode ()
938+ methodLen = leb128 .u .encode (len (method ))
939+ return tag + canister + methodLen + method
940+
941+ def _buildTypeTableImpl (self , typeTable : TypeTable ):
942+ for arg in self .argTypes :
943+ arg .buildTypeTable (typeTable )
944+ for ret in self .retTypes :
945+ ret .buildTypeTable (typeTable )
946+
947+ opCode = leb128 .i .encode (TypeIds .Func .value )
948+ argLen = leb128 .u .encode (len (self .argTypes ))
949+ args = b''
950+ for arg in self .argTypes :
951+ args += arg .encodeType (typeTable )
952+ retLen = leb128 .u .encode (len (self .retTypes ))
953+ rets = b''
954+ for ret in self .retTypes :
955+ rets += ret .encodeType (typeTable )
956+ annLen = leb128 .u .encode (len (self .annotations ))
957+ anns = b''
958+ for a in self .annotations :
959+ anns += self ._encodeAnnotation (a )
960+ typeTable .add (self , opCode + argLen + args + retLen + rets + annLen + anns )
961+
962+ def decodeValue (self , b : Pipe , t : Type ):
963+ x = safeReadByte (b )
964+ if leb128 .u .decode (x ) != 1 :
965+ raise ValueError ('Cannot decode function reference' )
966+ res = safeReadByte (b )
967+ if leb128 .u .decode (res ) != 1 :
968+ raise ValueError ("Cannot decode principal" )
969+ length = leb128uDecode (b )
970+ canister = P .from_hex (safeRead (b , length ).hex ())
971+ mLen = leb128uDecode (b )
972+ buf = safeRead (b , mLen )
973+ method = buf .decode ('utf-8' )
974+
975+ return [canister , method ]
976+
977+ @property
978+ def name (self ) -> str :
979+ args = ', ' .join (arg .name for arg in self .argTypes )
980+ rets = ', ' .join (ret .name for ret in self .retTypes )
981+ anns = ' ' .join (self .annotations )
982+ return '({}) → ({}) {}' .format (args , rets , anns )
983+
984+ @property
985+ def id (self ) -> int :
986+ return TypeIds .Func .value
987+
988+ def display (self ):
989+ args = ', ' .join (arg .display () for arg in self .argTypes )
990+ rets = ', ' .join (ret .display () for ret in self .retTypes )
991+ anns = ' ' .join (self .annotations )
992+ return '({}) → ({}) {}' .format (args , rets , anns )
993+
994+ def _encodeAnnotation (self , ann : str ):
995+ if ann == 'query' :
996+ return int .to_bytes (1 , 1 , byteorder = 'big' )
997+ elif ann == 'oneway' :
998+ return int .to_bytes (2 , 1 , byteorder = 'big' )
999+ else :
1000+ raise ValueError ('Illeagal function annotation' )
1001+
1002+ # Represents an IDL Service reference
1003+ class ServiceClass (ConstructType ):
1004+ def __init__ (self , field ):
1005+ super ().__init__ ()
1006+ self ._fields = dict (sorted (field .items (), key = lambda kv : labelHash (kv [0 ]))) # check
1007+
1008+ def covariant (self , x ):
1009+ if isinstance (x ,str ):
1010+ p = P .from_str (x )
1011+ elif isinstance (x , bytes ):
1012+ p = P .from_hex (x .hex ())
1013+ else :
1014+ raise ValueError ("only support string or bytes format" )
1015+ return p .isPrincipal
1016+
1017+
1018+ def encodeValue (self , val ):
1019+ tag = int .to_bytes (1 , 1 , byteorder = 'big' )
1020+ if isinstance (val , str ):
1021+ buf = P .from_str (val ).bytes
1022+ elif isinstance (val , bytes ):
1023+ buf = val
1024+ else :
1025+ raise ValueError ("Principal should be string or bytes." )
1026+ l = leb128 .u .encode (len (buf ))
1027+ return tag + l + buf
1028+
1029+ def _buildTypeTableImpl (self , typeTable : TypeTable ):
1030+ for _ , v in self ._fields .items ():
1031+ v .buildTypeTable (typeTable )
1032+ opCode = leb128 .i .encode (TypeIds .Service .value )
1033+ length = leb128 .u .encode (len (self ._fields ))
1034+ fields = b''
1035+ for k , v in self ._fields .items ():
1036+ fields += leb128 .u .encode (len (k .encode ())) + k .encode () + v .encodeType (typeTable )
1037+ typeTable .add (self , opCode + length + fields )
1038+
1039+ def decodeValue (self , b : Pipe , t : Type ):
1040+ res = safeReadByte (b )
1041+ if leb128 .u .decode (res ) != 1 :
1042+ raise ValueError ("Cannot decode principal" )
1043+ length = leb128uDecode (b )
1044+ return P .from_hex (safeRead (b , length ).hex ())
1045+
1046+ @property
1047+ def name (self ) -> str :
1048+ fields = ''
1049+ for k , v in self ._fields .items ():
1050+ fields += k + ' : ' + v .name
1051+ return 'service {}' .format (fields )
1052+
1053+ @property
1054+ def id (self ) -> int :
1055+ return TypeIds .Service .value
9221056
9231057# through Pipe to decode bytes
9241058def leb128uDecode (pipe : Pipe ):
@@ -954,7 +1088,6 @@ def readTypeTable(pipe):
9541088 #types length
9551089 typeTable = []
9561090 typeTable_len = leb128uDecode (pipe )
957- # contruct type todo
9581091 for _ in range (typeTable_len ):
9591092 ty = leb128iDecode (pipe )
9601093 if ty == TypeIds .Opt .value or ty == TypeIds .Vec .value :
@@ -1085,10 +1218,10 @@ def buildType(rawTable, table, entry):
10851218 temp = getType (rawTable , table , t )
10861219 fields [name ] = temp
10871220 return Types .Variant (fields )
1088- # elif TypeIds.Func.value:
1089- # return Types.Func([], [], [])
1090- # elif TypeIds.Service.value:
1091- # return Types.Service({})
1221+ elif ty == TypeIds .Func .value :
1222+ return Types .Func ([], [], [])
1223+ elif ty == TypeIds .Service .value :
1224+ return Types .Service ({})
10921225 else :
10931226 raise ValueError ("Illegal op_code: {}" .format (ty ))
10941227
@@ -1198,10 +1331,8 @@ def Variant(fields):
11981331 def Rec ():
11991332 return RecClass ()
12001333
1201- # not supported yet
1202- '''
12031334 def Func (args , ret , annotations ):
12041335 return FuncClass (args , ret , annotations )
1336+
12051337 def Service (t ):
12061338 return ServiceClass (t )
1207- '''
0 commit comments