@@ -36,7 +36,6 @@ class TypeIds(Enum):
36
36
37
37
prefix = "DIDL"
38
38
39
- # TODO
40
39
class Pipe :
41
40
def __init__ (self , buffer = b'' , length = 0 ):
42
41
self ._buffer = buffer
@@ -66,12 +65,6 @@ def readbyte(self):
66
65
self ._view = self ._view [1 :]
67
66
return res
68
67
69
- def write (buf ):
70
- pass
71
-
72
- def alloc (amount ):
73
- pass
74
-
75
68
76
69
class ConstructType : pass
77
70
class TypeTable ():
@@ -614,7 +607,6 @@ def display(self):
614
607
return 'opt ({})' .format (self ._type .display ())
615
608
616
609
# Represents an IDL Record
617
- # todo
618
610
class RecordClass (ConstructType ):
619
611
def __init__ (self , field : dict ):
620
612
super ().__init__ ()
@@ -696,7 +688,6 @@ def display(self):
696
688
return "record {}" .format (d )
697
689
698
690
# Represents Tuple, a syntactic sugar for Record.
699
- # todo
700
691
class TupleClass (RecordClass ):
701
692
def __init__ (self , * _components ):
702
693
x = {}
@@ -750,7 +741,6 @@ def display(self):
750
741
return "record {" + '{}' .format (';' .join (d )) + '}'
751
742
752
743
# Represents an IDL Variant
753
- # todo
754
744
class VariantClass (ConstructType ):
755
745
def __init__ (self , field ):
756
746
super ().__init__ ()
@@ -918,7 +908,151 @@ def name(self) -> str:
918
908
def id (self ) -> int :
919
909
return TypeIds .Principal .value
920
910
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
922
1056
923
1057
# through Pipe to decode bytes
924
1058
def leb128uDecode (pipe : Pipe ):
@@ -954,7 +1088,6 @@ def readTypeTable(pipe):
954
1088
#types length
955
1089
typeTable = []
956
1090
typeTable_len = leb128uDecode (pipe )
957
- # contruct type todo
958
1091
for _ in range (typeTable_len ):
959
1092
ty = leb128iDecode (pipe )
960
1093
if ty == TypeIds .Opt .value or ty == TypeIds .Vec .value :
@@ -1085,10 +1218,10 @@ def buildType(rawTable, table, entry):
1085
1218
temp = getType (rawTable , table , t )
1086
1219
fields [name ] = temp
1087
1220
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 ({})
1092
1225
else :
1093
1226
raise ValueError ("Illegal op_code: {}" .format (ty ))
1094
1227
@@ -1198,10 +1331,8 @@ def Variant(fields):
1198
1331
def Rec ():
1199
1332
return RecClass ()
1200
1333
1201
- # not supported yet
1202
- '''
1203
1334
def Func (args , ret , annotations ):
1204
1335
return FuncClass (args , ret , annotations )
1336
+
1205
1337
def Service (t ):
1206
1338
return ServiceClass (t )
1207
- '''
0 commit comments