123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238(*
* Copyright (c) 2013-2017 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.
*)open!ImportincludeContents_intfletlexemeex=ignore(Jsonm.encodee(`Lexemex))letrecencode_jsone=function|`Null->lexemee`Null|`Boolb->lexemee(`Boolb)|`Strings->lexemee(`Strings)|`Floatf->lexemee(`Floatf)|`Aa->lexemee`As;List.iter(encode_jsone)a;lexemee`Ae|`Oo->lexemee`Os;List.iter(fun(k,v)->lexemee(`Namek);encode_jsonev)o;lexemee`Oeletdecode_jsond=letdecoded=matchJsonm.decodedwith|`Lexemel->l|`Errore->failwith(Fmt.strf"%a"Jsonm.pp_errore)|_->failwith"invalid JSON encoding"inletrecunwrapvd=matchvwith|`Os->obj[]d|`As->arr[]d|(`Null|`Bool_|`String_|`Float_)asv->v|_->failwith"invalid JSON value"andarrvsd=matchdecodedwith|`Ae->`A(List.revvs)|v->letv=unwrapvdinarr(v::vs)dandobjmsd=matchdecodedwith|`Oe->`O(List.revms)|`Namek->letv=unwrap(decoded)dinobj((k,v)::ms)d|_->failwith"invalid JSON object"intryOk(unwrap(decoded)d)withFailuremsg->Error(`Msgmsg)typejson=[`Null|`Boolofbool|`Stringofstring|`Floatoffloat|`Oof(string*json)list|`Aofjsonlist][@@derivingirmin]moduleJson_value=structtypet=json[@@derivingirmin]letppfmtx=letbuffer=Buffer.create32inletencoder=Jsonm.encoder(`Bufferbuffer)inencode_jsonencoderx;ignore@@Jsonm.encodeencoder`End;lets=Buffer.contentsbufferinFmt.pffmt"%s"sletof_strings=letdecoder=Jsonm.decoder(`Strings)inmatchdecode_jsondecoderwithOkobj->Okobj|Error_aserr->errletequal_bool=Type.(unstage(equalbool))letequal_float=Type.(unstage(equalfloat))letrecequalab=match(a,b)with|`Null,`Null->true|`Boola,`Boolb->equal_boolab|`Stringa,`Stringb->String.equalab|`Floata,`Floatb->equal_floatab|`Aa,`Ab->(tryList.for_all2(funa'b'->equala'b')abwithInvalid_argument_->false)|`Oa,`Ob->(letcompare_fst(a,_)(b,_)=compareabintryList.for_all2(fun(k,v)(k',v')->k=k'&&equalvv')(List.sortcompare_fsta)(List.sortcompare_fstb)withInvalid_argument_->false)|_,_->falselett=Type.like~equal:(Type.stageequal)~pp~of_stringtletrecmerge_object~oldxy=letopenMerge.Infixinletm=Merge.(alistType.stringt(fun_key->option(vtmerge_value)))inMerge.(fm~oldxy)>>=*funx->Merge.ok(`Ox)andmerge_float~oldxy=letopenMerge.InfixinMerge.(ffloat~oldxy)>>=*funf->Merge.ok(`Floatf)andmerge_string~oldxy=letopenMerge.InfixinMerge.(fstring~oldxy)>>=*funs->Merge.ok(`Strings)andmerge_bool~oldxy=letopenMerge.InfixinMerge.(fbool~oldxy)>>=*funb->Merge.ok(`Boolb)andmerge_array~oldxy=letopenMerge.InfixinMerge.(f(Merge.idempotent(Type.listt))~oldxy)>>=*funx->Merge.ok(`Ax)andmerge_value~oldxy=letopenMerge.Infixinold()>>=*funold->match(old,x,y)with|Some`Null,_,_->merge_value~old:(fun()->Merge.okNone)xy|None,`Null,`Null->Merge.ok`Null|Some(`Floatold),`Floata,`Floatb->merge_float~old:(fun()->Merge.ok(Someold))ab|None,`Floata,`Floatb->merge_float~old:(fun()->Merge.okNone)ab|Some(`Stringold),`Stringa,`Stringb->merge_string~old:(fun()->Merge.ok(Someold))ab|None,`Stringa,`Stringb->merge_string~old:(fun()->Merge.okNone)ab|Some(`Boolold),`Boola,`Boolb->merge_bool~old:(fun()->Merge.ok(Someold))ab|None,`Boola,`Boolb->merge_bool~old:(fun()->Merge.okNone)ab|Some(`Aold),`Aa,`Ab->merge_array~old:(fun()->Merge.ok(Someold))ab|None,`Aa,`Ab->merge_array~old:(fun()->Merge.okNone)ab|Some(`Oold),`Oa,`Ob->merge_object~old:(fun()->Merge.ok(Someold))ab|None,`Oa,`Ob->merge_object~old:(fun()->Merge.okNone)ab|_,_,_->Merge.conflict"Conflicting JSON datatypes"letmerge_json=Merge.(vtmerge_value)letmerge=Merge.(optionmerge_json)endmoduleJson=structtypet=(string*json)list[@@derivingirmin]letppfmtx=letbuffer=Buffer.create32inletencoder=Jsonm.encoder(`Bufferbuffer)inencode_jsonencoder(`Ox);ignore@@Jsonm.encodeencoder`End;lets=Buffer.contentsbufferinFmt.pffmt"%s"sletof_strings=letdecoder=Jsonm.decoder(`Strings)inmatchdecode_jsondecoderwith|Ok(`Oobj)->Okobj|Ok_->Error(`Msg"Irmin JSON values must be objects")|Error_aserr->errletequalab=Json_value.equal(`Oa)(`Ob)lett=Type.like~equal:(Type.stageequal)~pp~of_stringtletmerge=Merge.(option(alistType.stringJson_value.t(fun_->Json_value.merge)))endmoduleString=structtypet=string[@@derivingirmin]letmerge=Merge.idempotentType.(optionstring)endmoduleStore(S:sigincludeS.CONTENT_ADDRESSABLE_STOREmoduleKey:Hash.Swithtypet=keymoduleVal:Swithtypet=valueend)=structmoduleKey=Hash.Typed(S.Key)(S.Val)moduleVal=S.Valtype'at='aS.ttypekey=S.keytypevalue=S.valueletfind=S.findletadd=S.addletunsafe_add=S.unsafe_addletmem=S.memletclear=S.clearletread_optt=functionNone->Lwt.return_none|Somek->findtkletadd_optt=function|None->Lwt.return_none|Somev->addtv>>=Lwt.return_someletmerget=Merge.like_lwtType.(optionKey.t)Val.merge(read_optt)(add_optt)endmoduleV1=structmoduleString=structincludeStringlett=Type.(boxed(string_of`Int64))letsize_of=Type.Size.ttletdecode_bin=Type.decode_bintletencode_bin=Type.encode_bintletpre_hash=Type.pre_hashtlett=Type.liket~bin:(encode_bin,decode_bin,size_of)~pre_hashendend