123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140(* A loose implementation of version 3 of the UUID spec:
Version 3 UUIDs use a scheme deriving a UUID via MD5 from a URL, a fully
qualified domain name, an object identifier, a distinguished name (DN as used
in Lightweight Directory Access Protocol), or on names in unspecified
namespaces. Version 3 UUIDs have the form xxxxxxxx-xxxx-3xxx-xxxx-xxxxxxxxxxxx
with hexadecimal digits x.
*)moduleStable=structopenCore_kernel.Core_kernel_stablemoduleV1=structmoduleT=structtypet=string[@@derivingbin_io,compare,hash,sexp]include(valComparator.V1.make~compare~sexp_of_t)endincludeTincludeComparable.V1.Make(T)letfor_testing="5a863fc1-67b7-3a0a-dc90-aca2995afbf9"endendopen!Core_kernelmoduleT=structtypet=string[@@derivingbin_io,compare,hash]typecomparator_witness=Stable.V1.comparator_witnessletcomparator=Stable.V1.comparatorletnext_counter=letcounter=ref0in(fun()->(* In OCaml this doesn't allocate, and threads can't context switch except on
allocation *)incrcounter;!counter);;(* [create] is responsible for generating unique string identifiers. It should be clear
to a reader that the id generated has an extremely high probability of uniqueness
across all possible machines, processes, and threads of execution. *)letcreate~hostname~pid=letdigest=lettime=Time.now()inletcounter=next_counter()inletbase=String.concat~sep:"-"[hostname;Int.to_stringpid;Float.to_string_12(Time.Span.to_sec(Time.to_span_since_epochtime));Int.to_stringcounter]inMd5.to_hex(Md5.digest_stringbase)inlets=Bytes.create36inBytes.sets8'-';Bytes.sets13'-';Bytes.sets18'-';Bytes.sets23'-';Bytes.From_string.blit~src:digest~dst:s~src_pos:0~dst_pos:0~len:8;Bytes.From_string.blit~src:digest~dst:s~src_pos:8~dst_pos:9~len:4;Bytes.From_string.blit~src:digest~dst:s~src_pos:12~dst_pos:14~len:4;Bytes.From_string.blit~src:digest~dst:s~src_pos:16~dst_pos:19~len:4;Bytes.From_string.blit~src:digest~dst:s~src_pos:20~dst_pos:24~len:12;Bytes.sets14'3';Bytes.to_strings;;letto_string=ident(*{v
xxxxxxxx-xxxx-3xxx-xxxx-xxxxxxxxxxxx
012345678901234567890123456789012345
0 1 2 3
v}*)letchar_is_dashc=Char.equal'-'cletis_valid_exns=(* we don't check for a 3 in the version position (14) because we want to be
generous about accepting UUIDs generated by other versions of the protocol, and
we want to be resilient to future changes in this algorithm. *)assert(String.lengths=36);assert(String.counts~f:char_is_dash=4);assert(char_is_dashs.[8]);assert(char_is_dashs.[13]);assert(char_is_dashs.[18]);assert(char_is_dashs.[23]);;;letof_strings=tryis_valid_exns;swith|_->failwithf"%s: not a valid UUID"s();;endincludeTincludeIdentifiable.Make_using_comparator(structletmodule_name="Uuid"includeTincludeSexpable.Of_stringable(T)end)letinvariantt=ignore(of_stringt:t)letnil="00000000-0000-0000-0000-000000000000"moduleUnstable=structtypenonrect=t[@@derivingbin_io,compare,hash,sexp]endletto_string_humt=ifam_running_testthennilelseto_stringt;;letsexp_of_tt=ifam_running_testthensexp_of_tnilelsesexp_of_tt;;modulePrivate=structletcreate=createletis_valid_exn=is_valid_exnletnil=nilendletcreate()=raise_s[%message"[Uuid.create] is deprecated"]