123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188moduletypeSTORE=sigtype'ard=<rd:unit;..>as'atype'awr=<wr:unit;..>as'atype'amode=|Rd:<rd:unit>mode|Wr:<wr:unit>mode|RdWr:<rd:unit;wr:unit>modetypettypeuidtype'afdtypeerrortype+'afibervalpp_error:errorFmt.tvalcreate:mode:'amode->t->uid->('afd,error)resultfibervalmap:t->'mrdfd->pos:int64->int->Bigstringaf.tvalclose:t->'mfd->(unit,error)resultfibervallist:t->uidlistfibervallength:'mfd->int64fiberendmoduletypeIO=sigtype+'atvalbind:'at->('a->'bt)->'btvalreturn:'a->'atendtype('fd,'uid)pack={pack:('fd*int64,'uid)Carton.Dec.t;index:'uidCarton.Dec.Idx.idx;z:Bigstringaf.t;w:De.window;}type('path,'fd,'uid)t={tbl:('path,('fd,'uid)pack)Hashtbl.t}[@@unbox]type'fdbuffers={z:Bigstringaf.t;allocate:int->De.window;w:'fdCarton.Dec.W.t;}moduleMake(Scheduler:Carton.SCHEDULER)(IO:IOwithtype+'at='aScheduler.s)(Store:STOREwithtype+'afiber='aScheduler.s)(Uid:Carton.UID)=structlet(>>=)=IO.bindletreturn=IO.returnlet(>>?)xf=x>>=functionOkx->fx|Error_aserr->returnerrlet(>>|)xf=x>>=funx->return(fx)letidx(root:Store.t)accpath=Store.create~mode:Store.Rdrootpath>>?funfd->Store.lengthfd>>=funlength->letpayload=Store.maprootfd~pos:0L(Int64.to_intlength)inStore.closerootfd>>?fun()->letidx=Carton.Dec.Idx.makepayload~uid_ln:Uid.length~uid_rw:Uid.to_raw_string~uid_wr:Uid.of_raw_stringinreturn(Ok(idx::acc))letpack(root:Store.t)acc(index,pack)=Store.create~mode:Store.Rdrootpack>>?funfd->Store.lengthfd>>=funlength->letz=Bigstringaf.createDe.io_buffer_sizeinletw=De.make_window~bits:15inletpack=Carton.Dec.make(fd,length)~z~allocate:(fun_->w)~uid_ln:Uid.length~uid_rw:Uid.of_raw_string(funuid->matchCarton.Dec.Idx.findindexuidwith|Some(_,offset)->offset|None->Fmt.invalid_arg"Object %a does not exist"Uid.ppuid)inreturn(Ok({pack;index;z;w}::acc))letfold_left_r?(err=fun_->return())fal=letrecgoa=function|[]->returna|x::r->(fax>>=function|Oka->goar|Errorx->errx>>=fun()->goar)ingoallet(<.>)fgx=f(gx)(* XXX(dinosaure): about design, I think that a listing of PACK files should be done
outside the scope of this module (or more generally outside the scope of the Git's core). *)letmake:Store.t->uid_of_major_uid:(Store.uid->'uid)->idx_major_uid_of_uid:(Store.t->'uid->Store.uid)->(Store.uid,<rd:unit>Store.fd,Uid.t)tIO.t=funroot~uid_of_major_uid~idx_major_uid_of_uid->Store.listroot>>=funpcks->letidxs=List.map(idx_major_uid_of_uidroot<.>uid_of_major_uid)pcksinfold_left_r(idxroot)[]idxs>>|List.rev>>=funidxs->fold_left_r(packroot)[](List.combineidxspcks)>>|List.rev>>=funvs->lettbl=Hashtbl.create10inList.iter(fun(k,v)->Hashtbl.addtblkv)(List.combinepcksvs);return{tbl}letmaproot(fd,top)~poslen=letmax=Int64.subtopposinletlen=min(Int64.of_intlen)maxinletlen=Int64.to_intleninStore.maprootfd~poslenletadd:Store.t->(Store.uid,<rd:unit>Store.fd,Uid.t)t->idx:Store.uid->Store.uid->(unit,Store.error)resultIO.t=funrootp~idx:idx_uidpck->idxroot[]idx_uid>>?funidxs->let[@warning"-8"][idx]=idxsinpackroot[](idx,pck)>>?funvs->List.iter(fun(k,v)->Hashtbl.addp.tblkv)(List.combine[pck]vs);return(Ok())letwith_resourcesrootpackuidbuffers=letmapfd~poslen=maprootfd~posleninletpack=Carton.Dec.with_zbuffers.zpackinletpack=Carton.Dec.with_allocate~allocate:buffers.allocatepackinletpack=Carton.Dec.with_wbuffers.wpackinletweight=Carton.Dec.weight_of_uid~mappack~weight:Carton.Dec.nulluidinletraw=Carton.Dec.make_raw~weightinletv=Carton.Dec.of_uid~mappackrawuidinreturnvletget:Store.t->resources:('fd->('fdbuffers->'aIO.t)->'aIO.t)->(Store.uid,<rd:unit>Store.fd,Uid.t)t->Uid.t->(Carton.Dec.v,[>`Msgofstring])resultIO.t=funroot~resourcespuid->letres=refNoneinHashtbl.iter(funk{index;_}->ifCarton.Dec.Idx.existsindexuidthenres:=Somek)p.tbl;match!reswith|Somek->let{pack;_}=Hashtbl.findp.tblkinresources(Carton.Dec.fdpack)(with_resourcesrootpackuid)>>=funv->return(Okv)|None->return(Error(`Not_founduid))letlist:Store.t->(Store.uid,'mStore.fd,Uid.t)t->Uid.tlist=fun_p->letfold_{index;_}a=letres=ref[]inCarton.Dec.Idx.iter~f:(fun~uid~offset:_~crc:_->res:=uid::!res)index;List.rev_append!resainHashtbl.foldfoldp.tbl[]letexists:Store.t->(Store.uid,'mStore.fd,Uid.t)t->Uid.t->bool=fun_puid->letres=reffalseinHashtbl.iter(fun_{index;_}->ifCarton.Dec.Idx.existsindexuidthenres:=true)p.tbl;!resletfds:(Store.uid,'mStore.fd,Uid.t)t->('mStore.fd*int64)list=fun{tbl}->letfold_{pack;_}a=Carton.Dec.fdpack::ainHashtbl.foldfoldtbl[]end