123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373(*
* Copyright (c) 2006-2009 Citrix Systems Inc.
* Copyright (c) 2006-2014 Thomas Gazagnaire <thomas@gazagnaire.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)letdebug=reffalseletset_debugx=debug:=xletget_debug()=!debugtypet=|Intofint64|Int32ofint32|Boolofbool|Floatoffloat|Stringofstring|DateTimeofstring|Enumoftlist|Dictof(string*t)list|Base64ofstring|NullmoduleVersion=structtypet=int*int*intletcompare(x,y,z)(x',y',z')=letcmpabfn()=letc=compareabinifc<>0thencelsefn()incmpxx'(cmpyy'(cmpzz'(fun()->0)))()endmoduleTypes=structtype_basic=|Int:intbasic|Int32:int32basic|Int64:int64basic|Bool:boolbasic|Float:floatbasic|String:stringbasic|Char:charbasictype_typ=|Basic:'abasic->'atyp|DateTime:stringtyp|Base64:stringtyp|Array:'atyp->'aarraytyp|List:'atyp->'alisttyp|Dict:'abasic*'btyp->('a*'b)listtyp|Unit:unittyp|Option:'atyp->'aoptiontyp|Tuple:'atyp*'btyp->('a*'b)typ|Tuple3:'atyp*'btyp*'ctyp->('a*'b*'c)typ|Tuple4:'atyp*'btyp*'ctyp*'dtyp->('a*'b*'c*'d)typ|Struct:'astructure->'atyp|Variant:'avariant->'atyp|Abstract:'aabstract->'atyp(* A type definition has a name and description *)and'adef={name:string;description:stringlist;ty:'atyp}andboxed_def=BoxedDef:'adef->boxed_defand('a,'s)field={fname:string;fdescription:stringlist;fversion:Version.toption;field:'atyp;fdefault:'aoption;fget:'s->'a;(* Lenses *)fset:'a->'s->'s}and'aboxed_field=BoxedField:('a,'s)field->'sboxed_fieldandfield_getter={field_get:'a.string->'atyp->('a,Rresult.R.msg)Result.t}and'astructure={sname:string;fields:'aboxed_fieldlist;version:Version.toption;constructor:field_getter->('a,Rresult.R.msg)Result.t}and('a,'s)tag={tname:string;tdescription:stringlist;tversion:Version.toption;tcontents:'atyp;tpreview:'s->'aoption;treview:'a->'s}and'aboxed_tag=BoxedTag:('a,'s)tag->'sboxed_tagandtag_getter={tget:'a.'atyp->('a,Rresult.R.msg)Result.t}and'avariant={vname:string;variants:'aboxed_taglist;vdefault:'aoption;vversion:Version.toption;vconstructor:string->tag_getter->('a,Rresult.R.msg)Result.t}and'aabstract={aname:string;test_data:'alist;rpc_of:'a->t;of_rpc:t->('a,Rresult.R.msg)Result.t}letint={name="int";ty=BasicInt;description=["Native integer"]}letint32={name="int32";ty=BasicInt32;description=["32-bit integer"]}letint64={name="int64";ty=BasicInt64;description=["64-bit integer"]}letbool={name="bool";ty=BasicBool;description=["Boolean"]}letfloat={name="float";ty=BasicFloat;description=["Floating-point number"]}letstring={name="string";ty=BasicString;description=["String"]}letchar={name="char";ty=BasicChar;description=["Char"]}letunit={name="unit";ty=Unit;description=["Unit"]}letdefault_types=[BoxedDefint;BoxedDefint32;BoxedDefint64;BoxedDefbool;BoxedDeffloat;BoxedDefstring;BoxedDefchar;BoxedDefunit]endexceptionRuntime_errorofstring*texceptionRuntime_exceptionofstring*stringletmap_stringssepfnl=String.concatsep(List.mapfnl)letrecto_stringt=letopenPrintfinmatchtwith|Inti->sprintf"I(%Li)"i|Int32i->sprintf"I32(%li)"i|Boolb->sprintf"B(%b)"b|Floatf->sprintf"F(%g)"f|Strings->sprintf"S(%s)"s|DateTimes->sprintf"D(%s)"s|Enumts->sprintf"[%s]"(map_strings";"to_stringts)|Dictts->sprintf"{%s}"(map_strings";"(fun(s,t)->sprintf"%s:%s"s(to_stringt))ts)|Base64s->sprintf"B64(%s)"s|Null->"N"letrpc_of_tx=xletrpc_of_int64i=Intiletrpc_of_int32i=Int(Int64.of_int32i)letrpc_of_inti=Int(Int64.of_inti)letrpc_of_boolb=Boolbletrpc_of_floatf=Floatfletrpc_of_strings=Stringsletrpc_of_dateTimes=DateTimesletrpc_of_base64s=Base64sletrpc_of_unit()=Nullletrpc_of_charx=Int(Int64.of_int(Char.codex))letint64_of_rpc=function|Inti->i|Strings->Int64.of_strings|x->failwith(Printf.sprintf"Expected int64, got '%s'"(to_stringx))letint32_of_rpc=function|Inti->Int64.to_int32i|Strings->Int32.of_strings|x->failwith(Printf.sprintf"Expected int32, got '%s'"(to_stringx))letint_of_rpc=function|Inti->Int64.to_inti|Strings->int_of_strings|x->failwith(Printf.sprintf"Expected int, got '%s'"(to_stringx))letbool_of_rpc=function|Boolb->b|x->failwith(Printf.sprintf"Expected bool, got '%s'"(to_stringx))letfloat_of_rpc=function|Floatf->f|Inti->Int64.to_floati|Int32i->Int32.to_floati|Strings->float_of_strings|x->failwith(Printf.sprintf"Expected float, got '%s'"(to_stringx))letstring_of_rpc=function|Strings->s|x->failwith(Printf.sprintf"Expected string, got '%s'"(to_stringx))letdateTime_of_rpc=function|DateTimes->s|x->failwith(Printf.sprintf"Expected DateTime, got '%s'"(to_stringx))letbase64_of_rpc=function|Base64s->Base64.decode_exns|x->failwith(Printf.sprintf"Expected base64, got '%s'"(to_stringx))letunit_of_rpc=function|Null->()|x->failwith(Printf.sprintf"Expected unit, got '%s'"(to_stringx))letchar_of_rpcx=letx=int_of_rpcxinifx<0||x>255thenfailwith(Printf.sprintf"Char out of range (%d)"x)elseChar.chrxlett_of_rpct=tletlowerfn=function|Strings->String(String.lowercase_asciis)|Enum(Strings::ss)->Enum(String(String.lowercase_asciis)::ss)|x->xmoduleResultUnmarshallers=structopenRresultletint64_of_rpc=function|Inti->R.oki|Strings->(tryR.ok(Int64.of_strings)with|_->R.error_msg(Printf.sprintf"Expected int64, got string '%s'"s))|x->R.error_msg(Printf.sprintf"Expected int64, got '%s'"(to_stringx))letint32_of_rpc=function|Inti->R.ok(Int64.to_int32i)|Strings->(tryR.ok(Int32.of_strings)with|_->R.error_msg(Printf.sprintf"Expected int32, got string '%s'"s))|x->R.error_msg(Printf.sprintf"Expected int32, got '%s'"(to_stringx))letint_of_rpc=function|Inti->R.ok(Int64.to_inti)|Strings->(tryR.ok(int_of_strings)with|_->R.error_msg(Printf.sprintf"Expected int, got string '%s'"s))|x->R.error_msg(Printf.sprintf"Expected int, got '%s'"(to_stringx))letbool_of_rpc=function|Boolb->R.okb|x->R.error_msg(Printf.sprintf"Expected bool, got '%s'"(to_stringx))letfloat_of_rpc=function|Floatf->R.okf|Inti->R.ok(Int64.to_floati)|Int32i->R.ok(Int32.to_floati)|Strings->(tryR.ok(float_of_strings)with|_->R.error_msg(Printf.sprintf"Expected float, got string '%s'"s))|x->R.error_msg(Printf.sprintf"Expected float, got '%s'"(to_stringx))letstring_of_rpc=function|Strings->R.oks|x->R.error_msg(Printf.sprintf"Expected string, got '%s'"(to_stringx))letdateTime_of_rpc=function|DateTimes->R.oks|x->R.error_msg(Printf.sprintf"Expected DateTime, got '%s'"(to_stringx))letbase64_of_rpc=function|Base64s->R.oks|x->R.error_msg(Printf.sprintf"Expected base64, got '%s'"(to_stringx))letunit_of_rpc=function|Null->R.ok()|x->R.error_msg(Printf.sprintf"Expected unit, got '%s'"(to_stringx))letchar_of_rpcx=Rresult.R.bind(int_of_rpcx)(funx->ifx<0||x>255thenR.error_msg(Printf.sprintf"Char out of range (%d)"x)elseR.ok(Char.chrx))lett_of_rpct=R.oktendletstruct_extendrpcdefault_rpc=matchrpc,default_rpcwith|Dictreal,Dictdefault_fields->Dict(List.fold_left(funreal(f,default)->ifList.mem_assocfrealthenrealelse(f,default)::real)realdefault_fields)|_,_->rpctypecallback=stringlist->t->unittypecall={name:string;params:tlist;is_notification:bool}letcallnameparams={name;params;is_notification=false}letnotificationnameparams={name;params;is_notification=true}letstring_of_callcall=Printf.sprintf"-> %s(%s)"call.name(String.concat","(List.mapto_stringcall.params))typeresponse={success:bool;contents:t;is_notification:bool}letstring_of_responseresponse=Printf.sprintf"<- %s(%s)"(ifresponse.successthen"success"else"failure")(to_stringresponse.contents)(* is_notification is to be set as true only if the call was a notification *)letsuccessv={success=true;contents=v;is_notification=false}letfailurev={success=false;contents=v;is_notification=false}