This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
4
unikernel/duniverse/uuidm/.gitignore
vendored
Normal file
4
unikernel/duniverse/uuidm/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
_build
|
||||
_b0
|
||||
tmp
|
||||
*.install
|
||||
4
unikernel/duniverse/uuidm/.merlin
Normal file
4
unikernel/duniverse/uuidm/.merlin
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
PKG b0.kit cmdliner
|
||||
S src/**
|
||||
S test/**
|
||||
B _b0/**
|
||||
1
unikernel/duniverse/uuidm/.ocp-indent
Normal file
1
unikernel/duniverse/uuidm/.ocp-indent
Normal file
|
|
@ -0,0 +1 @@
|
|||
strict_with=always,match_clause=4,strict_else=never
|
||||
58
unikernel/duniverse/uuidm/B0.ml
Normal file
58
unikernel/duniverse/uuidm/B0.ml
Normal 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 ()
|
||||
1
unikernel/duniverse/uuidm/BRZO
Normal file
1
unikernel/duniverse/uuidm/BRZO
Normal file
|
|
@ -0,0 +1 @@
|
|||
(srcs-x pkg)
|
||||
104
unikernel/duniverse/uuidm/CHANGES.md
Normal file
104
unikernel/duniverse/uuidm/CHANGES.md
Normal 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.
|
||||
6
unikernel/duniverse/uuidm/DEVEL.md
Normal file
6
unikernel/duniverse/uuidm/DEVEL.md
Normal 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
|
||||
13
unikernel/duniverse/uuidm/LICENSE.md
Normal file
13
unikernel/duniverse/uuidm/LICENSE.md
Normal 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.
|
||||
41
unikernel/duniverse/uuidm/README.md
Normal file
41
unikernel/duniverse/uuidm/README.md
Normal 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/
|
||||
4
unikernel/duniverse/uuidm/_tags
Normal file
4
unikernel/duniverse/uuidm/_tags
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
true : bin_annot, safe_string
|
||||
<_b0> : -traverse
|
||||
<src> : include
|
||||
<test/uuidtrip.*> : package(cmdliner unix)
|
||||
101
unikernel/duniverse/uuidm/doc/index.mld
Normal file
101
unikernel/duniverse/uuidm/doc/index.mld
Normal 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.
|
||||
3
unikernel/duniverse/uuidm/dune-project
Normal file
3
unikernel/duniverse/uuidm/dune-project
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
(lang dune 1.0)
|
||||
(name uuidm)
|
||||
(version v0.9.10+dune)
|
||||
8
unikernel/duniverse/uuidm/pkg/META
Normal file
8
unikernel/duniverse/uuidm/pkg/META
Normal 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"
|
||||
12
unikernel/duniverse/uuidm/pkg/pkg.ml
Executable file
12
unikernel/duniverse/uuidm/pkg/pkg.ml
Executable 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" ]
|
||||
4
unikernel/duniverse/uuidm/src/dune
Normal file
4
unikernel/duniverse/uuidm/src/dune
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
(library
|
||||
(name uuidm)
|
||||
(public_name uuidm)
|
||||
(wrapped false))
|
||||
322
unikernel/duniverse/uuidm/src/uuidm.ml
Normal file
322
unikernel/duniverse/uuidm/src/uuidm.ml
Normal 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
|
||||
272
unikernel/duniverse/uuidm/src/uuidm.mli
Normal file
272
unikernel/duniverse/uuidm/src/uuidm.mli
Normal 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"]
|
||||
(**/**)
|
||||
1
unikernel/duniverse/uuidm/src/uuidm.mllib
Normal file
1
unikernel/duniverse/uuidm/src/uuidm.mllib
Normal file
|
|
@ -0,0 +1 @@
|
|||
Uuidm
|
||||
25
unikernel/duniverse/uuidm/test/examples.ml
Normal file
25
unikernel/duniverse/uuidm/test/examples.ml
Normal 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 ()))
|
||||
39
unikernel/duniverse/uuidm/test/perf.ml
Normal file
39
unikernel/duniverse/uuidm/test/perf.ml
Normal 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 ()
|
||||
90
unikernel/duniverse/uuidm/test/test_uuidm.ml
Normal file
90
unikernel/duniverse/uuidm/test/test_uuidm.ml
Normal 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 ())
|
||||
99
unikernel/duniverse/uuidm/test/uuidtrip.ml
Normal file
99
unikernel/duniverse/uuidm/test/uuidtrip.ml
Normal 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 ())
|
||||
31
unikernel/duniverse/uuidm/uuidm.opam
Normal file
31
unikernel/duniverse/uuidm/uuidm.opam
Normal 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"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue