This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

4
unikernel/duniverse/uuidm/.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
_build
_b0
tmp
*.install

View file

@ -0,0 +1,4 @@
PKG b0.kit cmdliner
S src/**
S test/**
B _b0/**

View file

@ -0,0 +1 @@
strict_with=always,match_clause=4,strict_else=never

View file

@ -0,0 +1,58 @@
open B0_kit.V000
(* OCaml library names *)
let b0_std = B0_ocaml.libname "b0.std"
let cmdliner = B0_ocaml.libname "cmdliner"
let unix = B0_ocaml.libname "unix"
let uuidm = B0_ocaml.libname "uuidm"
(* Libraries *)
let uuidm_lib = B0_ocaml.lib uuidm ~srcs:[`Dir ~/"src"]
(* Tests *)
let test ?(requires = []) = B0_ocaml.test ~requires:(uuidm :: requires)
let perf = test ~/"test/perf.ml" ~run:false ~doc:"Test Uuidm performance"
let examples =
test ~/"test/examples.ml" ~run:false ~requires:[unix] ~doc:"Sample code"
let test_uuidm =
test ~/"test/test_uuidm.ml" ~requires:[b0_std] ~doc:"Test Uuidm"
(* Tools *)
let uuidtrip =
let doc = "Generates universally unique identifiers (UUIDs)" in
let srcs = [`File ~/"test/uuidtrip.ml"] in
let requires = [uuidm; unix; cmdliner] in
B0_ocaml.exe "uuidtrip" ~public:true ~doc ~srcs ~requires
(* Packs *)
let default =
let meta =
B0_meta.empty
|> ~~ B0_meta.authors ["The uuidm programmers"]
|> ~~ B0_meta.maintainers ["Daniel Bünzli <daniel.buenzl i@erratique.ch>"]
|> ~~ B0_meta.homepage "https://erratique.ch/software/uuidm"
|> ~~ B0_meta.online_doc "https://erratique.ch/software/uuidm/doc/"
|> ~~ B0_meta.licenses ["ISC"]
|> ~~ B0_meta.repo "git+https://erratique.ch/repos/uuidm.git"
|> ~~ B0_meta.issues "https://github.com/dbuenzli/uuidm/issues"
|> ~~ B0_meta.description_tags ["uuid"; "codec"; "org:erratique"]
|> B0_meta.tag B0_opam.tag
|> ~~ B0_opam.depopts ["cmdliner", ""]
|> ~~ B0_opam.conflicts [ "cmdliner", {|< "1.3.0"|}]
|> ~~ B0_opam.depends
[ "ocaml", {|>= "4.14.0"|};
"ocamlfind", {|build|};
"ocamlbuild", {|build|};
"topkg", {|build & >= "1.0.3"|};
]
|> B0_meta.add B0_opam.build
{|[["ocaml" "pkg/pkg.ml" "build" "--dev-pkg" "%{dev}%"
"--with-cmdliner" "%{cmdliner:installed}%"]]|}
in
B0_pack.make "default" ~doc:"uuidm package" ~meta ~locked:true @@
B0_unit.list ()

View file

@ -0,0 +1 @@
(srcs-x pkg)

View file

@ -0,0 +1,104 @@
v0.9.10 2025-03-10 La Forclaz (VS)
----------------------------------
- Install forgotten `index.mld` file.
- `uuidtrip`: handle `cmdliner` deprecations.
v0.9.9 2024-09-26 Zagreb
------------------------
- Add `Uuidm.{v7,v7_ns}` to create time and random based V7 UUIDs.
Thanks to Robin Newton for the patch (#14) and Christian Linding
and Pau Ruiz Safont for the help.
- Add `Uuidm.v7_[non_]monotonic_gen` V7 UUID generators.
- Add `Uuidm.v8` to create V8 custom UUIDs.
- Add `Uuidm.max` the RFC 9569 Max UUID.
- Add `Uuidm.{variant,version,time_ms}` UUID property accessors.
- Change `Uuidm.v4_gen` generation strategy.
- Call `Random.State.make_self_init` lazily rather than during module
initialisation.
- Documentation: clarified that `Random` based UUID generators are not stable
accross OCaml and Uuidm versions.
- Deprecate `Uuidm.v`, use individual version constructors instead.
- Deprecate type `Uuidm.version`.
- Deprecate `Uuidm.pp_string` to `Uuidm.pp'`.
- Deprecate `Uuidm.{to,of}_[mixed_endian_]bytes` to
`Uuidm.{to,of}_[mixed_endian_]binary_string` (follow `Stdlib` terminology).
- Require OCaml 4.14.
- `uuidtrip` set standard output to binary when outputing binary uuids.
- `uuidtrip` add options `--v3`, `--v4`, `--v5`, `--v7`.
- `uuidtrip` add support for time and random based v7 UUIDs generation.
v0.9.8 2022-02-09 La Forclaz (VS)
---------------------------------
- Add deprecation warnings on what is already deprecated.
- Require OCaml 4.08 and support 5.00 (Thanks to Kate @ki-ty-kate
for the patch).
v0.9.7 2019-03-08 La Forclaz (VS)
---------------------------------
- Add `Uuidm.v4`, creates random based V4 UUID using client provided
random bytes (#8). Thanks to François-René Rideau for suggesting and
David Kaloper Meršinjak for additional comments.
- Add `Uuidm.{to,of}_mixed_endian_bytes`. Support for UEFI and
Microsoft's binary serialization of UUIDs.
v0.9.6 2016-08-12 Zagreb
------------------------
- Safe-string support. Thanks to Josh Allmann for the help.
- Deprecate `Uuidm.create` in favor of `Uuidm.v`.
- Deprecate `Uuidm.print` in favor of `Uuidm.pp_string`
- Add `Uuidm.pp`.
- Relicensed from BSD3 to ISC.
- Build depend on topkg.
- `uuidtrip` uses `Cmdliner` which becomes an optional dependency of
the package. The command line interface is unchanged except for long
options which have to be written with a double dash. Binary output
no longer adds an ending newline.
v0.9.5 2012-08-05 Lausanne
--------------------------
- OASIS 0.3.0 support.
v0.9.4 2012-03-15 La Forclaz (VS)
---------------------------------
- OASIS support.
- New functions `Uuidm.v3` and `Uuidm.v5` that generate directly these
kinds of UUIDs.
- New function `Uuidm.v4_gen` returns a function that generates
version 4 UUIDs with a client provided random state. Thanks to Lauri
Alanko for suggesting that `Random.make_self_init` may be too weak
for certain usages.
v0.9.3 2008-08-01 Lausanne
--------------------------
- POSIX compliant build shell script.
v0.9.2 2008-07-30 Lausanne
--------------------------
- Support for debian packaging. Thanks to Sylvain Le Gall.
v0.9.1 2008-06-18 Lausanne
--------------------------
- Minor internal cleanings.
v0.9.0 2008-06-11 Lausanne
--------------------------
- First release.

View file

@ -0,0 +1,6 @@
This project uses (perhaps the development version of) [`b0`] for
development. Consult [b0 occasionally] for quick hints on how to
perform common development tasks.
[`b0`]: https://erratique.ch/software/b0
[b0 occasionally]: https://erratique.ch/software/b0/doc/occasionally.html

View file

@ -0,0 +1,13 @@
Copyright (c) 2008 The uuidm programmers
Permission to use, copy, modify, and/or 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.

View file

@ -0,0 +1,41 @@
Uuidm — Universally unique identifiers (UUIDs) for OCaml
========================================================
Uuidm is an OCaml library implementing 128 bits universally unique
identifiers version 3, 5 (named based with MD5, SHA-1 hashing), 4
(random based), 7 (time and random based) and 8 (custom) according to
[RFC 9562].
Uuidm has no dependency. It is distributed under the ISC license.
[RFC 9562]: https://www.rfc-editor.org/rfc/rfc9562
Homepage: <https://erratique.ch/software/uuidm>
## Installation
Uuidm can be installed with `opam`:
opam install uuidm
If you don't use `opam` consult the [`opam`](opam) file for build
instructions.
## Documentation
The documentation can be consulted [online] or via `odig doc uuidm`.
Questions are welcome but better asked on the [OCaml forum][ocaml-forum]
than on the issue tracker.
[online]: https://erratique.ch/software/uuidm/doc/
[ocaml-forum]: https://discuss.ocaml.org/
## Sample programs
The [`uuidtrip`] tool generates UUIDs and outputs them on stdout.
See also code in the [`test`] directory.
[`uuidtrip`]: test/uuidtrip.ml
[`test`]: test/

View file

@ -0,0 +1,4 @@
true : bin_annot, safe_string
<_b0> : -traverse
<src> : include
<test/uuidtrip.*> : package(cmdliner unix)

View file

@ -0,0 +1,101 @@
{0 Uuidm {%html: <span class="version">v0.9.10+dune</span>%}}
{!Uuidm} implements 128 bits universally unique identifiers version 3,
5 (named based with MD5, SHA-1 hashing), 4 (random based), 7 (time and
random based) and 8 (custom) according according to
{{:https://www.rfc-editor.org/rfc/rfc9562} RFC 9562}.
See the {{!quick}quick start}.
{1:uuidm_lib Library [uuidm]}
{!modules: Uuidm}
{1:quick Quick start}
{2:random_based Random V4 UUIDs}
The following [uuid] function generates V4 random UUIDs.
{[
let uuid = Uuidm.v4_gen (Random.State.make_self_init ())
let () = print_endline (Uuidm.to_string (uuid ()))
let () = print_endline (Uuidm.to_string (uuid ()))
]}
Make sure to read the {{!Uuidm.gen}warnings} about random generators.
{2:name_based Name based V5 UUIDs}
Name based V5 UUIDs can be used to generate [urn:uuid] URIs for atom
feed {{:https://www.rfc-editor.org/rfc/rfc4287#section-4.2.6}entry
IDs} to minimize the chances of feed replays.
First generate a random V4 UUID for the feed. For example with
the code of the previous section or with:
{@shell[
> uuidtrip
6228c5f9-7069-4519-9bf4-0b6e865f4c42
]}
Store this UUID preciously and use it as your feed ID:
{[
let feed_id ~feed_id = "urn:uuid:" ^ (Uuid.to_string feed_id)
]}
For feed entry IDs, use the feed UUID as a V5 namespace and the immutable
{{:https://www.rfc-editor.org/rfc/rfc4287#section-4.2.9}[atom:published]}
value of the entry as the data to hash:
{[
let entry_id ~feed_id ~rfc3339_stamp =
"urn:uuid:" ^ (Uuidm.to_string @@ Uuidm.v5 feed_id rfc3339_stamp)
]}
This assumes that
{ol
{- You do not publish two entries at exactly the same time.
{{:https://www.rfc-editor.org/rfc/rfc3339}RFC 3339} has
enough time granularity to ensure that.}
{- You do not change your publication dates. In atom they must in fact
not change, updates to entries must be specified
in {{:https://www.rfc-editor.org/rfc/rfc4287#section-4.2.15}[atom:updated]}.}
{- If you store publication dates as a raw POSIX timestamp be careful
to render them to RFC 3339 with a fixed time zone. Alternatively
you can directly use the decimal representation of the timestamp
as the data to hash.}}
{2:time_based Monotonic time based V7 UUIDs}
In order to generate monotonic time based V7 UUIDs we need to:
{ul
{- Provide a millisecond precision monotonic POSIX clock. {!Unix.gettimeofday}
can provide a reasonable one but if your monotonicity requirements are
paramount, remember that it can go back in time.}
{- Do something if the clock doesn't move between two UUID
generations. The {!Uuidm.v7_monotonic_gen} generator uses a counter which
allows to generate up to 4096 UUID per millisecond and returns [None] in case
of rollover during the millisecond. In the code below we {!Unix.sleepf}
for a millisecond if we reach the limit.}}
{[
let uuid_monotonic =
let now_ms () = Int64.of_float (Unix.gettimeofday () *. 1000.) in
Uuidm.v7_monotonic_gen ~now_ms (Random.State.make_self_init ())
let rec uuid () = match uuid_monotonic () with
| None -> (* Too many UUIDs generated in a ms *) Unix.sleepf 1e-3; uuid ()
| Some uuid -> uuid
let () = print_endline (Uuidm.to_string (uuid ()))
let () = print_endline (Uuidm.to_string (uuid ()))
]}
Depending on your application {!Uuidm.v7_monotonic_gen} may be a bit
too simplistic, you can easily implement all sorts of other
{{:https://www.rfc-editor.org/rfc/rfc9562#name-monotonicity-and-counters}
generation schemes} by using {!Uuidm.v7} or {!Uuidm.v7_ns} directly. Also, make
sure to read the {{!Uuidm.gen}warnings} about generators.

View file

@ -0,0 +1,3 @@
(lang dune 1.0)
(name uuidm)
(version v0.9.10+dune)

View file

@ -0,0 +1,8 @@
description = "Universally unique identifiers (UUIDs) for OCaml"
version = "0.9.10+dune"
requires = ""
archive(byte) = "uuidm.cma"
archive(native) = "uuidm.cmxa"
plugin(byte) = "uuidm.cma"
plugin(native) = "uuidm.cmxs"
exists_if = "uuidm.cma uuidm.cmxa"

View file

@ -0,0 +1,12 @@
#!/usr/bin/env ocaml
#use "topfind";;
#require "topkg"
open Topkg
let cmdliner = Conf.with_pkg "cmdliner"
let () =
Pkg.describe "uuidm" @@ fun c ->
let cmdliner = Conf.value c cmdliner in
Ok [ Pkg.mllib "src/uuidm.mllib";
Pkg.doc "doc/index.mld" ~dst:"odoc-pages/index.mld";
Pkg.bin ~cond:cmdliner "test/uuidtrip" ]

View file

@ -0,0 +1,4 @@
(library
(name uuidm)
(public_name uuidm)
(wrapped false))

View file

@ -0,0 +1,322 @@
(*---------------------------------------------------------------------------
Copyright (c) 2008 The uuidm programmers. All rights reserved.
SPDX-License-Identifier: ISC
---------------------------------------------------------------------------*)
(* Bits *)
type bits62 = int64
type bits4 = int
type bits12 = int
(* Hashing *)
let md5 = Digest.string
let sha_1 s =
(* Based on pseudo-code of RFC 3174. Slow and ugly but does the job. *)
let sha_1_pad s =
let len = String.length s in
let blen = 8 * len in
let rem = len mod 64 in
let mlen = if rem > 55 then len + 128 - rem else len + 64 - rem in
let m = Bytes.create mlen in
Bytes.blit_string s 0 m 0 len;
Bytes.fill m len (mlen - len) '\x00';
Bytes.set m len '\x80';
if Sys.word_size > 32 then begin
Bytes.set_uint8 m (mlen - 8) (blen lsr 56 land 0xFF);
Bytes.set_uint8 m (mlen - 7) (blen lsr 48 land 0xFF);
Bytes.set_uint8 m (mlen - 6) (blen lsr 40 land 0xFF);
Bytes.set_uint8 m (mlen - 5) (blen lsr 32 land 0xFF);
end;
Bytes.set_uint8 m (mlen - 4) (blen lsr 24 land 0xFF);
Bytes.set_uint8 m (mlen - 3) (blen lsr 16 land 0xFF);
Bytes.set_uint8 m (mlen - 2) (blen lsr 8 land 0xFF);
Bytes.set_uint8 m (mlen - 1) (blen land 0xFF);
m
in
(* Operations on int32 *)
let ( &&& ) = ( land ) in
let ( lor ) = Int32.logor in
let ( lxor ) = Int32.logxor in
let ( land ) = Int32.logand in
let ( ++ ) = Int32.add in
let lnot = Int32.lognot in
let sl = Int32.shift_left in
let cls n x = (sl x n) lor (Int32.shift_right_logical x (32 - n)) in
(* Start *)
let m = sha_1_pad s in
let w = Array.make 16 0l in
let h0 = ref 0x67452301l in
let h1 = ref 0xEFCDAB89l in
let h2 = ref 0x98BADCFEl in
let h3 = ref 0x10325476l in
let h4 = ref 0xC3D2E1F0l in
let a = ref 0l in
let b = ref 0l in
let c = ref 0l in
let d = ref 0l in
let e = ref 0l in
for i = 0 to ((Bytes.length m) / 64) - 1 do (* For each block *)
(* Fill w *)
let base = i * 64 in
for j = 0 to 15 do w.(j) <- Bytes.get_int32_be m (base + (j * 4)); done;
(* Loop *)
a := !h0; b := !h1; c := !h2; d := !h3; e := !h4;
for t = 0 to 79 do
let f, k =
if t <= 19 then (!b land !c) lor ((lnot !b) land !d), 0x5A827999l else
if t <= 39 then !b lxor !c lxor !d, 0x6ED9EBA1l else
if t <= 59 then
(!b land !c) lor (!b land !d) lor (!c land !d), 0x8F1BBCDCl
else
!b lxor !c lxor !d, 0xCA62C1D6l
in
let s = t &&& 0xF in
if (t >= 16) then begin
w.(s) <- cls 1 begin
w.((s + 13) &&& 0xF) lxor
w.((s + 8) &&& 0xF) lxor
w.((s + 2) &&& 0xF) lxor
w.(s)
end
end;
let temp = (cls 5 !a) ++ f ++ !e ++ w.(s) ++ k in
e := !d;
d := !c;
c := cls 30 !b;
b := !a;
a := temp;
done;
(* Update *)
h0 := !h0 ++ !a;
h1 := !h1 ++ !b;
h2 := !h2 ++ !c;
h3 := !h3 ++ !d;
h4 := !h4 ++ !e
done;
let h = Bytes.create 20 in
let i2s h k i = Bytes.set_int32_be h k i in
i2s h 0 !h0;
i2s h 4 !h1;
i2s h 8 !h2;
i2s h 12 !h3;
i2s h 16 !h4;
Bytes.unsafe_to_string h
(* Uuids *)
type t = string (* 16 bytes *)
let make u ~version =
let b6 = (version lsl 4) lor ((Bytes.get_uint8 u 6) land 0b0000_1111) in
let b8 = 0b1000_0000 lor ((Bytes.get_uint8 u 8) land 0b0011_1111) in
Bytes.set_uint8 u 6 b6;
Bytes.set_uint8 u 8 b8;
Bytes.unsafe_to_string u
let make_named ~version digest ns n =
let hash = Bytes.unsafe_of_string (digest (ns ^ n)) in
make (Bytes.sub hash 0 16) ~version
let v3 ns n = make_named ~version:3 md5 ns n
let v5 ns n = make_named ~version:5 sha_1 ns n
let v4 b = make (Bytes.sub b 0 16) ~version:4
let v7 ~time_ms ~rand_a ~rand_b =
let u = Bytes.create 16 in
Bytes.set_int64_be u 0 (Int64.shift_left time_ms 16);
Bytes.set_int16_be u 6 rand_a;
Bytes.set_int64_be u 8 rand_b;
make u ~version:7
let v7_ns ~time_ns ~rand_b =
let ns_in_ms = 1_000_000L in
let sub_ms_frac_multiplier = Int64.unsigned_div Int64.minus_one ns_in_ms in
let u = Bytes.create 16 in
(* RFC 9562 requires we use 48 bits for a timestamp in milliseconds, and
allows for 12 bits to store a sub-millisecond fraction. We get the
latter by multiplying to put the fraction in a 64-bit range, then
shifting into 12 bits. *)
let ms = Int64.unsigned_div time_ns ns_in_ms in
let ns = Int64.unsigned_rem time_ns ns_in_ms in
let sub_ms_frac =
Int64.shift_right_logical (Int64.mul ns sub_ms_frac_multiplier) 52
in
Bytes.set_int64_be u 0 (Int64.shift_left ms 16);
Bytes.set_int16_be u 6 (Int64.to_int sub_ms_frac);
Bytes.set_int64_be u 8 rand_b;
make u ~version:7
let v8 s =
let l = String.length s in
if l = 16 then make (Bytes.of_string s) ~version:8 else
invalid_arg (Printf.sprintf "expected 16 bytes but found: %d" l)
(* Generators *)
type posix_ms_clock = unit -> int64
let v4_random rstate =
let r0 = Random.State.bits64 rstate in
let r1 = Random.State.bits64 rstate in
let u = Bytes.create 16 in
Bytes.set_int64_be u 0 r0;
Bytes.set_int64_be u 8 r1;
make u ~version:4
let v4_gen rstate = function () -> v4_random rstate
let v7_non_monotonic_gen ~now_ms rstate =
fun () ->
let time_ms = now_ms () in
let rand_a = Random.State.bits (* 30 bits *) rstate in
let rand_b = Random.State.bits64 rstate in
v7 ~time_ms ~rand_a ~rand_b
let v7_monotonic_gen ~now_ms rstate =
let last_ms = ref 0L in
let count = ref 0 in
fun () ->
let time_ms = now_ms () in
let rand_b = Random.State.bits64 rstate in
if Int64.equal time_ms !last_ms then
let rand_a = incr count; !count in
if rand_a >= 4096 then None else Some (v7 ~time_ms ~rand_a ~rand_b)
else
(count := 0; last_ms := time_ms; Some (v7 ~time_ms ~rand_a:0 ~rand_b))
(* Constants *)
let nil = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
let max = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
let ns_dns = "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8"
let ns_url = "\x6b\xa7\xb8\x11\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8"
let ns_oid = "\x6b\xa7\xb8\x12\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8"
let ns_X500 ="\x6b\xa7\xb8\x14\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8"
(* Properties *)
let variant u = (String.get_uint8 u 8) lsr 4
let version u = (String.get_uint8 u 6) lsr 4
let time_ms u =
let variant = variant u in
if not (0x8 <= variant && variant <= 0xB && version u = 7) then None else
Some (Int64.shift_right_logical (String.get_int64_be u 0) 16)
(* Predicates and comparisons *)
let equal = String.equal
let compare = String.compare
(* Standard binary format *)
let to_binary_string s = s
let of_binary_string ?(pos = 0) s =
let len = String.length s in
if pos + 16 > len then None else
if pos = 0 && len = 16 then Some s else
Some (String.sub s pos 16)
(* Mixed endian binary format *)
let mixed_swaps s =
let swap b i j =
let t = Bytes.get b i in
Bytes.set b i (Bytes.get b j);
Bytes.set b j t
in
let b = Bytes.of_string s in
swap b 0 3; swap b 1 2;
swap b 4 5; swap b 6 7;
Bytes.unsafe_to_string b
let to_mixed_endian_binary_string s = mixed_swaps s
let of_mixed_endian_binary_string ?pos s =
Option.map mixed_swaps (of_binary_string ?pos s)
(* Unsafe conversions *)
let unsafe_of_binary_string u = u
let unsafe_to_binary_string u = u
(* US-ASCII format *)
let of_string ?(pos = 0) s =
let len = String.length s in
if
pos + 36 > len || s.[pos + 8] <> '-' || s.[pos + 13] <> '-' ||
s.[pos + 18] <> '-' || s.[pos + 23] <> '-'
then
None
else try
let u = Bytes.create 16 in
let i = ref 0 in
let j = ref pos in
let ihex c =
let i = Char.code c in
if i < 0x30 then raise Exit else
if i <= 0x39 then i - 0x30 else
if i < 0x41 then raise Exit else
if i <= 0x46 then i - 0x37 else
if i < 0x61 then raise Exit else
if i <= 0x66 then i - 0x57 else
raise Exit
in
let byte s j = Char.unsafe_chr (ihex s.[j] lsl 4 lor ihex s.[j + 1]) in
while (!i < 4) do Bytes.set u !i (byte s !j); j := !j + 2; incr i done;
incr j;
while (!i < 6) do Bytes.set u !i (byte s !j); j := !j + 2; incr i done;
incr j;
while (!i < 8) do Bytes.set u !i (byte s !j); j := !j + 2; incr i done;
incr j;
while (!i < 10) do Bytes.set u !i (byte s !j); j := !j + 2; incr i done;
incr j;
while (!i < 16) do Bytes.set u !i (byte s !j); j := !j + 2; incr i done;
Some (Bytes.unsafe_to_string u)
with Exit -> None
let to_string ?(upper = false) u =
let hbase = if upper then 0x37 else 0x57 in
let hex hbase i = Char.unsafe_chr (if i < 10 then 0x30 + i else hbase + i) in
let s = Bytes.of_string "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" in
let i = ref 0 in
let j = ref 0 in
let byte s i c =
Bytes.set s i @@ hex hbase (c lsr 4);
Bytes.set s (i + 1) @@ hex hbase (c land 0x0F)
in
while (!j < 4) do byte s !i (Char.code u.[!j]); i := !i + 2; incr j; done;
incr i;
while (!j < 6) do byte s !i (Char.code u.[!j]); i := !i + 2; incr j; done;
incr i;
while (!j < 8) do byte s !i (Char.code u.[!j]); i := !i + 2; incr j; done;
incr i;
while (!j < 10) do byte s !i (Char.code u.[!j]); i := !i + 2; incr j; done;
incr i;
while (!j < 16) do byte s !i (Char.code u.[!j]); i := !i + 2; incr j; done;
Bytes.unsafe_to_string s
(* Pretty-printing *)
let pp ppf u = Format.pp_print_string ppf (to_string u)
let pp' ~upper ppf u = Format.pp_print_string ppf (to_string ~upper u)
(* Deprecated *)
let default_seed = lazy (Random.State.make_self_init ())
type version = [ `V3 of t * string | `V4 | `V5 of t * string ]
let v = function
| `V4 -> v4_random (Lazy.force default_seed)
| `V3 (ns, n) -> v3 ns n
| `V5 (ns, n) -> v5 ns n
let create = v (* deprecated *)
let pp_string ?upper ppf u = Format.pp_print_string ppf (to_string ?upper u)
let print = pp_string (* deprecated *)
let to_bytes = to_binary_string
let of_bytes = of_binary_string
let to_mixed_endian_bytes = to_mixed_endian_binary_string
let of_mixed_endian_bytes = of_mixed_endian_binary_string
let unsafe_of_bytes = unsafe_of_binary_string
let unsafe_to_bytes = unsafe_to_binary_string

View file

@ -0,0 +1,272 @@
(*---------------------------------------------------------------------------
Copyright (c) 2008 The uuidm programmers. All rights reserved.
SPDX-License-Identifier: ISC
---------------------------------------------------------------------------*)
(** Universally unique identifiers (UUIDs).
[Uuidm] implements 128 bits universally unique identifiers version
3, 5 (name based with MD5, SHA-1 hashing), 4 (random based), 7
(random and timestamp based) and 8 (custom) according to
{{:https://www.rfc-editor.org/rfc/rfc9562}RFC 9562}.
See the {{!page-index.quick}quick start}. *)
(** {1:bits Bits} *)
type bits4 = int
(** The type for 4 bits stored in the 4 lower bits of an [int] value.
The higher bits are either set to zero or ignored on use. *)
type bits12 = int
(** The type for 12 bits stored in the 12 lower bits of an [int] value.
The higher bits are either set to zero or ignored on use. *)
type bits62 = int64
(** The type for 62 bits stored in the 62 lower bits of an [int64] value.
The higher bits are either set to zero or ignored on use. *)
(** {1:uuids UUIDs} *)
type t
(** The type for UUIDs. *)
val v3 : t -> string -> t
(** [v3 ns n] is a
{{:https://www.rfc-editor.org/rfc/rfc9562#name-uuid-version-3}V3 UUID}
(name based with MD5 hashing) named by [n] and namespaced by [ns]. *)
val v4 : bytes -> t
(** [v4 b] is a {{:https://www.rfc-editor.org/rfc/rfc9562#name-uuid-version-4}
V4 UUID} (random based) that uses the first 16 bytes of
[b] for randomness. See also {!v4_gen}.
{b Warning.} The randomness is seen literally in the result. *)
val v5 : t -> string -> t
(** [v5 ns n] is a
{{:https://www.rfc-editor.org/rfc/rfc9562#name-uuid-version-5}V5 UUID}
(name based with SHA-1 hashing) named by [n] and
namespaced by [ns]. See {{!page-index.name_based}this example}. *)
val v7 : time_ms:int64 -> rand_a:bits12 -> rand_b:bits62 -> t
(** [v7 ~time_ms ~rand_a ~rand_b] is a
{{:https://www.rfc-editor.org/rfc/rfc9562#name-uuid-version-7}V7 UUID}
(time and random based) using the 64-bit millisecond POSIX timestamp
[time_ms] and random bits [rand_a] and [rand_b]. See also {!v7_ns},
{!v7_non_monotonic_gen} and {!v7_monotonic_gen}.
{b Warning.} The timestamp and the randomness are seen literally
in the result. *)
val v7_ns : time_ns:int64 -> rand_b:bits62 -> t
(** [v7_ns ~time_ns ~rand_b] is a
{{:https://www.rfc-editor.org/rfc/rfc9562#name-uuid-version-7}V7
UUID} (time and random based) using the {e unsigned} 64-bit
nanosecond POSIX timestamp [time_ns] and random bits [rand_b]. The
[rand_a] field is used with the timestamp's submillisecond precision
with about 244 nanoseconds resolution. See also {!v7}.
{b Warning.} The timestamp and the randomness are seen literally in
the result. *)
val v8 : string -> t
(** [v8 s] is a {{:https://www.rfc-editor.org/rfc/rfc9562#name-uuid-version-8}
V8 UUID} (custom) that uses the 16 bytes of [s] but overwrites the
{!version} and {!variant} bits to make it a propert V8 UUID. Raises
[Invalid_argument] if the length of [s] is not [16]. *)
(** {1:gen Generators}
{b Warning.} If you use the generators take into account the following
points:
{ul
{- Sequences of UUIDs are generated with {!Random}. This is
suitably random but {e predictable} by an observer. Use the
base constuctors with random bytes generated by a
cryptographically secure pseudorandom number generator (CSPRNG) if that
is an issue.}
{- Sequences of UUIDs generated from a given {!Random.State.t}
value are not guaranteed to be stable across OCaml or Uuidm versions.
Use the base constructors with your own
pseudorandom number generator if that is an issue.}
{- Sequences of UUIDs generated using a {!posix_ms_clock} assume
the clock is monotonic in order to generate monotonic UUIDs.
If you derive it from {!Unix.gettimeofday} this may not be the case.}} *)
type posix_ms_clock = unit -> int64
(** The type for millisecond precision POSIX time clocks. *)
val v4_gen : Random.State.t -> (unit -> t)
(** [v4_gen state] is a function generating {!v4} UUIDs using
random [state]. See {{!page-index.random_based}this example}. *)
val v7_non_monotonic_gen :
now_ms:posix_ms_clock -> Random.State.t -> (unit -> t)
(** [v7_non_monotonic_gen ~now_ms state] is a function generating
{!v7} UUIDs using [now_ms] for the timestamp [time_ms] and random [state]
for [rand_a] and [rand_b]. UUIDs generated in the same millisecond
may not be be monotonic. Use {!v7_monotonic_gen} for that. *)
val v7_monotonic_gen :
now_ms:posix_ms_clock -> Random.State.t -> (unit -> t option)
(** [v7_monotonic_gen ~posix_now_ms state] is a function that
generates monotonic {!v7} UUIDs using [now_ms] for the timestamp
[time_ms], [rand_a] as a counter if the clock did not move between
two UUID generations and [random] state for [rand_b]. This allows
to generate up to 4096 monotonic UUIDs per millisecond. [None] is
returned if the counter rolls over before the millisecond
increments. See {{!page-index.time_based}this example}.*)
(** {1:constants Constants} *)
val nil : t
(** [nil] is the
{{:https://www.rfc-editor.org/rfc/rfc9562#name-nil-uuid}nil} UUID. *)
val max : t
(** [max] is the {{:https://www.rfc-editor.org/rfc/rfc9562#name-max-uuid}max}
UUID. *)
val ns_dns : t
(** [ns_dns] is the DNS namespace UUID. *)
val ns_url : t
(** [ns_url] is the URL namespace UUID. *)
val ns_oid : t
(** [ns_oid] is the ISO OID namespace UUID. *)
val ns_X500 : t
(** [ns_dn] is the X.500 DN namespace UUID. *)
(** {1:properties Properties} *)
val variant : t -> bits4
(** [variant u] is the
{{:https://www.rfc-editor.org/rfc/rfc9562#name-variant-field}variant field}
of [u], including the "don't-care" values. *)
val version : t -> bits4
(** [version u] is the
{{:https://www.rfc-editor.org/rfc/rfc9562#name-version-field}version field}
of [u]. *)
val time_ms : t -> int64 option
(** [time_ms u] is the
{{:https://www.rfc-editor.org/rfc/rfc9562#name-uuid-version-7}
[unit_ts_ms]} millisecond POSIX timestamp of [u] as a 64-bit
integer. This is [None] if [u] is not a V7 UUID. *)
(** {1:preds Predicates and comparisons} *)
val equal : t -> t -> bool
(** [equal u u'] is [true] iff [u] and [u'] are equal. *)
val compare : t -> t -> int
(** [compare] is the binary order on UUIDs. *)
(** {1:fmt_binary Standard binary format}
This is the binary format mandated by
{{:https://www.rfc-editor.org/rfc/rfc9562#name-uuid-format}RFC 9562}. *)
val of_binary_string : ?pos:int -> string -> t option
(** [of_binary_string pos s] is the UUID represented by the 16 bytes starting
at [pos] (defaults to [0]) in [s]. No particular checks are
performed on the bytes. The result is [None] if the string is not
long enough. *)
val to_binary_string : t -> string
(** [to_binary_string u] is [u] as a 16 bytes long string. *)
(** {1:fmt_binary_mixed Mixed-endian binary format}
This is the binary format in which the three first fields of UUIDs
(which are oblivious to this module) are read and written in
little-endian. This corresponds to how UEFI or Microsoft formats
UUIDs. *)
val of_mixed_endian_binary_string : ?pos:int -> string -> t option
(** [of_mixed_endian_binary_string] is like {!of_bytes} but decodes
the mixed endian serialization. *)
val to_mixed_endian_binary_string : t -> string
(** [to_mixed_endian_binary_string] is like {!to_bytes} but encodes
the mixed endian serialization. *)
(**/**)
val unsafe_of_binary_string : string -> t
val unsafe_to_binary_string : t -> string
(**/**)
(** {1:fmt_ascii US-ASCII format} *)
val of_string : ?pos:int -> string -> t option
(** [of_string pos s] converts the substring of [s] starting at [pos]
(defaults to [0]) of the form ["XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"]
where X is a lower or upper case hexadecimal number to an
UUID. The result is [None] if a parse error occurs. Any extra
characters after are ignored. *)
val to_string : ?upper:bool -> t -> string
(** [to_string u] is [u] as a string of the form
["XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"] where X is a lower
(or upper if [upper] is [true]) case hexadecimal number. *)
val pp : Format.formatter -> t -> unit
(** [pp ppf u] formats [u] with {!to_string} on [ppf]. *)
val pp' : upper:bool -> Format.formatter -> t -> unit
(** [pp' ~upper ppf u] formats [u] with {!to_string}[ ~upper] on [ppf]. *)
(** {1:deprecated Deprecated} *)
type[@ocaml.deprecated "Use the version specific Uuidm.v* functions."] version =
[ `V3 of t * string (** Name based with MD5 hashing *)
| `V4 (** Random based *)
| `V5 of t * string (** Name based with SHA-1 hasing *) ]
(** The type for UUID versions and generation parameters.
{ul
{- [`V3] and [`V5] specify a namespace and a name for the generation.}
{- [`V4] is random based with a private state seeded with
{!Stdlib.Random.State.make_self_init}. Use {!v4_gen} to specify
your own seed. Use {!v4} to specify your own randomness.
{b Warning.} The sequence resulting from repeatedly calling
[v `V4] is random but predictable see {!v4_gen}.}} *)
[@@@alert "-deprecated"]
val v : version -> t
[@@ocaml.deprecated "Use the version specific Uuidm.v* functions."]
val pp_string : ?upper:bool -> Format.formatter -> t -> unit
[@@ocaml.deprecated "Use Uuidm.pp' instead"]
val of_bytes : ?pos:int -> string -> t option
[@@ocaml.deprecated "Use Uuidm.of_binary_string instead"]
val to_bytes : t -> string
[@@ocaml.deprecated "Use Uuidm.to_binary_string instead"]
val of_mixed_endian_bytes : ?pos:int -> string -> t option
[@@ocaml.deprecated "Use Uuidm.of_mixed_endian_binary_string instead"]
val to_mixed_endian_bytes : t -> string
[@@ocaml.deprecated "Use Uuidm.to_mixed_endian_binary_string instead"]
(**/**)
val print : ?upper:bool -> Format.formatter -> t -> unit (* deprecated *)
[@@ocaml.deprecated "Use Uuidm.pp_string instead"]
val create : version -> t (* deprecated *)
[@@ocaml.deprecated "Use Uuidm.v instead"]
val unsafe_of_bytes : string -> t
[@@ocaml.deprecated "Use Uuidm.unsafe_of_binary_string instead"]
val unsafe_to_bytes : t -> string
[@@ocaml.deprecated "Use Uuidm.unsafe_to_binary_string instead"]
(**/**)

View file

@ -0,0 +1 @@
Uuidm

View file

@ -0,0 +1,25 @@
(*---------------------------------------------------------------------------
Copyright (c) 2024 The uuidm programmers. All rights reserved.
SPDX-License-Identifier: CC0-1.0
---------------------------------------------------------------------------*)
(* Code from the quick start *)
let uuid = Uuidm.v4_gen (Random.State.make_self_init ())
let () = print_endline (Uuidm.to_string (uuid ()))
let () = print_endline (Uuidm.to_string (uuid ()))
let feed_id ~feed_id = "urn:uuid:" ^ (Uuidm.to_string feed_id)
let entry_id ~feed_id ~rfc3339_stamp =
"urn:uuid:" ^ (Uuidm.to_string @@ Uuidm.v5 feed_id rfc3339_stamp)
let uuid_monotonic =
let now_ms () = Int64.of_float (Unix.gettimeofday () *. 1000.) in
Uuidm.v7_monotonic_gen ~now_ms (Random.State.make_self_init ())
let rec uuid () = match uuid_monotonic () with
| None -> (* Too many UUIDs generated in a ms *) Unix.sleepf 1e-3; uuid ()
| Some uuid -> uuid
let () = print_endline (Uuidm.to_string (uuid ()))
let () = print_endline (Uuidm.to_string (uuid ()))

View file

@ -0,0 +1,39 @@
(* This code is in the public domain *)
let str = Printf.sprintf
let exec = Filename.basename Sys.executable_name
let main () =
let usage =
str "Usage: %s [OPTION]...\n\
\ UUID performance tests.\n\
Options:" exec
in
let n = ref 10_000_000 in
let v = ref `V4 in
let cstr = ref false in
let options = [
"-n", Arg.Set_int n,
"<int> Number of ids to generate";
"-str", Arg.Set cstr,
" Also convert UUIDs to strings";
"-r", Arg.Unit (fun () -> v := `V4),
" Random based UUID version 4 (default)";
"-md5", Arg.Unit (fun () -> v := `V3 (Uuidm.ns_dns,"www.example.org")),
" MD5 name based UUID version 3";
"-sha1", Arg.Unit (fun () -> v := `V5 (Uuidm.ns_dns,"www.example.org")),
" SHA-1 name based UUID version 5"; ]
in
Arg.parse (Arg.align options) (fun _ -> ()) usage;
let uuid = match !v with
| `V4 -> Uuidm.v4_gen (Random.State.make_self_init ())
| `V3 (ns, n) -> fun () -> Uuidm.v3 ns n
| `V5 (ns, n) -> fun () -> Uuidm.v5 ns n
in
let f = match !cstr with
| true -> fun version -> ignore (Uuidm.to_string (uuid ()))
| false -> fun version -> ignore (uuid ())
in
for i = 1 to !n do f v done
let () = main ()

View file

@ -0,0 +1,90 @@
(*---------------------------------------------------------------------------
Copyright (c) 2024 The uuidm programmers. All rights reserved.
SPDX-License-Identifier: ISC
---------------------------------------------------------------------------*)
open B0_testing
let test_uuid ?__POS__:pos version ?time_ms u us =
Test.block ?__POS__:pos @@ fun () ->
let us = Test.noraise ~__POS__ @@ fun () -> Option.get (Uuidm.of_string us) in
let trip =
Test.noraise ~__POS__ @@ fun () ->
Option.get (Uuidm.of_string (Uuidm.to_string u))
in
let variant = Uuidm.variant u in
Test.eq (module Uuidm) u trip ~__POS__;
Test.eq (module Uuidm) u us ~__POS__ ;
if Uuidm.equal u Uuidm.nil then Test.int variant 0x0 ~__POS__ else
if Uuidm.equal u Uuidm.max then Test.int variant 0xF ~__POS__ else
Test.holds (8 <= variant && variant <= 0xB) ~__POS__;
Test.int (Uuidm.version u) version ~__POS__;
Test.(option T.int64) (Uuidm.time_ms u) time_ms ~__POS__;
()
let test_constructors =
Test.test "Uuid.v* constructors" @@ fun () ->
test_uuid ~__POS__ 3
(Uuidm.v3 Uuidm.ns_dns "www.widgets.com")
"3D813CBB-47FB-32BA-91DF-831E1593AC29";
test_uuid ~__POS__ 3
(Uuidm.v3 Uuidm.ns_dns "www.example.org")
"0012416f-9eec-3ed4-a8b0-3bceecde1cd9";
test_uuid ~__POS__ 3
(Uuidm.v3 Uuidm.ns_dns "www.example.com")
"5df41881-3aed-3515-88a7-2f4a814cf09e";
test_uuid ~__POS__ 4
(Uuidm.v4
(Bytes.of_string
"\x91\x91\x08\xF7\x52\xD1\x33\x20\x5B\xAC\xF8\x47\xDB\x41\x48\xA8"))
"919108f7-52d1-4320-9bac-f847db4148a8";
test_uuid ~__POS__ 5
(Uuidm.v5 Uuidm.ns_dns "www.widgets.com")
"21F7F8DE-8051-5B89-8680-0195EF798B6A";
test_uuid ~__POS__ 5
(Uuidm.v5 Uuidm.ns_dns "www.example.org")
"74738ff5-5367-5958-9aee-98fffdcd1876";
test_uuid ~__POS__ 5
(Uuidm.v5 Uuidm.ns_dns "www.example.com")
"2ed6657d-e927-568b-95e1-2665a8aea6a2";
test_uuid ~__POS__ 7 ~time_ms:0x1020_3040_5060L
(Uuidm.v7_ns ~time_ns:Int64.(add (mul 1_000_000L 0x1020_3040_5060L) 213135L)
~rand_b:0x123456789abcdef0L)
"10203040-5060-7369-9234-56789abcdef0";
test_uuid ~__POS__ 7 ~time_ms:0x017F22E279B0L
(Uuidm.v7
~time_ms:0x017F22E279B0L ~rand_a:0xCC3 ~rand_b:0x18C4DC0C0C07398FL)
"017F22E2-79B0-7CC3-98C4-DC0C0C07398F";
test_uuid ~__POS__ 8
(Uuidm.v8
"\x24\x89\xE9\xAD\x2E\xE2\x0E\x00\x0E\xC9\x32\xD5\xF6\x91\x81\xC0")
"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0";
Test.invalid_arg ~__POS__ @@ fun () -> ignore (Uuidm.v8 "");
()
let test_constants =
Test.test "Uuidm UUID constants" @@ fun () ->
test_uuid ~__POS__ 0 Uuidm.nil "00000000-0000-0000-0000-000000000000";
test_uuid ~__POS__ 0xF Uuidm.max "ffffffff-ffff-ffff-ffff-ffffffffffff";
test_uuid ~__POS__ 1 Uuidm.ns_dns "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
test_uuid ~__POS__ 1 Uuidm.ns_url "6ba7b811-9dad-11d1-80b4-00c04fd430c8";
test_uuid ~__POS__ 1 Uuidm.ns_oid "6ba7b812-9dad-11d1-80b4-00c04fd430c8";
test_uuid ~__POS__ 1 Uuidm.ns_X500 "6ba7b814-9dad-11d1-80b4-00c04fd430c8";
()
let test_mixed_endian =
Test.test "Uuidm.{of,to}_mixed_endian_binary_string" @@ fun () ->
test_uuid ~__POS__ 13
(Uuidm.unsafe_of_binary_string
(Uuidm.to_mixed_endian_binary_string Uuidm.ns_X500))
"14B8a76b-ad9d-d111-80b4-00c04fd430c8";
test_uuid ~__POS__ 13
(Test.noraise ~__POS__ @@ fun () ->
Option.get @@
Uuidm.of_mixed_endian_binary_string
(Uuidm.to_binary_string Uuidm.ns_X500))
"14B8a76b-ad9d-d111-80b4-00c04fd430c8";
()
let main () = Test.main @@ fun () -> Test.autorun ()
let () = if !Sys.interactive then () else exit (main ())

View file

@ -0,0 +1,99 @@
(*---------------------------------------------------------------------------
Copyright (c) 2008 The uuidm programmers. All rights reserved.
SPDX-License-Identifier: ISC
---------------------------------------------------------------------------*)
let strf = Printf.sprintf
let gen ~version ~ns ~name ~upper ~binary =
let u = match version with
| `V3 -> Uuidm.v3 ns name
| `V4 -> Uuidm.v4_gen (Random.State.make_self_init ()) ()
| `V5 -> Uuidm.v5 ns name
| `V7 ->
let now_ms () = Int64.of_float (Unix.gettimeofday () *. 1000.) in
Uuidm.v7_non_monotonic_gen ~now_ms (Random.State.make_self_init ()) ()
in
let s = match binary with
| true -> Uuidm.to_binary_string u
| false -> strf "%s\n" (Uuidm.to_string ~upper u)
in
let () = Out_channel.set_binary_mode stdout binary in
print_string s; flush stdout
(* Command line interface *)
open Cmdliner
open Cmdliner.Term.Syntax
let version =
let v3 =
let doc =
"Generate a MD5 name based UUID version 3, see option $(b,--name)." in
`V3, Arg.info ["v3"; "md5"] ~doc
in
let v4 =
let doc = "Generate a random based UUID version 4 (default)." in
`V4, Arg.info ["v4"; "r"; "random"] ~doc
in
let v5 =
let doc =
"Generate a SHA-1 name based UUID version 5, see option $(b,--name)."
in
`V5, Arg.info ["v5"; "sha1"] ~doc
in
let v7 =
let doc = "Generate a time and random based UUID version 7." in
`V7, Arg.info ["v7"] ~doc
in
Arg.(value & vflag `V4 [v3; v4; v5; v7])
let ns =
let ns_arg =
let parse s = match Uuidm.of_string s with
| None -> Error (strf "%S: could not parse namespace UUID" s)
| Some ns -> Ok ns
in
Arg.conv' ~docv:"UUID" (parse, Uuidm.pp)
in
let doc = "Namespace UUID for name based UUIDs (version 4 or 5).
Defaults to the DNS namespace UUID."
in
Arg.(value & opt ns_arg Uuidm.ns_dns & info ["ns"; "namespace"] ~doc)
let name =
let doc = "Name for name based UUIDs (version 4 or 5)." in
Arg.(value & opt string "www.example.org" & info ["name"] ~doc)
let upper =
let doc = "Output hexadecimal letters in uppercase" in
Arg.(value & flag & info ["u"; "uppercase"] ~doc)
let binary =
let doc = "Output the UUID as its 16 bytes binary representation." in
Arg.(value & flag & info ["b"; "binary"] ~doc)
let cmd =
let doc = "Generates universally unique identifiers (UUIDs)" in
let man = [
`S "DESCRIPTION";
`P "$(tname) generates 128 bits universally unique identifiers version
3, 5 (name based with MD5, SHA-1 hashing), 4 (random based) and
7 (time and random based) according to RFC 9562.";
`P "Invoked without any option, a random based version 4 UUID is \
generated and written on stdout.";
`S "SEE ALSO";
`P "P. Leach et al. Universally Unique IDentifiers (UUIDs),
2024. $(i,https://www.rfc-editor.org/rfc/rfc9562)";
`S "BUGS";
`P "This program is distributed with the Uuidm OCaml library. \
See $(i,https://erratique.ch/software/uuidm) for contact \
information."; ]
in
Cmd.v (Cmd.info "uuidtrip" ~version:"v0.9.10+dune" ~doc ~man) @@
let+ version and+ ns and+ name and+ upper and+ binary in
gen ~version ~ns ~name ~upper ~binary
let main () = Cmd.eval cmd
let () = if !Sys.interactive then () else exit (main ())

View file

@ -0,0 +1,31 @@
version: "0.9.10+dune"
opam-version: "2.0"
maintainer: "Daniel Bünzli <daniel.buenzl i@erratique.ch>"
authors: ["Daniel Bünzli <daniel.buenzl i@erratique.ch>"]
homepage: "https://github.com/dune-universe/uuidm"
dev-repo: "git+https://github.com/dune-universe/uuidm.git"
bug-reports: "https://github.com/dbuenzli/uuidm/issues"
tags: [ "uuid" "codec" "org:erratique" ]
license: "ISC"
depends: [
"dune" {build}
"ocaml" {>= "4.14.0"}
"base-bytes"
]
depopts: ["cmdliner"]
conflicts: [
"cmdliner" {< "1.3.0"}
]
synopsis: "Universally unique identifiers (UUIDs) for OCaml"
description: """
Uuidm is an OCaml module implementing 128 bits universally unique
identifiers version 3, 5 (named based with MD5, SHA-1 hashing) and 4
(random based) according to [RFC 4122][rfc4122].
Uuidm has no dependency and is distributed under the ISC license.
[rfc4122]: http://tools.ietf.org/html/rfc4122"""
build: [[ "dune" "build" "-p" name ]]
url {
src: "git://github.com/dune-universe/uuidm.git#duniverse-v0.9.10"
}