on master help sign in
.git-blame-ignore-revsnew file+2
since splitsnapshots
unifiedsplit
@@ -0,0 +1,2 @@
1+# Move code into subdirectories
2+bf1ac1bad848bb2c081f0cae1631bf53811ec05a
.github/workflows/haskell-ci-bench.ymlnew file+241
@@ -0,0 +1,241 @@
1+# This GitHub workflow config has been generated by a script via
2+#
3+# haskell-ci 'github' '--project' 'cabal.bench.project' '-o' '.github/workflows/haskell-ci-bench.yml' '--github-action-name' 'Benchmarks'
4+#
5+# To regenerate the script (for example after adjusting tested-with) run
6+#
7+# haskell-ci regenerate
8+#
9+# For more information, see https://github.com/haskell-CI/haskell-ci
10+#
11+# version: 0.19.20240702
12+#
13+# REGENDATA ("0.19.20240702",["github","--project","cabal.bench.project","-o",".github/workflows/haskell-ci-bench.yml","--github-action-name","Benchmarks"])
14+#
15+name: Benchmarks
16+on:
17+ push:
18+ branches:
19+ - master
20+ pull_request:
21+ branches:
22+ - master
23+jobs:
24+ linux:
25+ name: Benchmarks - Linux - ${{ matrix.compiler }}
26+ runs-on: ubuntu-20.04
27+ timeout-minutes:
28+ 60
29+ container:
30+ image: buildpack-deps:jammy
31+ continue-on-error: ${{ matrix.allow-failure }}
32+ strategy:
33+ matrix:
34+ include:
35+ - compiler: ghc-9.10.1
36+ compilerKind: ghc
37+ compilerVersion: 9.10.1
38+ setup-method: ghcup
39+ allow-failure: false
40+ - compiler: ghc-9.8.2
41+ compilerKind: ghc
42+ compilerVersion: 9.8.2
43+ setup-method: ghcup
44+ allow-failure: false
45+ - compiler: ghc-9.6.6
46+ compilerKind: ghc
47+ compilerVersion: 9.6.6
48+ setup-method: ghcup
49+ allow-failure: false
50+ - compiler: ghc-9.4.8
51+ compilerKind: ghc
52+ compilerVersion: 9.4.8
53+ setup-method: ghcup
54+ allow-failure: false
55+ - compiler: ghc-9.2.8
56+ compilerKind: ghc
57+ compilerVersion: 9.2.8
58+ setup-method: ghcup
59+ allow-failure: false
60+ - compiler: ghc-9.0.2
61+ compilerKind: ghc
62+ compilerVersion: 9.0.2
63+ setup-method: ghcup
64+ allow-failure: false
65+ - compiler: ghc-8.10.7
66+ compilerKind: ghc
67+ compilerVersion: 8.10.7
68+ setup-method: ghcup
69+ allow-failure: false
70+ - compiler: ghc-8.8.4
71+ compilerKind: ghc
72+ compilerVersion: 8.8.4
73+ setup-method: ghcup
74+ allow-failure: false
75+ - compiler: ghc-8.6.5
76+ compilerKind: ghc
77+ compilerVersion: 8.6.5
78+ setup-method: ghcup
79+ allow-failure: false
80+ fail-fast: false
81+ steps:
82+ - name: apt
83+ run: |
84+ apt-get update
85+ apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5
86+ mkdir -p "$HOME/.ghcup/bin"
87+ curl -sL https://downloads.haskell.org/ghcup/0.1.20.0/x86_64-linux-ghcup-0.1.20.0 > "$HOME/.ghcup/bin/ghcup"
88+ chmod a+x "$HOME/.ghcup/bin/ghcup"
89+ "$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false)
90+ "$HOME/.ghcup/bin/ghcup" install cabal 3.12.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
91+ env:
92+ HCKIND: ${{ matrix.compilerKind }}
93+ HCNAME: ${{ matrix.compiler }}
94+ HCVER: ${{ matrix.compilerVersion }}
95+ - name: Set PATH and environment variables
96+ run: |
97+ echo "$HOME/.cabal/bin" >> $GITHUB_PATH
98+ echo "LANG=C.UTF-8" >> "$GITHUB_ENV"
99+ echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV"
100+ echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV"
101+ HCDIR=/opt/$HCKIND/$HCVER
102+ HC=$("$HOME/.ghcup/bin/ghcup" whereis ghc "$HCVER")
103+ HCPKG=$(echo "$HC" | sed 's#ghc$#ghc-pkg#')
104+ HADDOCK=$(echo "$HC" | sed 's#ghc$#haddock#')
105+ echo "HC=$HC" >> "$GITHUB_ENV"
106+ echo "HCPKG=$HCPKG" >> "$GITHUB_ENV"
107+ echo "HADDOCK=$HADDOCK" >> "$GITHUB_ENV"
108+ echo "CABAL=$HOME/.ghcup/bin/cabal-3.12.1.0 -vnormal+nowrap" >> "$GITHUB_ENV"
109+ HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
110+ echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV"
111+ echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV"
112+ echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV"
113+ echo "HEADHACKAGE=false" >> "$GITHUB_ENV"
114+ echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV"
115+ echo "GHCJSARITH=0" >> "$GITHUB_ENV"
116+ env:
117+ HCKIND: ${{ matrix.compilerKind }}
118+ HCNAME: ${{ matrix.compiler }}
119+ HCVER: ${{ matrix.compilerVersion }}
120+ - name: env
121+ run: |
122+ env
123+ - name: write cabal config
124+ run: |
125+ mkdir -p $CABAL_DIR
126+ cat >> $CABAL_CONFIG <<EOF
127+ remote-build-reporting: anonymous
128+ write-ghc-environment-files: never
129+ remote-repo-cache: $CABAL_DIR/packages
130+ logs-dir: $CABAL_DIR/logs
131+ world-file: $CABAL_DIR/world
132+ extra-prog-path: $CABAL_DIR/bin
133+ symlink-bindir: $CABAL_DIR/bin
134+ installdir: $CABAL_DIR/bin
135+ build-summary: $CABAL_DIR/logs/build.log
136+ store-dir: $CABAL_DIR/store
137+ install-dirs user
138+ prefix: $CABAL_DIR
139+ repository hackage.haskell.org
140+ url: http://hackage.haskell.org/
141+ EOF
142+ cat >> $CABAL_CONFIG <<EOF
143+ program-default-options
144+ ghc-options: $GHCJOBS +RTS -M3G -RTS
145+ EOF
146+ cat $CABAL_CONFIG
147+ - name: versions
148+ run: |
149+ $HC --version || true
150+ $HC --print-project-git-commit-id || true
151+ $CABAL --version || true
152+ - name: update cabal index
153+ run: |
154+ $CABAL v2-update -v
155+ - name: install cabal-plan
156+ run: |
157+ mkdir -p $HOME/.cabal/bin
158+ curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.7.3.0/cabal-plan-0.7.3.0-x86_64-linux.xz > cabal-plan.xz
159+ echo 'f62ccb2971567a5f638f2005ad3173dba14693a45154c1508645c52289714cb2 cabal-plan.xz' | sha256sum -c -
160+ xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
161+ rm -f cabal-plan.xz
162+ chmod a+x $HOME/.cabal/bin/cabal-plan
163+ cabal-plan --version
164+ - name: checkout
165+ uses: actions/checkout@v4
166+ with:
167+ path: source
168+ - name: initial cabal.project for sdist
169+ run: |
170+ touch cabal.project
171+ echo "packages: $GITHUB_WORKSPACE/source/uuid-bench" >> cabal.project
172+ cat cabal.project
173+ - name: sdist
174+ run: |
175+ mkdir -p sdist
176+ $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
177+ - name: unpack
178+ run: |
179+ mkdir -p unpacked
180+ find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
181+ - name: generate cabal.project
182+ run: |
183+ PKGDIR_uuid_bench="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/uuid-bench-[0-9.]*')"
184+ echo "PKGDIR_uuid_bench=${PKGDIR_uuid_bench}" >> "$GITHUB_ENV"
185+ rm -f cabal.project cabal.project.local
186+ touch cabal.project
187+ touch cabal.project.local
188+ echo "packages: ${PKGDIR_uuid_bench}" >> cabal.project
189+ echo "package uuid-bench" >> cabal.project
190+ echo " ghc-options: -Werror=missing-methods" >> cabal.project
191+ cat >> cabal.project <<EOF
192+ EOF
193+ $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: any.$_ installed\n" unless /^(uuid-bench)$/; }' >> cabal.project.local
194+ cat cabal.project
195+ cat cabal.project.local
196+ - name: dump install plan
197+ run: |
198+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
199+ cabal-plan
200+ - name: restore cache
201+ uses: actions/cache/restore@v4
202+ with:
203+ key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
204+ path: ~/.cabal/store
205+ restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
206+ - name: install dependencies
207+ run: |
208+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
209+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
210+ - name: build w/o tests
211+ run: |
212+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
213+ - name: build
214+ run: |
215+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
216+ - name: cabal check
217+ run: |
218+ cd ${PKGDIR_uuid_bench} || false
219+ ${CABAL} -vnormal check
220+ - name: haddock
221+ run: |
222+ $CABAL v2-haddock --disable-documentation --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
223+ - name: unconstrained build
224+ run: |
225+ rm -f cabal.project.local
226+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
227+ - name: prepare for constraint sets
228+ run: |
229+ rm -f cabal.project.local
230+ - name: constraint set random-1.2
231+ run: |
232+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='random==1.2.*' all --dry-run
233+ cabal-plan topo | sort
234+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='random==1.2.*' --dependencies-only -j2 all
235+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='random==1.2.*' all
236+ - name: save cache
237+ uses: actions/cache/save@v4
238+ if: always()
239+ with:
240+ key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
241+ path: ~/.cabal/store
.github/workflows/haskell-ci.ymlnew file+262
@@ -0,0 +1,262 @@
1+# This GitHub workflow config has been generated by a script via
2+#
3+# haskell-ci 'github' 'cabal.project'
4+#
5+# To regenerate the script (for example after adjusting tested-with) run
6+#
7+# haskell-ci regenerate
8+#
9+# For more information, see https://github.com/haskell-CI/haskell-ci
10+#
11+# version: 0.19.20241223
12+#
13+# REGENDATA ("0.19.20241223",["github","cabal.project"])
14+#
15+name: Haskell-CI
16+on:
17+ push:
18+ branches:
19+ - master
20+ pull_request:
21+ branches:
22+ - master
23+jobs:
24+ linux:
25+ name: Haskell-CI - Linux - ${{ matrix.compiler }}
26+ runs-on: ubuntu-20.04
27+ timeout-minutes:
28+ 60
29+ container:
30+ image: buildpack-deps:jammy
31+ continue-on-error: ${{ matrix.allow-failure }}
32+ strategy:
33+ matrix:
34+ include:
35+ - compiler: ghc-9.12.1
36+ compilerKind: ghc
37+ compilerVersion: 9.12.1
38+ setup-method: ghcup
39+ allow-failure: false
40+ - compiler: ghc-9.10.1
41+ compilerKind: ghc
42+ compilerVersion: 9.10.1
43+ setup-method: ghcup
44+ allow-failure: false
45+ - compiler: ghc-9.8.4
46+ compilerKind: ghc
47+ compilerVersion: 9.8.4
48+ setup-method: ghcup
49+ allow-failure: false
50+ - compiler: ghc-9.6.6
51+ compilerKind: ghc
52+ compilerVersion: 9.6.6
53+ setup-method: ghcup
54+ allow-failure: false
55+ - compiler: ghc-9.4.8
56+ compilerKind: ghc
57+ compilerVersion: 9.4.8
58+ setup-method: ghcup
59+ allow-failure: false
60+ - compiler: ghc-9.2.8
61+ compilerKind: ghc
62+ compilerVersion: 9.2.8
63+ setup-method: ghcup
64+ allow-failure: false
65+ - compiler: ghc-9.0.2
66+ compilerKind: ghc
67+ compilerVersion: 9.0.2
68+ setup-method: ghcup
69+ allow-failure: false
70+ - compiler: ghc-8.10.7
71+ compilerKind: ghc
72+ compilerVersion: 8.10.7
73+ setup-method: ghcup
74+ allow-failure: false
75+ - compiler: ghc-8.8.4
76+ compilerKind: ghc
77+ compilerVersion: 8.8.4
78+ setup-method: ghcup
79+ allow-failure: false
80+ - compiler: ghc-8.6.5
81+ compilerKind: ghc
82+ compilerVersion: 8.6.5
83+ setup-method: ghcup
84+ allow-failure: false
85+ fail-fast: false
86+ steps:
87+ - name: apt-get install
88+ run: |
89+ apt-get update
90+ apt-get install -y --no-install-recommends gnupg ca-certificates dirmngr curl git software-properties-common libtinfo5
91+ - name: Install GHCup
92+ run: |
93+ mkdir -p "$HOME/.ghcup/bin"
94+ curl -sL https://downloads.haskell.org/ghcup/0.1.30.0/x86_64-linux-ghcup-0.1.30.0 > "$HOME/.ghcup/bin/ghcup"
95+ chmod a+x "$HOME/.ghcup/bin/ghcup"
96+ - name: Install cabal-install
97+ run: |
98+ "$HOME/.ghcup/bin/ghcup" install cabal 3.14.1.0 || (cat "$HOME"/.ghcup/logs/*.* && false)
99+ echo "CABAL=$HOME/.ghcup/bin/cabal-3.14.1.0 -vnormal+nowrap" >> "$GITHUB_ENV"
100+ - name: Install GHC (GHCup)
101+ if: matrix.setup-method == 'ghcup'
102+ run: |
103+ "$HOME/.ghcup/bin/ghcup" install ghc "$HCVER" || (cat "$HOME"/.ghcup/logs/*.* && false)
104+ HC=$("$HOME/.ghcup/bin/ghcup" whereis ghc "$HCVER")
105+ HCPKG=$(echo "$HC" | sed 's#ghc$#ghc-pkg#')
106+ HADDOCK=$(echo "$HC" | sed 's#ghc$#haddock#')
107+ echo "HC=$HC" >> "$GITHUB_ENV"
108+ echo "HCPKG=$HCPKG" >> "$GITHUB_ENV"
109+ echo "HADDOCK=$HADDOCK" >> "$GITHUB_ENV"
110+ env:
111+ HCKIND: ${{ matrix.compilerKind }}
112+ HCNAME: ${{ matrix.compiler }}
113+ HCVER: ${{ matrix.compilerVersion }}
114+ - name: Set PATH and environment variables
115+ run: |
116+ echo "$HOME/.cabal/bin" >> $GITHUB_PATH
117+ echo "LANG=C.UTF-8" >> "$GITHUB_ENV"
118+ echo "CABAL_DIR=$HOME/.cabal" >> "$GITHUB_ENV"
119+ echo "CABAL_CONFIG=$HOME/.cabal/config" >> "$GITHUB_ENV"
120+ HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\d+)\.(\d+)\.(\d+)(\.(\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')
121+ echo "HCNUMVER=$HCNUMVER" >> "$GITHUB_ENV"
122+ echo "ARG_TESTS=--enable-tests" >> "$GITHUB_ENV"
123+ echo "ARG_BENCH=--enable-benchmarks" >> "$GITHUB_ENV"
124+ echo "HEADHACKAGE=false" >> "$GITHUB_ENV"
125+ echo "ARG_COMPILER=--$HCKIND --with-compiler=$HC" >> "$GITHUB_ENV"
126+ env:
127+ HCKIND: ${{ matrix.compilerKind }}
128+ HCNAME: ${{ matrix.compiler }}
129+ HCVER: ${{ matrix.compilerVersion }}
130+ - name: env
131+ run: |
132+ env
133+ - name: write cabal config
134+ run: |
135+ mkdir -p $CABAL_DIR
136+ cat >> $CABAL_CONFIG <<EOF
137+ remote-build-reporting: anonymous
138+ write-ghc-environment-files: never
139+ remote-repo-cache: $CABAL_DIR/packages
140+ logs-dir: $CABAL_DIR/logs
141+ world-file: $CABAL_DIR/world
142+ extra-prog-path: $CABAL_DIR/bin
143+ symlink-bindir: $CABAL_DIR/bin
144+ installdir: $CABAL_DIR/bin
145+ build-summary: $CABAL_DIR/logs/build.log
146+ store-dir: $CABAL_DIR/store
147+ install-dirs user
148+ prefix: $CABAL_DIR
149+ repository hackage.haskell.org
150+ url: http://hackage.haskell.org/
151+ EOF
152+ cat >> $CABAL_CONFIG <<EOF
153+ program-default-options
154+ ghc-options: $GHCJOBS +RTS -M3G -RTS
155+ EOF
156+ cat $CABAL_CONFIG
157+ - name: versions
158+ run: |
159+ $HC --version || true
160+ $HC --print-project-git-commit-id || true
161+ $CABAL --version || true
162+ - name: update cabal index
163+ run: |
164+ $CABAL v2-update -v
165+ - name: install cabal-plan
166+ run: |
167+ mkdir -p $HOME/.cabal/bin
168+ curl -sL https://github.com/haskell-hvr/cabal-plan/releases/download/v0.7.3.0/cabal-plan-0.7.3.0-x86_64-linux.xz > cabal-plan.xz
169+ echo 'f62ccb2971567a5f638f2005ad3173dba14693a45154c1508645c52289714cb2 cabal-plan.xz' | sha256sum -c -
170+ xz -d < cabal-plan.xz > $HOME/.cabal/bin/cabal-plan
171+ rm -f cabal-plan.xz
172+ chmod a+x $HOME/.cabal/bin/cabal-plan
173+ cabal-plan --version
174+ - name: checkout
175+ uses: actions/checkout@v4
176+ with:
177+ path: source
178+ - name: initial cabal.project for sdist
179+ run: |
180+ touch cabal.project
181+ echo "packages: $GITHUB_WORKSPACE/source/uuid-types" >> cabal.project
182+ echo "packages: $GITHUB_WORKSPACE/source/uuid" >> cabal.project
183+ cat cabal.project
184+ - name: sdist
185+ run: |
186+ mkdir -p sdist
187+ $CABAL sdist all --output-dir $GITHUB_WORKSPACE/sdist
188+ - name: unpack
189+ run: |
190+ mkdir -p unpacked
191+ find sdist -maxdepth 1 -type f -name '*.tar.gz' -exec tar -C $GITHUB_WORKSPACE/unpacked -xzvf {} \;
192+ - name: generate cabal.project
193+ run: |
194+ PKGDIR_uuid_types="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/uuid-types-[0-9.]*')"
195+ echo "PKGDIR_uuid_types=${PKGDIR_uuid_types}" >> "$GITHUB_ENV"
196+ PKGDIR_uuid="$(find "$GITHUB_WORKSPACE/unpacked" -maxdepth 1 -type d -regex '.*/uuid-[0-9.]*')"
197+ echo "PKGDIR_uuid=${PKGDIR_uuid}" >> "$GITHUB_ENV"
198+ rm -f cabal.project cabal.project.local
199+ touch cabal.project
200+ touch cabal.project.local
201+ echo "packages: ${PKGDIR_uuid_types}" >> cabal.project
202+ echo "packages: ${PKGDIR_uuid}" >> cabal.project
203+ echo "package uuid-types" >> cabal.project
204+ echo " ghc-options: -Werror=missing-methods" >> cabal.project
205+ echo "package uuid" >> cabal.project
206+ echo " ghc-options: -Werror=missing-methods" >> cabal.project
207+ cat >> cabal.project <<EOF
208+ EOF
209+ $HCPKG list --simple-output --names-only | perl -ne 'for (split /\s+/) { print "constraints: any.$_ installed\n" unless /^(uuid|uuid-types)$/; }' >> cabal.project.local
210+ cat cabal.project
211+ cat cabal.project.local
212+ - name: dump install plan
213+ run: |
214+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dry-run all
215+ cabal-plan
216+ - name: restore cache
217+ uses: actions/cache/restore@v4
218+ with:
219+ key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
220+ path: ~/.cabal/store
221+ restore-keys: ${{ runner.os }}-${{ matrix.compiler }}-
222+ - name: install dependencies
223+ run: |
224+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --dependencies-only -j2 all
225+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH --dependencies-only -j2 all
226+ - name: build w/o tests
227+ run: |
228+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
229+ - name: build
230+ run: |
231+ $CABAL v2-build $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --write-ghc-environment-files=always
232+ - name: tests
233+ run: |
234+ $CABAL v2-test $ARG_COMPILER $ARG_TESTS $ARG_BENCH all --test-show-details=direct
235+ - name: cabal check
236+ run: |
237+ cd ${PKGDIR_uuid_types} || false
238+ ${CABAL} -vnormal check
239+ cd ${PKGDIR_uuid} || false
240+ ${CABAL} -vnormal check
241+ - name: haddock
242+ run: |
243+ $CABAL v2-haddock --disable-documentation --haddock-all $ARG_COMPILER --with-haddock $HADDOCK $ARG_TESTS $ARG_BENCH all
244+ - name: unconstrained build
245+ run: |
246+ rm -f cabal.project.local
247+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks all
248+ - name: prepare for constraint sets
249+ run: |
250+ rm -f cabal.project.local
251+ - name: constraint set random-1.2
252+ run: |
253+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='random==1.2.*' all --dry-run
254+ cabal-plan topo | sort
255+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='random==1.2.*' --dependencies-only -j2 all
256+ $CABAL v2-build $ARG_COMPILER --disable-tests --disable-benchmarks --constraint='random==1.2.*' all
257+ - name: save cache
258+ if: always()
259+ uses: actions/cache/save@v4
260+ with:
261+ key: ${{ runner.os }}-${{ matrix.compiler }}-${{ github.sha }}
262+ path: ~/.cabal/store
.gitignorenew file+13
@@ -0,0 +1,13 @@
1+# Sandboxing
2+.cabal-sandbox/
3+cabal.sandbox.config
4+
5+# Cabal stuff
6+dist/
7+cabal.config
8+dist-newstyle/
9+/cabal.project.local
10+.ghc.environment.*
11+
12+# Emacs
13+*~
CHANGESdeleted−10
@@ -1,10 +0,0 @@
1−
2−- added CHANGES file
3−- added functions toByteString and fromByteString (Mark Lentczner)
4−- added 'nil' UUID (Mark Lentczner)
5−
6−1.1.1
7−
8−- no longer exporting 'null' from the prelude
9−- add 'null' predicate on UUIDs
10−- documentation fix (thanks Mark Lentczner)
CONTRIBUTORS+9
@@ -4,3 +4,12 @@ Antoine Latter
4Jason Dusek
4Jason Dusek
5Tim Newsham
5Tim Newsham
6Mark Lentczner
6Mark Lentczner
7+Neil Mitchell
8+Bas van Dijk
9+Sergei Trofimovich
10+davean
11+Francesco Mazzoli
12+Michael Snoyman
13+Bardur Arantsson
14+Timo von Holtz
15+Oleg Grenrus
Data/UUID.hsdeleted−34
@@ -1,34 +0,0 @@
1−-- |
2−-- Module : Data.UUID
3−-- Copyright : (c) 2008 Antoine Latter
4−--
5−-- License : BSD-style
6−--
7−-- Maintainer : aslatter@gmail.com
8−-- Stability : experimental
9−-- Portability : portable
10−--
11−--
12−-- This library is useful for comparing, parsing and
13−-- printing Universally Unique Identifiers.
14−-- See <http://en.wikipedia.org/wiki/UUID> for the general idea.
15−-- See <http://tools.ietf.org/html/rfc4122> for the specification.
16−--
17−-- For generating UUIDs, check out 'Data.UUID.V1', 'Data.UUID.V5' and
18−-- 'System.Random'.
19−
20−module Data.UUID(UUID
21− ,toString
22− ,fromString
23− ,toByteString
24− ,fromByteString
25− ,null
26− ,nil
27− ) where
28−
29−import Prelude hiding (null)
30−import Data.UUID.Internal
31−
32−-- Everything is really implemented in Data.UUID.Internal,
33−-- but I don't want to export the constructors out of the
34−-- package.
Data/UUID/Internal.hsdeleted−324
@@ -1,324 +0,0 @@
1−{-# LANGUAGE DeriveDataTypeable, CPP #-}
2−
3−-- |
4−-- Module : Data.UUID
5−-- Copyright : (c) 2008 Antoine Latter
6−--
7−-- License : BSD-style
8−--
9−-- Maintainer : aslatter@gmail.com
10−-- Stability : experimental
11−-- Portability : portable
12−
13−module Data.UUID.Internal
14− (UUID(..)
15− ,null
16− ,nil
17− ,Node(..)
18− ,nullNode
19− ,nodeToList
20− ,listToNode
21− ,fromByteString
22− ,toByteString
23− ,fromString
24− ,toString
25− ,versionMask
26− ,reservedMask
27− ,reserved
28− ) where
29−
30−import Prelude hiding (null)
31−import qualified Prelude
32−
33−import Data.Word
34−import Data.Char
35−import Data.Maybe
36−import Data.Bits
37−import Data.List (splitAt, foldl', unfoldr)
38−
39−import Data.Typeable
40−
41−#if MIN_VERSION_base(4,0,0)
42−import Data.Data
43−#else
44−import Data.Generics.Basics
45−#endif
46−
47−import Foreign.Ptr
48−import Foreign.Storable
49−
50−import Data.Binary
51−import Data.Binary.Put
52−import Data.Binary.Get
53−import qualified Data.ByteString.Lazy as Lazy
54−
55−import System.Random
56−
57−import Text.Printf
58−
59−#ifndef STRICT
60−#define SLOT(x) x
61−#else
62−#define SLOT(x) {-# UNPACK #-} !x
63−#endif
64−
65−-- |The UUID type. A 'Random' instance is provided which produces
66−-- version 4 UUIDs as specified in RFC 4122. The 'Storable' and
67−-- 'Binary' instances are compatable with RFC 4122. The 'Binary'
68−-- instance serializes to network byte order.
69−data UUID = UUID
70− {uuid_timeLow :: SLOT(Word32)
71− ,uuid_timeMid :: SLOT(Word16)
72− ,uuid_timeHigh :: SLOT(Word16) -- includes version number
73− ,uuid_clockSeqHi :: SLOT(Word8) -- includes reserved field
74− ,uuid_clokcSeqLow :: SLOT(Word8)
75− ,uuid_node :: SLOT(Node)
76− } deriving (Eq, Ord, Typeable)
77−
78−-- |Returns true if the passed-in UUID is the 'nil' UUID.
79−null :: UUID -> Bool
80−null (UUID 0 0 0 0 0 node) | nullNode node = True
81−null _ = False
82−
83−-- |The nil UUID, as defined in RFC 4122.
84−-- It is a UUID of all zeros. @'null' u@ iff @'u' == 'nil'@.
85−nil :: UUID
86−nil = UUID 0 0 0 0 0 (Node 0 0 0 0 0 0)
87−
88−instance Random UUID where
89− random g = let (timeLow, g1) = randomBoundedIntegral g
90− (timeMid, g2) = randomBoundedIntegral g1
91− (timeHigh, g3) = randomBoundedIntegral g2
92− (seqHigh, g4) = randomBoundedIntegral g3
93− (seqLow, g5) = randomBoundedIntegral g4
94− (node, g6) = random g5
95− seqHighReserved = (seqHigh .&. reservedMask) .|. reserved
96− timeHighVersion = (timeHigh .&. versionMask) .|. versionRandom
97− in (UUID timeLow timeMid timeHighVersion seqHighReserved seqLow node, g6)
98−
99− randomR _ = random -- range is ignored
100−
101−versionMask :: Word16 -- 0000 1111 1111 1111
102−versionMask = 0x0FFF
103−
104−versionRandom :: Word16
105−versionRandom = 4 `shiftL` 12
106−
107−reservedMask :: Word8 -- 0011 1111
108−reservedMask = 0x3F
109−
110−reserved :: Word8
111−reserved = bit 7
112−
113−data Node = Node
114− SLOT(Word8)
115− SLOT(Word8)
116− SLOT(Word8)
117− SLOT(Word8)
118− SLOT(Word8)
119− SLOT(Word8)
120− deriving (Eq, Ord, Typeable)
121−
122−instance Random Node where
123− random g = let (w1, g1) = randomBoundedIntegral g
124− (w2, g2) = randomBoundedIntegral g1
125− (w3, g3) = randomBoundedIntegral g2
126− (w4, g4) = randomBoundedIntegral g3
127− (w5, g5) = randomBoundedIntegral g4
128− (w6, g6) = randomBoundedIntegral g5
129− in (Node w1 w2 w3 w4 w5 w6, g6)
130− randomR _ = random -- neglect range
131−
132−nullNode :: Node -> Bool
133−nullNode (Node 0 0 0 0 0 0) = True
134−nullNode _ = False
135−
136−nodeToList :: Node -> [Word8]
137−nodeToList (Node w1 w2 w3 w4 w5 w6) = [w1, w2, w3, w4, w5, w6]
138−
139−listToNode :: [Word8] -> Maybe Node
140−listToNode [w1, w2, w3, w4, w5, w6] = return $ Node w1 w2 w3 w4 w5 w6
141−listToNode _ = Nothing
142−
143−instance Show UUID where
144− show = toString
145−
146−instance Read UUID where
147− readsPrec _ str = case fromString (take 36 str) of
148− Nothing -> []
149− Just u -> [(u,drop 36 str)]
150−
151−
152−instance Storable UUID where
153− sizeOf _ = 16
154− alignment _ = 4 -- not sure what to put here
155−
156− peek p = do
157− tl <- peek $ castPtr p
158− tm <- peekByteOff p 4
159− th <- peekByteOff p 6
160− ch <- peekByteOff p 8
161− cl <- peekByteOff p 9
162− node <- peekByteOff p 10
163− return $ UUID tl tm th ch cl node
164−
165− poke p (UUID tl tm th ch cl node) = do
166− poke (castPtr p) tl
167− pokeByteOff p 4 tm
168− pokeByteOff p 6 th
169− pokeByteOff p 8 ch
170− pokeByteOff p 9 cl
171− pokeByteOff p 10 node
172−
173−instance Storable Node where
174− sizeOf _ = 6
175− alignment _ = 1 -- ???
176−
177− peek p = do
178− w1 <- peek $ castPtr p
179− w2 <- peekByteOff p 1
180− w3 <- peekByteOff p 2
181− w4 <- peekByteOff p 3
182− w5 <- peekByteOff p 4
183− w6 <- peekByteOff p 5
184− return $ Node w1 w2 w3 w4 w5 w6
185−
186− poke p (Node w1 w2 w3 w4 w5 w6) = do
187− poke (castPtr p) w1
188− pokeByteOff p 1 w2
189− pokeByteOff p 2 w3
190− pokeByteOff p 3 w4
191− pokeByteOff p 4 w5
192− pokeByteOff p 5 w6
193−
194−-- Binary instance in network byte-order
195−instance Binary UUID where
196− put (UUID tl tm th ch cl n) = do
197− putWord32be tl
198− putWord16be tm
199− putWord16be th
200− putWord8 ch
201− putWord8 cl
202− put n
203−
204− get = do
205− tl <- getWord32be
206− tm <- getWord16be
207− th <- getWord16be
208− ch <- getWord8
209− cl <- getWord8
210− node <- get
211− return $ UUID tl tm th ch cl node
212−
213−instance Binary Node where
214− put (Node w1 w2 w3 w4 w5 w6) = do
215− putWord8 w1
216− putWord8 w2
217− putWord8 w3
218− putWord8 w4
219− putWord8 w5
220− putWord8 w6
221−
222− get = do
223− w1 <- getWord8
224− w2 <- getWord8
225− w3 <- getWord8
226− w4 <- getWord8
227− w5 <- getWord8
228− w6 <- getWord8
229− return $ Node w1 w2 w3 w4 w5 w6
230−
231−
232−-- |Extract a UUID from a 'ByteString' in network byte order.
233−-- The argument must be 16 bytes long, otherwise 'Nothing' is returned.
234−fromByteString :: Lazy.ByteString -> Maybe UUID
235−fromByteString bs | Lazy.length bs == 16 = Just $ decode bs
236− | otherwise = Nothing
237−
238−-- |Encode a UUID into a 'ByteString' in network order.
239−toByteString :: UUID -> Lazy.ByteString
240−toByteString uu = encode uu
241−
242−-- My goal with this instance was to make it work just enough to do what
243−-- I want when used with the HStringTemplate library.
244−instance Data UUID where
245− toConstr uu = mkConstr uuidType (show uu) [] (error "fixity")
246− gunfold _ _ = error "gunfold"
247− dataTypeOf _ = uuidType
248−
249−uuidType = mkNoRepType "Data.UUID.UUID"
250−
251−#if !(MIN_VERSION_base(4,2,0))
252−mkNoRepType :: String -> DataType
253−mkNoRepType = mkNorepType
254−#endif
255−
256−-- |If the passed in 'String' can be parsed as a 'UUID', it will be.
257−-- The hyphens may not be omitted.
258−-- Example:
259−--
260−-- @
261−-- fromString \"c2cc10e1-57d6-4b6f-9899-38d972112d8c\"
262−-- @
263−--
264−-- Hex digits may be upper or lower-case.
265−fromString :: String -> Maybe UUID
266−fromString xs | validFmt = Just uuid
267− | otherwise = Nothing
268− where validFmt = length ws == 5 &&
269− map length ws == [8,4,4,4,12] &&
270− all isHexDigit (concat ws) &&
271− isJust node
272− ws = splitList '-' xs
273− [tl, tm, th, c, n] = ws
274− ns = unfoldUntil Prelude.null (splitAt 2) n :: [String]
275− node = listToNode $ map hexVal ns :: Maybe Node
276− uuid = UUID (hexVal tl) (hexVal tm) (hexVal th) (hexVal $ take 2 c) (hexVal $ drop 2 c) (fromJust $ node)
277−
278−-- | Convert a string to a hex value, assuming the string is already validated.
279−hexVal :: Num a => String -> a
280−hexVal = fromInteger . foldl' (\n c -> 16*n + digitToInteger c) 0
281−
282−digitToInteger :: Char -> Integer
283−digitToInteger = fromIntegral . digitToInt
284−
285−
286−-- | Convert a UUID into a hypenated string using lower-case letters.
287−-- Example:
288−--
289−-- @
290−-- toString $ fromString \"550e8400-e29b-41d4-a716-446655440000\"
291−-- @
292−toString :: UUID -> String
293−toString (UUID tl tm th ch cl n) = printf "%08x-%04x-%04x-%02x%02x-%s" tl tm th ch cl ns
294− where ns = concatMap hexb $ nodeToList n
295− hexb x = printf "%02x" x :: String
296−
297−
298−-- remove all occurances of the input element in the inpt list.
299−-- none of the sub-lists are empty.
300−splitList :: Eq a => a -> [a] -> [[a]]
301−splitList c xs = let ys = dropWhile (== c) xs
302− in case span (/= c) ys of
303− ([],_) -> []
304− (sub,rest) -> sub : splitList c rest
305−
306−-- the passed-in predicate signals when to stop unfolding
307−unfoldUntil :: (b -> Bool) -> (b -> (a, b)) -> b -> [a]
308−unfoldUntil p f n = unfoldr g n
309− where g m | p m = Nothing
310− | otherwise = Just $ f m
311−
312−
313−-- no random intance for Data.Word types :-(
314−-- this will work, though
315−
316−randomBoundedIntegral :: (RandomGen g, Bounded a, Integral a) => g -> (a, g)
317−randomBoundedIntegral g =
318− let (n, g1) = randomR (fromIntegral l, fromIntegral u) g
319− _ = n :: Integer
320− retVal = fromIntegral n `asTypeOf` (l `asTypeOf` u)
321− u = maxBound
322− l = minBound
323− in (retVal, g1)
324−
Data/UUID/V1.hsdeleted−108
@@ -1,108 +0,0 @@
1−{-# OPTIONS_GHC -fno-cse #-}
2−
3−-- |
4−-- Module : Data.UUID.V1
5−-- Copyright : (c) 2008 Jason Dusek
6−--
7−-- License : BSD-style
8−--
9−-- Maintainer : aslatter@gmail.com
10−-- Stability : experimental
11−-- Portability : portable
12−--
13−-- RFC 4122 Version 1 UUID state machine.
14−
15−module Data.UUID.V1(nextUUID)
16−where
17−
18−import Data.Time
19−
20−import Data.Bits
21−import Data.Word
22−import Data.Binary
23−
24−import Data.IORef
25−import System.IO
26−import System.IO.Unsafe
27−
28−import System.Info.MAC
29−import Data.MAC
30−
31−import Data.UUID.Internal
32−
33−-- | Returns a new UUID derived from the local hardware MAC
34−-- address and the current system time.
35−-- Is generated according to the Version 1 UUID sepcified in
36−-- RFC 4122.
37−--
38−-- Returns nothing if the hardware MAC address could not
39−-- be discovered.
40−nextUUID :: IO (Maybe UUID)
41−nextUUID = do
42− res <- stepTime
43− mac <- mac
44− case (res, mac) of
45− (Just (c, t), Just (MAC a' b' c' d' e' f')) -> do
46− let
47− (tL, tM, tH) = word64ToTimePieces t
48− (cL, cH) = word16ToClockSeqPieces c
49− return $ Just $ UUID tL tM tH cH cL $ Node a' b' c' d' e' f'
50− _ -> return Nothing
51−
52−
53−-- |The bit layout and version number here used are described in clause 13 of
54−-- ITU X.667, from September 2004.
55−word64ToTimePieces :: Word64 -> (Word32, Word16, Word16)
56−word64ToTimePieces w = (lo, mi, hi)
57− where
58− lo = fromIntegral $ (w `shiftL` 32) `shiftR` 32
59− mi = fromIntegral $ (w `shiftL` 16) `shiftR` 48
60− hi = (fromIntegral $ w `shiftR` 48) `setBit` 15
61−
62−
63−stepTime = do
64− State c0 h0 <- readIORef state
65− h1 <- fmap hundredsOfNanosSinceGregorianReform getCurrentTime
66− if h1 > h0
67− then do
68− writeIORef state $ State 0 h1
69− return $ Just (0, h1)
70− else do
71− let
72− c1 = succ c0
73− if c1 < 2^14
74− then do
75− writeIORef state $ State c1 h0
76− return $ Just (c1, h0)
77− else do
78− return Nothing
79−
80−
81−{-# NOINLINE state #-}
82−state = unsafePerformIO $ do
83− h0 <- fmap hundredsOfNanosSinceGregorianReform getCurrentTime
84− newIORef $ State 0 h0
85−
86−
87−data State = State
88− {-# UNPACK #-} !Word16
89− {-# UNPACK #-} !Word64
90− deriving (Show)
91−
92−
93−
94−hundredsOfNanosSinceGregorianReform :: UTCTime -> Word64
95−hundredsOfNanosSinceGregorianReform t = floor $ 10000000 * dt
96− where
97− gregorianReform = UTCTime (fromGregorian 1582 10 15) 0
98− dt = t `diffUTCTime` gregorianReform
99−
100−
101−-- |Per clause 13 of ITU X.667, from September 2004.
102−word16ToClockSeqPieces :: Word16 -> (Word8, Word8)
103−word16ToClockSeqPieces w = (lo, hi)
104− where
105− lo = fromIntegral $ (w `shiftL` 8) `shiftR` 8
106− hi = (fromIntegral $ w `shiftR` 8) `setBit` 7
107−
108−
Data/UUID/V5.hsdeleted−101
@@ -1,101 +0,0 @@
1−-- |
2−-- Module : Data.UUID.V5
3−-- Copyright : (c) 2008 Antoine Latter
4−--
5−-- License : BSD-style
6−--
7−-- Maintainer : aslatter@gmail.com
8−-- Stability : experimental
9−-- Portability : portable
10−--
11−--
12−-- This module implements Version 5 UUIDs as specified
13−-- in RFC 4122.
14−--
15−-- These UUIDs identify an object within a namespace,
16−-- and are deterministic.
17−--
18−-- The namespace is identified by a UUID. Several sample
19−-- namespaces are enclosed.
20−
21−module Data.UUID.V5
22− (generateNamed
23− ,namespaceDNS
24− ,namespaceURL
25− ,namespaceOID
26− ,namespaceX500
27− ) where
28−
29−
30−import Data.UUID.Internal
31−
32−import Data.Binary
33−import Data.Bits
34−import Data.Maybe
35−
36−import qualified Data.ByteString.Lazy as BS
37−import Data.ByteString.Lazy (ByteString)
38−
39−import qualified Data.Digest.SHA1 as SHA1
40−
41−
42−-- |Generate a 'UUID' within the specified namespace out of the given
43−-- object.
44−--
45−-- Uses a SHA1 hash.
46−generateNamed :: UUID -- ^Namespace
47− -> [Word8] -- ^Object
48− -> UUID
49−generateNamed namespace object =
50− let chunk = BS.unpack (encode namespace) ++ object
51− SHA1.Word160 w1 w2 w3 w4 w5 = SHA1.hash chunk
52−
53− tl = w1
54− tm = high16 w2
55− th = (versionSHA .|.) $ (versionMask .&.) $ low16 w2
56− ch = (reserved .|.) $ (reservedMask .&.) $ high8 $ high16 w3
57− cl = low8 $ high16 w3
58− node = Node (high8 (low16 w3))
59− (low8 (low16 w3))
60− (high8 (high16 w4))
61− (low8 (high16 w4))
62− (high8 (low16 w4))
63− (low8 (low16 w4))
64− in UUID tl tm th ch cl node
65−
66−-- HASH 0 1 - 2 3 : w1
67−-- 4 5 - 6 7 : w2
68−-- 8 9 - 10 11 : w3
69−-- 12 13 - 14 15 : w4
70−-- 16 17 - 18 19 : w5
71−
72−low16 :: Word32 -> Word16
73−low16 = fromIntegral . (.&. 0x0000FFFF)
74−
75−high16 :: Word32 -> Word16
76−high16 = fromIntegral . flip shiftR 16
77−
78−low8 :: Word16 -> Word8
79−low8 = fromIntegral . (.&. 0x00FF)
80−
81−high8 :: Word16 -> Word8
82−high8 = fromIntegral . flip shiftR 8
83−
84−versionSHA = 5 `shiftL` 12
85−
86−unsafeFromString :: String -> UUID
87−unsafeFromString = fromJust . fromString
88−
89−-- |The namespace for DNS addresses
90−namespaceDNS :: UUID
91−namespaceDNS = unsafeFromString "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
92−
93−-- |The namespace for URLs
94−namespaceURL :: UUID
95−namespaceURL = unsafeFromString "6ba7b811-9dad-11d1-80b4-00c04fd430c8"
96−
97−namespaceOID :: UUID
98−namespaceOID = unsafeFromString "6ba7b812-9dad-11d1-80b4-00c04fd430c8"
99−
100−namespaceX500 :: UUID
101−namespaceX500 = unsafeFromString "6ba7b814-9dad-11d1-80b4-00c04fd430c8"
Policy.mdnew file+11
@@ -0,0 +1,11 @@
1+# Versioning
2+
3+Because many consumers of the `UUID` type receive the type
4+through the `uuid` package and not the `uuid-types` package
5+we need to be careful about removing instances from the `uuid`
6+type.
7+
8+If the `uuid-types` package has a major-version bump because of
9+the removal of a class instance then we must also bump the major
10+version of the `uuid` package when we update the package
11+description to pull in the new version of `uuid-types`.
README.mdnew file+12
@@ -0,0 +1,12 @@
1+# uuid [![Build Status](https://travis-ci.org/hvr/uuid.svg?branch=master)](https://travis-ci.org/hvr/uuid)
2+
3+This library is useful for creating, comparing, parsing and printing Universally
4+Unique Identifiers. See http://en.wikipedia.org/wiki/UUID for the general idea.
5+
6+We offer two different packages: `uuid` and `uuid-types`
7+
8+The `uuid` package aims to be a fully-featured library for working with UUIDs.
9+
10+However if you're developing a library and only want the `UUID` type to show up
11+in your APIs you may want to use the `uuid-types` library to minimize the number
12+of dependencies needed by users of your library.
cabal.bench.projectnew file+4
@@ -0,0 +1,4 @@
1+-- separate package for benchmarks
2+-- this way we can build criterion
3+packages: uuid-bench
4+benchmarks: True
cabal.haskell-cinew file+7
@@ -0,0 +1,7 @@
1+branches: master
2+-- jobs-selection: any
3+head-hackage: False
4+
5+constraint-set random-1.2
6+ ghc: >=7.10
7+ constraints: random==1.2.*
cabal.projectnew file+15
@@ -0,0 +1,15 @@
1+-- see http://cabal.readthedocs.io/en/latest/nix-local-build.html
2+-- for more details
3+
4+packages: uuid-types/
5+packages: uuid/
6+
7+package uuid-types
8+ tests: True
9+ -- profiling: True
10+ -- profiling-detail: toplevel-functions
11+
12+package uuid
13+ tests: True
14+ -- profiling: True
15+ -- profiling-detail: toplevel-functions
gen-ci.shnew file+5
@@ -0,0 +1,5 @@
1+#!/bin/sh
2+
3+# haskell-ci doesn't know how to regenerate multiple GHA workflows
4+haskell-ci github cabal.project
5+haskell-ci github --project cabal.bench.project -o .github/workflows/haskell-ci-bench.yml --github-action-name Benchmarks
tests/BenchUUID.hsdeleted−37
@@ -1,37 +0,0 @@
1−import Control.Monad (replicateM)
2−import Control.Parallel.Strategies
3−import Criterion.Main
4−import Data.Maybe (fromJust)
5−import qualified Data.ByteString.Lazy as BL
6−import qualified Data.ByteString.Lazy.Internal as BL
7−import qualified Data.UUID as U
8−import qualified Data.UUID.Internal as U
9−import System.Random
10−
11−
12−instance NFData BL.ByteString where
13− rnf BL.Empty = ()
14− rnf (BL.Chunk _ ts) = rnf ts
15−
16−instance NFData U.UUID where
17− rnf (U.UUID tl tm th ch cl node) =
18− rnf tl `seq` rnf tm `seq` rnf th `seq` rnf ch `seq` rnf cl `seq` rnf node
19−
20−instance NFData U.Node where
21− rnf (U.Node w1 w2 w3 w4 w5 w6) =
22− rnf w1 `seq` rnf w2 `seq` rnf w3 `seq` rnf w4 `seq` rnf w5 `seq` rnf w6
23−
24−
25−
26−main :: IO ()
27−main = do
28− u1 <- randomIO
29− let s1 = U.toString u1
30− b1 = U.toByteString u1
31− defaultMain [
32− bench "toString" $ B (rnf . U.toString) u1,
33− bench "fromString" $ B (rnf . U.fromString) s1,
34− bench "toByteString" $ B (rnf . U.toByteString) u1,
35− bench "fromByteString" $ B (rnf . U.fromByteString) b1,
36− bench "random gen" $ rnf `fmap` (randomIO :: IO U.UUID)
37− ]
tests/TestUUID.hsdeleted−119
@@ -1,119 +0,0 @@
1−import Data.Bits
2−import qualified Data.ByteString.Lazy as B
3−import Data.Char (ord)
4−import Data.Maybe
5−import Data.Word
6−import qualified Data.UUID as U
7−import qualified Data.UUID.V5 as U
8−import Test.HUnit
9−import Test.QuickCheck
10−import System.IO
11−import System.Random
12−
13−
14−isValidVersion :: Int -> U.UUID -> Bool
15−isValidVersion v u = lenOK && variantOK && versionOK
16− where bs = U.toByteString u
17− lenOK = B.length bs == 16
18− variantOK = (B.index bs 8) .&. 0xc0 == 0x80
19− versionOK = (B.index bs 6) .&. 0xf0 == fromIntegral (v `shiftL` 4)
20−
21−
22−instance Arbitrary U.UUID where
23− arbitrary = (fst . random) `fmap` rand
24− coarbitrary = undefined
25−
26−instance Arbitrary Word8 where
27− arbitrary = (fromIntegral . fst . randomR (0,255::Int)) `fmap` rand
28− coarbitrary = undefined
29−
30−
31−test_null = TestList [
32− "nil is null" ~: assertBool "" (U.null U.nil),
33− "namespaceDNS is not null" ~: assertBool "" (not $ U.null U.namespaceDNS)
34− ]
35−
36−test_nil = TestList [
37− "nil string" ~: U.toString U.nil @?= "00000000-0000-0000-0000-000000000000",
38− "nil bytes" ~: U.toByteString U.nil @?= B.pack (replicate 16 0)
39− ]
40−
41−test_conv = TestList [
42− "conv bytes to string" ~:
43− maybe "" (U.toString) (U.fromByteString b16) @?= s16,
44− "conv string to bytes" ~:
45− maybe B.empty (U.toByteString) (U.fromString s16) @?= b16
46− ]
47− where b16 = B.pack [1..16]
48− s16 = "01020304-0506-0708-090a-0b0c0d0e0f10"
49−
50−test_v5 = TestList [
51− "V5 computation" ~:
52− U.generateNamed U.namespaceDNS name @?= uV5
53− ]
54− where name = map (fromIntegral . ord) "www.widgets.com" :: [Word8]
55− -- uV3 = fromJust $ U.fromString "3d813cbb-47fb-32ba-91df-831e1593ac29"
56− uV5 = fromJust $ U.fromString "21f7f8de-8051-5b89-8680-0195ef798b6a"
57−
58−prop_stringRoundTrip = label "String round trip" stringRoundTrip
59− where stringRoundTrip :: U.UUID -> Bool
60− stringRoundTrip u = maybe False (== u) $ U.fromString (U.toString u)
61−
62−prop_byteStringRoundTrip = label "ByteString round trip" byteStringRoundTrip
63− where byteStringRoundTrip :: U.UUID -> Bool
64− byteStringRoundTrip u = maybe False (== u)
65− $ U.fromByteString (U.toByteString u)
66−
67−prop_stringLength = label "String length" stringLength
68− where stringLength :: U.UUID -> Bool
69− stringLength u = length (U.toString u) == 36
70−
71−prop_byteStringLength = label "ByteString length" byteStringLength
72− where byteStringLength :: U.UUID -> Bool
73− byteStringLength u = B.length (U.toByteString u) == 16
74−
75−prop_randomsDiffer :: Property
76−prop_randomsDiffer = label "Randoms differ" randomsDiffer
77− where randomsDiffer :: (U.UUID, U.UUID) -> Bool
78− randomsDiffer (u1, u2) = u1 /= u2
79−
80−prop_randomNotNull :: Property
81−prop_randomNotNull = label "Random not null" randomNotNull
82− where randomNotNull :: U.UUID -> Bool
83− randomNotNull = not. U.null
84−
85−prop_randomsValid :: Property
86−prop_randomsValid = label "Random valid" randomsValid
87− where randomsValid :: U.UUID -> Bool
88− randomsValid = isValidVersion 4
89−
90−prop_v5NotNull :: Property
91−prop_v5NotNull = label "V5 not null" v5NotNull
92− where v5NotNull :: [Word8] -> Bool
93− v5NotNull = not . U.null . U.generateNamed U.namespaceDNS
94−
95−prop_v5Valid :: Property
96−prop_v5Valid = label "V5 valid" v5Valid
97− where v5Valid :: [Word8] -> Bool
98− v5Valid = isValidVersion 5 . U.generateNamed U.namespaceDNS
99−
100−
101−main :: IO ()
102−main = do
103− runTestText (putTextToHandle stderr False) (TestList [
104− test_null,
105− test_nil,
106− test_conv,
107− test_v5
108− ])
109− mapM_ quickCheck $ [
110− prop_stringRoundTrip,
111− prop_byteStringRoundTrip,
112− prop_stringLength,
113− prop_byteStringLength,
114− prop_randomsDiffer,
115− prop_randomNotNull,
116− prop_randomsValid,
117− prop_v5NotNull,
118− prop_v5Valid
119− ]
tests/uuid-tests.cabaldeleted−39
@@ -1,39 +0,0 @@
1−Name: uuid-tests
2−Version: 1.0.0
3−Copyright: (c) 2009 Antoine Latter
4−Author: Antoine Latter
5−Maintainer: aslatter@gmail.com
6−License: BSD3
7−License-file: ../LICENSE
8−
9−Category: Data
10−Build-Type: Simple
11−Cabal-Version: >= 1.6
12−
13−Description:
14− This is a set of test programs for testing the uuid package.
15−
16−Synopsis: This is a set of test programs for testing the uuid package.
17−
18−Homepage: http://community.haskell.org/~aslatter/code/uuid/
19−Bug-Reports: mailto:aslatter@gmail.com
20−
21−
22−Executable benchuuid
23− Main-Is: BenchUUID.hs
24− HS-Source-Dirs: . ..
25− Build-Depends: random, binary, bytestring, Crypto, maccatcher,
26− time, base >=3, base < 5,
27− criterion >= 0.3 && < 0.4, parallel >= 2.1 && < 2.3
28−
29− Extensions: DeriveDataTypeable
30−
31−Executable testuuid
32− Main-Is: TestUUID.hs
33− HS-Source-Dirs: . ..
34− Build-Depends: random, binary, bytestring, Crypto, maccatcher,
35− time, base >=3, base < 5,
36− HUnit >=1.2 && < 1.3, QuickCheck >=1.2 && < 1.3
37−
38− Extensions: DeriveDataTypeable
39−
LICENSE → uuid-bench/LICENSErenamed

The content is the same.

uuid-bench/bench/uuid-benchmark.hsnew file+33
@@ -0,0 +1,33 @@
1+import Criterion.Main
2+import Data.Char (ord)
3+import Data.IORef
4+import Data.Word
5+import qualified Data.UUID as U
6+import qualified Data.UUID.V4 as U
7+import qualified Data.UUID.V3 as U3
8+import qualified Data.UUID.V5 as U5
9+import System.Random
10+import System.Random.Mersenne.Pure64
11+
12+main :: IO ()
13+main = do
14+ let n1 = (map (fromIntegral . ord) "http://www.haskell.org/") :: [Word8]
15+
16+ -- setup for random generation
17+ randomState <- newPureMT >>= newIORef
18+ let randomUUID = do
19+ state <- readIORef randomState
20+ let (uuid, state') = random state
21+ writeIORef randomState state'
22+ return uuid
23+
24+ -- benchmark UUID generation
25+ defaultMain [
26+ bgroup "generation" [
27+ bench "V1" $ nfIO U.nextUUID,
28+ bench "V4-stock" $ nfIO (U.nextRandom :: IO U.UUID),
29+ bench "V4-mersenne" $ nfIO (randomUUID :: IO U.UUID),
30+ bench "V3" $ nf (U3.generateNamed U3.namespaceURL) n1,
31+ bench "V5" $ nf (U5.generateNamed U5.namespaceURL) n1
32+ ]
33+ ]
uuid-bench/bench/uuid-types-benchmark.hsnew file+133
@@ -0,0 +1,133 @@
1+{-# LANGUAGE CPP #-}
2+
3+#if !(MIN_VERSION_bytestring(0,10,0))
4+{-# OPTIONS_GHC -fno-warn-orphans #-}
5+-- Needed for NFData instance
6+import Control.DeepSeq
7+import qualified Data.ByteString.Lazy.Internal as BL
8+#endif
9+import Criterion.Main
10+import qualified Data.ByteString.Lazy as BL
11+import qualified Data.HashSet as HashSet
12+import Data.Maybe (fromJust)
13+import qualified Data.Set as Set
14+import qualified Data.UUID.Types as U
15+import Foreign (alloca, peek, poke)
16+import System.Random
17+
18+#if !(MIN_VERSION_bytestring(0,10,0))
19+-- orphan
20+instance NFData BL.ByteString where
21+ rnf BL.Empty = ()
22+ rnf (BL.Chunk _ ts) = rnf ts
23+#endif
24+
25+main :: IO ()
26+main = do
27+ u1 <- randomIO
28+ let s1 = U.toString u1
29+ b1 = U.toByteString u1
30+ a1 = U.toASCIIBytes u1
31+ t1 = U.toText u1
32+ (w1a,w1b,w1c,w1d) = U.toWords u1
33+ nil2 = fromJust $
34+ U.fromString "00000000-0000-0000-0000-000000000000"
35+ u2a = fromJust $ U.fromString "169a5a43-c051-4a16-98f4-08447ddd5dc0"
36+ u2b = fromJust $ U.fromByteString $
37+ BL.pack [0x16, 0x9a, 0x5a, 0x43, 0xc0, 0x51, 0x4a, 0x16,
38+ 0x98, 0xf4, 0x08, 0x44, 0x7d, 0xdd, 0x5d, 0xc0]
39+ u3 = fromJust $ U.fromString "dea6f619-1038-438b-b4af-f1cdec1e6e23"
40+
41+ -- setup for Storable benchmark
42+ alloca $ \ uuidPtr -> do
43+
44+ poke uuidPtr u1
45+
46+ defaultMain [
47+ bgroup "testing" [
48+ bench "null non-nil" $ whnf U.null u1,
49+ bench "null nil" $ whnf U.null U.nil,
50+ bench "null nil2" $ whnf U.null nil2,
51+ bench "eq same" $ whnf (==u2a) u2b,
52+ bench "eq differ" $ whnf (==u2a) u3,
53+ bench "compare same" $ whnf (compare u2a) u2b,
54+ bench "compare differ" $ whnf (compare u2a) u3
55+ ],
56+ bgroup "conversion" [
57+ bench "toString" $ nf U.toString u1,
58+ bench "fromString" $ nf U.fromString s1,
59+ bench "toByteString" $ nf U.toByteString u1,
60+ bench "fromByteString" $ nf U.fromByteString b1,
61+ bench "toASCIIBytes" $ nf U.toASCIIBytes u1,
62+ bench "fromASCIIBytes" $ nf U.fromASCIIBytes a1,
63+ bench "toWords" $ nf U.toWords u1,
64+ bench "fromWords" $ nf (U.fromWords w1a w1b w1c) w1d,
65+ bench "toText" $ nf U.toText u1,
66+ bench "fromText" $ nf U.fromText t1
67+ ],
68+
69+ bench "Set making" $ nf Set.fromList uuids,
70+ bench "HashSet making" $ nf HashSet.fromList uuids,
71+
72+ bgroup "storable" [
73+ bench "peek" $ nfIO (peek uuidPtr),
74+ bench "poke" $ whnfIO $ poke uuidPtr u1
75+ ]
76+ ]
77+
78+-- 50 uuids, so tests can be repeatable
79+uuids :: [U.UUID]
80+uuids
81+ = map (fromJust . U.fromString)
82+ [
83+ "35d42593-1fca-4465-b588-a2e78cb996ba",
84+ "1e97e407-eca7-4c5d-a947-6fbe9dc168b6",
85+ "a41fd7ce-a053-4c0a-a742-77c95b85da2a",
86+ "f7e3913a-0fd7-4355-a92f-d73f9b046efa",
87+ "8961a35d-55c2-42f3-8680-08fce3986647",
88+ "96246c58-d0b4-4e56-a543-356bd59686a9",
89+ "72c46194-648c-4b1e-a9fb-2eba060ab43b",
90+ "0fc252d4-a37b-4eca-9309-e3d2a59a3a22",
91+ "a8aceb5a-6a8e-43f3-85bb-9653a3c1ebcd",
92+ "b23d1118-6bc8-4add-9d56-99634d78949f",
93+ "5f8c7896-9c4f-4d7e-a4d2-961bda298012",
94+ "219a4137-7bc5-42b1-ac95-490948a978e1",
95+ "5af5024f-fbe9-45ab-991d-49b655994437",
96+ "569dfb33-185d-4a3c-99c4-bc2b83250a7c",
97+ "43a58442-aa51-4a5d-8e00-b8a83b5fc5b0",
98+ "2865ced1-b54d-4725-8f01-b408f4617424",
99+ "b8cfaff0-4dee-4f32-af2f-0469b3e535fc",
100+ "63f45bc0-f303-4f1a-b0d6-76f876be626d",
101+ "d171eaf3-f20d-45d6-9268-0cc22dfbe887",
102+ "7c28f457-ad27-494a-8642-6e47e7f3efb8",
103+ "f8de9193-66ff-49e8-9826-fc50858d7855",
104+ "2af85f28-cace-4740-b8bb-2b5860f5fdb3",
105+ "b12a7a22-edb3-4694-b8f4-0532eaad6112",
106+ "5e052a08-8e49-4668-bbe7-77cdbc4679a3",
107+ "42d5a68d-3f08-4e39-9b8c-71cc17c538ed",
108+ "ba2b1487-b3a4-4a19-98cc-59530f36613f",
109+ "e4a5c569-b8ac-4851-8ad2-fbdb89986be2",
110+ "35b4a1b6-b5ca-4646-803b-c337ee730d9a",
111+ "f0df1206-05d9-49d6-a726-d49fb253e645",
112+ "9656a0f0-89b2-4cec-bb1c-fdf5633e1cd7",
113+ "d13382f5-04a1-422d-94d6-e47219425816",
114+ "b8d0c762-4c6b-4bd0-ad0b-f68988a87166",
115+ "06360e85-f18a-44f6-aa72-45f1e60b6b77",
116+ "347491ca-62b3-48e8-ac94-6ffebe1318ed",
117+ "014339d0-7b2d-4dda-914b-14ee5cb4391b",
118+ "dc57931b-4744-41be-b3c4-e24dbeeb606a",
119+ "2c9fdcf0-e1d6-4a2d-951d-4766b99032cb",
120+ "b6bde422-eea8-4231-bf1c-ee0e56699511",
121+ "921073c5-f7c1-4583-ac03-aeb7aef8662b",
122+ "eff6a517-aeb1-453e-9810-1b4b324c5a1e",
123+ "eadaae8c-cbf8-4e0b-ab80-e34284b07dad",
124+ "4d307c36-70d9-453f-8455-ec7e2ba405ed",
125+ "53ddef9a-2413-4f7f-8363-cff56ee17c6c",
126+ "4dd4c27a-b300-4a00-ab87-eef505275492",
127+ "4a5d7001-f0c1-4e2f-8362-8833bda2114b",
128+ "0c46f438-9365-406a-b04e-34436806ec25",
129+ "b35469cf-05f8-40ff-a38b-117604347957",
130+ "f1c54df0-5f59-4891-b3c6-82bac0d814ca",
131+ "8091837c-6456-42c3-a686-f4731a41d4f9",
132+ "2a0e2efb-a11c-4a44-81ee-3efc37379b48"
133+ ]
uuid-bench/src-uuidnew file+1
@@ -0,0 +1 @@
1+../uuid/src
uuid-bench/src-uuid-typesnew file+1
@@ -0,0 +1 @@
1+../uuid-types/src
uuid-bench/uuid-bench.cabalnew file+126
@@ -0,0 +1,126 @@
1+cabal-version: 1.12
2+name: uuid-bench
3+version: 0
4+copyright:
5+ (c) 2017-2018 Herbert Valerio Riedel
6+ (c) 2008-2014 Antoine Latter
7+
8+author: Antoine Latter
9+maintainer: Oleg Grenrus <oleg.grenrus@iki.fi>
10+license: BSD3
11+license-file: LICENSE
12+category: Data
13+build-type: Simple
14+
15+-- Benchmarking with older GHCs is not meaningful
16+tested-with:
17+ GHC ==8.6.5
18+ || ==8.8.4
19+ || ==8.10.7
20+ || ==9.0.2
21+ || ==9.2.8
22+ || ==9.4.8
23+ || ==9.6.6
24+ || ==9.8.2
25+ || ==9.10.1
26+
27+synopsis: UUID benchmarks
28+description:
29+ UUID benchmarks.
30+ This package is combined uuid and uuid-types, renamed so we do not
31+ cause benchmark tools to be build against local package.
32+
33+homepage: https://github.com/haskell-hvr/uuid
34+bug-reports: https://github.com/haskell-hvr/uuid/issues
35+
36+source-repository head
37+ type: git
38+ location: https://github.com/haskell-hvr/uuid.git
39+ subdir: uuid-bench
40+
41+library
42+ build-depends:
43+ base >=4.12.0.0 && <5
44+ , binary >=0.8.6.0 && <0.9
45+ , bytestring >=0.10.8.2 && <0.13
46+ , cryptohash-md5 >=0.11.100 && <0.12
47+ , cryptohash-sha1 >=0.11.100 && <0.12
48+ , deepseq >=1.4.4.0 && <1.6
49+ , entropy >=0.3.7 && <0.5
50+ , hashable >=1.4.4.0 && <1.6
51+ , network-info >=0.2 && <0.3
52+ , random >=1.2.1.2 && <1.3
53+ , template-haskell >=2.14.0.0 && <2.23
54+ , text >=1.2.3.0 && <1.3 || >=2.0 && <2.2
55+ , time >=1.4 && <1.13
56+
57+ -- uuid modules
58+ exposed-modules:
59+ Data.UUID
60+ Data.UUID.Util
61+ Data.UUID.V3
62+ Data.UUID.V4
63+ Data.UUID.V5
64+
65+ other-modules:
66+ Data.UUID.Named
67+ Data.Word.Util
68+
69+ -- uuid-types modules
70+ exposed-modules: Data.UUID.Types
71+
72+ -- Exposed for companion projects; *NOT* part of the official API:
73+ exposed-modules:
74+ Data.UUID.Types.Internal
75+ Data.UUID.Types.Internal.Builder
76+
77+ default-language: Haskell2010
78+ other-extensions:
79+ DeriveDataTypeable
80+ TypeFamilies
81+
82+ ghc-options: -Wall
83+ hs-source-dirs: src-uuid-types src-uuid
84+
85+benchmark uuid-types-benchmark
86+ type: exitcode-stdio-1.0
87+ main-is: uuid-types-benchmark.hs
88+ hs-source-dirs: bench
89+ default-language: Haskell2010
90+ other-extensions: CPP
91+ ghc-options: -Wall
92+
93+ -- inherited constraints
94+ build-depends:
95+ base
96+ , bytestring
97+ , random
98+ , uuid-bench
99+
100+ -- deps w/o inherited constraints
101+ build-depends:
102+ containers >=0.5 && <0.8
103+ , criterion >=1.5 && <1.7
104+ , unordered-containers >=0.2.7 && <0.3
105+
106+benchmark uuid-benchmark
107+ type: exitcode-stdio-1.0
108+ main-is: uuid-benchmark.hs
109+ hs-source-dirs: bench
110+ default-language: Haskell2010
111+ default-extensions:
112+ CPP
113+ DeriveDataTypeable
114+
115+ ghc-options: -Wall -fno-warn-orphans
116+
117+ -- inherited constraints
118+ build-depends:
119+ base
120+ , random
121+ , uuid-bench
122+
123+ -- deps w/o inherited constraints
124+ build-depends:
125+ criterion >=1.5 && <1.7
126+ , mersenne-random-pure64 >=0.2 && <0.3
uuid-types/ChangeLog.mdnew file+31
@@ -0,0 +1,31 @@
1+## 1.0.6 (2023-04-16)
2+
3+- Support GHC-8.6.5..GHC-9.10.1
4+
5+## 1.0.5 (2021-05-03)
6+
7+- Add (Template Haskell) `Lift UUID` instance
8+
9+## 1.0.4.0
10+
11+- Declare `Data.UUID.Types` module "`Trustworthy`" with respect to SafeHaskell.
12+- Use more compact heap object representation which saves 16 bytes on 64bit platforms.
13+- Add `toWords64`/`fromWords64` functions
14+- Drop support for GHC < 7.
15+- Add support for `random-1.2`, i.e. idiomatic `Random` and added `Uniform` instances.
16+
17+## 1.0.3
18+
19+- Bump package dependencies.
20+
21+## 1.0.2
22+
23+- Add `toText`/`fromText` functions.
24+
25+## 1.0.1
26+
27+- Update dependencies in tests and benchmarks.
28+
29+## 1.0.0
30+
31+- Initial split from "`uuid-1.3.8`" package.
uuid-types/LICENSEnew file+28
@@ -0,0 +1,28 @@
1+Copyright (c) 2008, Antoine Latter
2+
3+All rights reserved.
4+
5+Redistribution and use in source and binary forms, with or without
6+modification, are permitted provided that the following conditions are
7+met:
8+
9+ * Redistributions of source code must retain the above copyright
10+notice, this list of conditions and the following disclaimer.
11+ * Redistributions in binary form must reproduce the above copyright
12+notice, this list of conditions and the following disclaimer in the
13+documentation and/or other materials provided with the distribution.
14+ * The names of the authors may not be used to endorse or promote
15+products derived from this software without specific prior written
16+permission.
17+
18+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Setup.hs → uuid-types/Setup.hsrenamed

The content is the same.

uuid-types/cabal.projectnew file+1
@@ -0,0 +1 @@
1+packages: .
uuid-types/src/Data/UUID/Types.hsnew file+47
@@ -0,0 +1,47 @@
1+{-# LANGUAGE Trustworthy #-}
2+
3+{- |
4+Module : Data.UUID.Types
5+Copyright : (c) 2017-2018 Herbert Valerio Riedel
6+ (c) 2008,2012 Antoine Latter
7+
8+License : BSD-style
9+
10+Maintainer : hvr@gnu.org
11+Portability : portable
12+
13+This library is useful for comparing, parsing and
14+printing <http://en.wikipedia.org/wiki/UUID Universally Unique Identifiers (UUID)>.
15+See <http://tools.ietf.org/html/rfc4122 RFC 4122> for the specification.
16+
17+-}
18+module Data.UUID.Types
19+ ( -- * The 'UUID' Type
20+ UUID
21+ -- * Nil UUID
22+ , nil
23+ , null
24+ -- * Textual Representation
25+ , toString
26+ , fromString
27+ , toText
28+ , fromText
29+ , toASCIIBytes
30+ , fromASCIIBytes
31+ , toLazyASCIIBytes
32+ , fromLazyASCIIBytes
33+ -- * Binary Representation
34+ , toByteString
35+ , fromByteString
36+ -- * Integer Representation
37+ , toWords
38+ , fromWords
39+ , toWords64
40+ , fromWords64
41+ ) where
42+
43+import Data.UUID.Types.Internal
44+import Prelude ()
45+
46+-- Everything is really implemented in Data.UUID.Types.Internal, but I
47+-- don't want to export the constructors out of the package.
uuid-types/src/Data/UUID/Types/Internal.hsnew file+575
@@ -0,0 +1,575 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DeriveDataTypeable #-}
3+{-# LANGUAGE TypeFamilies #-}
4+{-# LANGUAGE ViewPatterns #-}
5+{-# LANGUAGE Unsafe #-}
6+{-# LANGUAGE DeriveLift #-}
7+{-# LANGUAGE StandaloneDeriving #-}
8+{-# OPTIONS_HADDOCK hide #-}
9+
10+-- |
11+-- Module : Data.UUID.Types.Internal
12+-- Copyright : (c) 2017-2018 Herbert Valerio Riedel
13+-- (c) 2008-2009, 2012 Antoine Latter
14+-- (c) 2009 Mark Lentczner
15+--
16+-- License : BSD-style
17+--
18+-- Maintainer : hvr@gnu.org
19+-- Portability : portable
20+
21+module Data.UUID.Types.Internal
22+ ( UUID(..)
23+ , null
24+ , nil
25+ , fromByteString
26+ , toByteString
27+ , fromString
28+ , toString
29+ , fromText
30+ , toText
31+ , fromWords
32+ , toWords
33+ , fromWords64
34+ , toWords64
35+ , toList
36+ , buildFromBytes
37+ , buildFromWords
38+ , fromASCIIBytes
39+ , toASCIIBytes
40+ , fromLazyASCIIBytes
41+ , toLazyASCIIBytes
42+ , UnpackedUUID(..)
43+ , pack
44+ , unpack
45+ ) where
46+
47+import Prelude hiding (null)
48+
49+import Control.DeepSeq (NFData (..))
50+import Control.Monad (guard, liftM2)
51+import Data.Bits
52+import Data.Char
53+import Data.Data
54+import Data.Hashable
55+import Data.List (elemIndices)
56+import Foreign.Ptr (Ptr)
57+
58+import Foreign.Storable
59+
60+import Data.Binary
61+import Data.Binary.Get
62+import Data.Binary.Put
63+import qualified Data.ByteString as B
64+import qualified Data.ByteString.Internal as BI
65+import qualified Data.ByteString.Lazy as BL
66+import qualified Data.ByteString.Unsafe as BU
67+import Data.Text (Text)
68+import qualified Data.Text.Encoding as T
69+
70+import Data.UUID.Types.Internal.Builder
71+
72+import System.Random (Random (..), uniform)
73+import System.Random.Stateful (Uniform (..), uniformWord64)
74+
75+import Language.Haskell.TH.Syntax (Lift)
76+
77+-- | Type representing <https://en.wikipedia.org/wiki/UUID Universally Unique Identifiers (UUID)> as specified in
78+-- <http://tools.ietf.org/html/rfc4122 RFC 4122>.
79+data UUID = UUID {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64
80+ deriving (Eq, Ord)
81+{-
82+ Prior to uuid-types-1.0.4:
83+ !Word32 !Word32 !Word32 !Word32
84+ Other representations that we tried are:
85+ Mimic V1 structure: !Word32 !Word16 !Word16 !Word16
86+ !Word8 !Word8 !Word8 !Word8 !Word8 !Word8
87+ Sixteen bytes: !Word8 ... (x 16)
88+ Simple list of bytes: [Word8]
89+ ByteString (strict) ByteString
90+ Immutable array: UArray Int Word8
91+ Vector: UArr Word8
92+ None was as fast, overall, as the representation used here.
93+-}
94+
95+-- | Convert a 'UUID' into a sequence of 'Word32' values.
96+-- Useful for when you need to serialize a UUID and
97+-- neither 'Storable' nor 'Binary' are appropriate.
98+--
99+-- >>> toWords <$> fromString "550e8400-e29b-41d4-a716-446655440000"
100+-- Just (1427014656,3801825748,2803254374,1430519808)
101+--
102+-- See also 'toWords64'.
103+--
104+-- /Since: @uuid-1.2.2@/
105+--
106+-- @since 1.0.0
107+toWords :: UUID -> (Word32, Word32, Word32, Word32)
108+toWords (UUID w12 w34) = (w1, w2, w3, w4)
109+ where
110+ w1 = fromIntegral (w12 `unsafeShiftR` 32)
111+ w2 = fromIntegral w12
112+ w3 = fromIntegral (w34 `unsafeShiftR` 32)
113+ w4 = fromIntegral w34
114+
115+-- | Create a 'UUID' from a sequence of 'Word32'. The
116+-- inverse of 'toWords'. Useful when you need a total
117+-- function for constructing 'UUID' values.
118+--
119+-- See also 'fromWords64'.
120+--
121+-- /Since: @uuid-1.2.2@/
122+--
123+-- @since 1.0.0
124+fromWords :: Word32 -> Word32 -> Word32 -> Word32 -> UUID
125+fromWords w1 w2 w3 w4 = UUID (w32to64 w1 w2) (w32to64 w3 w4)
126+
127+-- | Convert a 'UUID' into a pair of 'Word64's.
128+--
129+-- >>> toWords64 <$> fromString "550e8400-e29b-41d4-a716-446655440000"
130+-- Just (6128981282234515924,12039885860129472512)
131+--
132+-- See also 'toWords'.
133+--
134+-- @since 1.0.4
135+toWords64 :: UUID -> (Word64, Word64)
136+toWords64 (UUID w12 w34) = (w12,w34)
137+
138+-- | Create a 'UUID' from a pair of 'Word64's.
139+--
140+-- Inverse of 'toWords64'. See also 'fromWords'.
141+--
142+-- @since 1.0.4
143+fromWords64 :: Word64 -> Word64 -> UUID
144+fromWords64 = UUID
145+
146+data UnpackedUUID =
147+ UnpackedUUID {
148+ time_low :: Word32 -- 0-3
149+ , time_mid :: Word16 -- 4-5
150+ , time_hi_and_version :: Word16 -- 6-7
151+ , clock_seq_hi_res :: Word8 -- 8
152+ , clock_seq_low :: Word8 -- 9
153+ , node_0 :: Word8
154+ , node_1 :: Word8
155+ , node_2 :: Word8
156+ , node_3 :: Word8
157+ , node_4 :: Word8
158+ , node_5 :: Word8
159+ }
160+ deriving (Read, Show, Eq, Ord)
161+
162+unpack :: UUID -> UnpackedUUID
163+unpack (UUID w0 w1) = build /-/ w0 /-/ w1
164+ where
165+ build x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF =
166+ UnpackedUUID {
167+ time_low = word x0 x1 x2 x3
168+ , time_mid = w8to16 x4 x5
169+ , time_hi_and_version = w8to16 x6 x7
170+ , clock_seq_hi_res = x8
171+ , clock_seq_low = x9
172+ , node_0 = xA
173+ , node_1 = xB
174+ , node_2 = xC
175+ , node_3 = xD
176+ , node_4 = xE
177+ , node_5 = xF
178+ }
179+
180+pack :: UnpackedUUID -> UUID
181+pack unpacked =
182+ makeFromBytes /-/ (time_low unpacked)
183+ /-/ (time_mid unpacked)
184+ /-/ (time_hi_and_version unpacked)
185+ /-/ (clock_seq_hi_res unpacked)
186+ /-/ (clock_seq_low unpacked)
187+ /-/ (node_0 unpacked) /-/ (node_1 unpacked)
188+ /-/ (node_2 unpacked) /-/ (node_3 unpacked)
189+ /-/ (node_4 unpacked) /-/ (node_5 unpacked)
190+
191+
192+--
193+-- UTILITIES
194+--
195+
196+-- |Build a Word32 from four Word8 values, presented in big-endian order
197+word :: Word8 -> Word8 -> Word8 -> Word8 -> Word32
198+word a b c d = (fromIntegral a `unsafeShiftL` 24)
199+ .|. (fromIntegral b `unsafeShiftL` 16)
200+ .|. (fromIntegral c `unsafeShiftL` 8)
201+ .|. (fromIntegral d )
202+
203+-- |Extract a Word8 from a Word64. Bytes, high to low, are numbered from 7 to 0,
204+byte :: Int -> Word64 -> Word8
205+byte i w = fromIntegral (w `shiftR` (i * 8))
206+
207+-- |Build a Word16 from two Word8 values, presented in big-endian order.
208+w8to16 :: Word8 -> Word8 -> Word16
209+w8to16 w0s w1s =
210+ (w0 `unsafeShiftL` 8) .|. w1
211+ where
212+ w0 = fromIntegral w0s
213+ w1 = fromIntegral w1s
214+
215+-- | Construct 'Word64' from low/high 'Word32's
216+w32to64 :: Word32 -> Word32 -> Word64
217+w32to64 w0 w1 = (fromIntegral w0 `unsafeShiftL` 32) .|. (fromIntegral w1)
218+
219+-- |Make a UUID from sixteen Word8 values
220+makeFromBytes :: Word8 -> Word8 -> Word8 -> Word8
221+ -> Word8 -> Word8 -> Word8 -> Word8
222+ -> Word8 -> Word8 -> Word8 -> Word8
223+ -> Word8 -> Word8 -> Word8 -> Word8
224+ -> UUID
225+makeFromBytes b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf
226+ = fromWords w0 w1 w2 w3
227+ where w0 = word b0 b1 b2 b3
228+ w1 = word b4 b5 b6 b7
229+ w2 = word b8 b9 ba bb
230+ w3 = word bc bd be bf
231+
232+-- |A Builder for constructing a UUID of a given version.
233+buildFromBytes :: Word8
234+ -> Word8 -> Word8 -> Word8 -> Word8
235+ -> Word8 -> Word8 -> Word8 -> Word8
236+ -> Word8 -> Word8 -> Word8 -> Word8
237+ -> Word8 -> Word8 -> Word8 -> Word8
238+ -> UUID
239+buildFromBytes v b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf =
240+ makeFromBytes b0 b1 b2 b3 b4 b5 b6' b7 b8' b9 ba bb bc bd be bf
241+ where b6' = b6 .&. 0x0f .|. (v `shiftL` 4)
242+ b8' = b8 .&. 0x3f .|. 0x80
243+
244+-- |Build a UUID of a given version from 'Word32' values.
245+buildFromWords :: Word8 -> Word32 -> Word32 -> Word32 -> Word32 -> UUID
246+buildFromWords v w0 w1 w2 w3 = fromWords w0 w1' w2' w3
247+ where w1' = w1 .&. 0xffff0fff .|. ((fromIntegral v) `shiftL` 12)
248+ w2' = w2 .&. 0x3fffffff .|. 0x80000000
249+
250+
251+-- |Return the bytes that make up the UUID
252+toList :: UUID -> [Word8]
253+toList (UUID w0 w1) =
254+ [byte 7 w0, byte 6 w0, byte 5 w0, byte 4 w0,
255+ byte 3 w0, byte 2 w0, byte 1 w0, byte 0 w0,
256+ byte 7 w1, byte 6 w1, byte 5 w1, byte 4 w1,
257+ byte 3 w1, byte 2 w1, byte 1 w1, byte 0 w1]
258+
259+-- |Construct a UUID from a list of Word8. Returns Nothing if the list isn't
260+-- exactly sixteen bytes long
261+fromList :: [Word8] -> Maybe UUID
262+fromList [b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf] =
263+ Just $ makeFromBytes b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf
264+fromList _ = Nothing
265+
266+
267+--
268+-- UUID API
269+--
270+
271+-- |Returns true if the passed-in UUID is the 'nil' UUID.
272+null :: UUID -> Bool
273+null = (== nil)
274+ -- Note: This actually faster than:
275+ -- null (UUID 0 0 0 0) = True
276+ -- null _ = False
277+
278+-- |The 'nil' UUID, as defined in <http://tools.ietf.org/html/rfc4122 RFC 4122>.
279+-- It is a UUID of all zeros. @'null' u@ /iff/ @'u' == 'nil'@.
280+nil :: UUID
281+nil = UUID 0 0
282+
283+-- |Extract a UUID from a 'ByteString' in network byte order.
284+-- The argument must be 16 bytes long, otherwise 'Nothing' is returned.
285+fromByteString :: BL.ByteString -> Maybe UUID
286+fromByteString = fromList . BL.unpack
287+
288+-- |Encode a UUID into a 'ByteString' in network order.
289+--
290+-- This uses the same encoding as the 'Binary' instance.
291+toByteString :: UUID -> BL.ByteString
292+toByteString = BL.pack . toList
293+
294+-- |If the passed in 'String' can be parsed as a 'UUID', it will be.
295+-- The hyphens may not be omitted.
296+-- Example:
297+--
298+-- >>> fromString "c2cc10e1-57d6-4b6f-9899-38d972112d8c"
299+-- Just c2cc10e1-57d6-4b6f-9899-38d972112d8c
300+--
301+-- Hex digits may be upper or lower-case.
302+fromString :: String -> Maybe UUID
303+fromString xs | validFmt = fromString' xs
304+ | otherwise = Nothing
305+ where validFmt = elemIndices '-' xs == [8,13,18,23]
306+
307+fromString' :: String -> Maybe UUID
308+fromString' s0 = do
309+ (w0, s1) <- hexWord s0
310+ (w1, s2) <- hexWord s1
311+ (w2, s3) <- hexWord s2
312+ (w3, s4) <- hexWord s3
313+ if s4 /= "" then Nothing
314+ else Just $ fromWords w0 w1 w2 w3
315+ where hexWord :: String -> Maybe (Word32, String)
316+ hexWord s = Just (0, s) >>= hexByte >>= hexByte
317+ >>= hexByte >>= hexByte
318+
319+ hexByte :: (Word32, String) -> Maybe (Word32, String)
320+ hexByte (w, '-':ds) = hexByte (w, ds)
321+ hexByte (w, hi:lo:ds)
322+ | bothHex = Just ((w `shiftL` 8) .|. octet, ds)
323+ | otherwise = Nothing
324+ where bothHex = isHexDigit hi && isHexDigit lo
325+ octet = fromIntegral (16 * digitToInt hi + digitToInt lo)
326+ hexByte _ = Nothing
327+
328+-- | Convert a UUID into a hypenated string using lower-case letters.
329+-- Example:
330+--
331+-- >>> toString <$> fromString "550e8400-e29b-41d4-a716-446655440000"
332+-- Just "550e8400-e29b-41d4-a716-446655440000"
333+--
334+--
335+toString :: UUID -> String
336+toString uuid = hexw0 w0 $ hexw1 w1 ""
337+ where hexw0 :: Word64 -> String -> String
338+ hexw0 w s = hexn w 60 : hexn w 56 : hexn w 52 : hexn w 48
339+ : hexn w 44 : hexn w 40 : hexn w 36 : hexn w 32
340+ : '-' : hexn w 28 : hexn w 24 : hexn w 20 : hexn w 16
341+ : '-' : hexn w 12 : hexn w 8 : hexn w 4 : hexn w 0
342+ : s
343+
344+ hexw1 :: Word64 -> String -> String
345+ hexw1 w s = '-' : hexn w 60 : hexn w 56 : hexn w 52 : hexn w 48
346+ : '-' : hexn w 44 : hexn w 40 : hexn w 36 : hexn w 32
347+ : hexn w 28 : hexn w 24 : hexn w 20 : hexn w 16
348+ : hexn w 12 : hexn w 8 : hexn w 4 : hexn w 0
349+ : s
350+
351+ hexn :: Word64 -> Int -> Char
352+ hexn w r = intToDigit $ fromIntegral ((w `shiftR` r) .&. 0xf)
353+
354+ (w0,w1) = toWords64 uuid
355+
356+-- | If the passed in `Text` can be parsed as an ASCII representation of
357+-- a `UUID`, it will be. The hyphens may not be omitted.
358+fromText :: Text -> Maybe UUID
359+fromText = fromASCIIBytes . T.encodeUtf8
360+
361+-- | Convert a UUID into a hyphentated string using lower-case letters.
362+toText :: UUID -> Text
363+toText = T.decodeLatin1 . toASCIIBytes
364+
365+-- | Convert a UUID into a hyphentated string using lower-case letters, packed
366+-- as ASCII bytes into `B.ByteString`.
367+--
368+-- This should be equivalent to `toString` with `Data.ByteString.Char8.pack`.
369+toASCIIBytes :: UUID -> B.ByteString
370+toASCIIBytes uuid = BI.unsafeCreate 36 (pokeASCII uuid)
371+
372+-- | Helper function for `toASCIIBytes`
373+pokeASCII :: UUID -> Ptr Word8 -> IO ()
374+pokeASCII uuid ptr = do
375+ pokeDash 8
376+ pokeDash 13
377+ pokeDash 18
378+ pokeDash 23
379+ pokeSingle 0 w0
380+ pokeDouble 9 w1
381+ pokeDouble 19 w2
382+ pokeSingle 28 w3
383+ where
384+ (w0, w1, w2, w3) = toWords uuid
385+
386+ -- ord '-' ==> 45
387+ pokeDash ix = pokeElemOff ptr ix 45
388+
389+ pokeSingle ix w = do
390+ pokeWord ix w 28
391+ pokeWord (ix + 1) w 24
392+ pokeWord (ix + 2) w 20
393+ pokeWord (ix + 3) w 16
394+ pokeWord (ix + 4) w 12
395+ pokeWord (ix + 5) w 8
396+ pokeWord (ix + 6) w 4
397+ pokeWord (ix + 7) w 0
398+
399+ -- We skip the dash in the middle
400+ pokeDouble ix w = do
401+ pokeWord ix w 28
402+ pokeWord (ix + 1) w 24
403+ pokeWord (ix + 2) w 20
404+ pokeWord (ix + 3) w 16
405+ pokeWord (ix + 5) w 12
406+ pokeWord (ix + 6) w 8
407+ pokeWord (ix + 7) w 4
408+ pokeWord (ix + 8) w 0
409+
410+ pokeWord ix w r =
411+ pokeElemOff ptr ix (fromIntegral (toDigit ((w `shiftR` r) .&. 0xf)))
412+
413+ toDigit :: Word32 -> Word32
414+ toDigit w = if w < 10 then 48 + w else 97 + w - 10
415+
416+-- | If the passed in `B.ByteString` can be parsed as an ASCII representation of
417+-- a `UUID`, it will be. The hyphens may not be omitted.
418+--
419+-- This should be equivalent to `fromString` with `Data.ByteString.Char8.unpack`.
420+fromASCIIBytes :: B.ByteString -> Maybe UUID
421+fromASCIIBytes bs = do
422+ guard wellFormed
423+ fromWords <$> single 0 <*> double 9 14 <*> double 19 24 <*> single 28
424+ where
425+ -- ord '-' ==> 45
426+ dashIx bs' ix = BU.unsafeIndex bs' ix == 45
427+
428+ -- Important: check the length first, given the `unsafeIndex` later.
429+ wellFormed =
430+ B.length bs == 36 && dashIx bs 8 && dashIx bs 13 &&
431+ dashIx bs 18 && dashIx bs 23
432+
433+ single ix = combine <$> octet ix <*> octet (ix + 2)
434+ <*> octet (ix + 4) <*> octet (ix + 6)
435+ double ix0 ix1 = combine <$> octet ix0 <*> octet (ix0 + 2)
436+ <*> octet ix1 <*> octet (ix1 + 2)
437+
438+ combine o0 o1 o2 o3 = shiftL o0 24 .|. shiftL o1 16 .|. shiftL o2 8 .|. o3
439+
440+ octet ix = do
441+ hi <- fromIntegral <$> toDigit (BU.unsafeIndex bs ix)
442+ lo <- fromIntegral <$> toDigit (BU.unsafeIndex bs (ix + 1))
443+ return (16 * hi + lo)
444+
445+ toDigit :: Word8 -> Maybe Word8
446+ toDigit w
447+ -- Digit
448+ | w >= 48 && w <= 57 = Just (w - 48)
449+ -- Uppercase
450+ | w >= 65 && w <= 70 = Just (10 + w - 65)
451+ -- Lowercase
452+ | w >= 97 && w <= 102 = Just (10 + w - 97)
453+ | otherwise = Nothing
454+
455+-- | Similar to `toASCIIBytes` except we produce a lazy `BL.ByteString`.
456+toLazyASCIIBytes :: UUID -> BL.ByteString
457+toLazyASCIIBytes =
458+ BL.fromStrict
459+ . toASCIIBytes
460+
461+-- | Similar to `fromASCIIBytes` except parses from a lazy `BL.ByteString`.
462+fromLazyASCIIBytes :: BL.ByteString -> Maybe UUID
463+fromLazyASCIIBytes bs =
464+ if BL.length bs == 36 then fromASCIIBytes (BL.toStrict bs) else Nothing
465+
466+--
467+-- Class Instances
468+--
469+
470+-- | This 'Random' instance produces __insecure__ version 4 UUIDs as
471+-- specified in <http://tools.ietf.org/html/rfc4122 RFC 4122>.
472+instance Random UUID where
473+ random = uniform
474+ randomR _ = random -- range is ignored
475+
476+-- @since 1.0.4
477+instance Uniform UUID where
478+ uniformM gen = do
479+ w0 <- uniformWord64 gen
480+ w1 <- uniformWord64 gen
481+ pure $ buildFromBytes 4 /-/ w0 /-/ w1
482+
483+-- |A ByteSource to extract only three bytes from an Int, since next on StdGet
484+-- only returns 31 bits of randomness.
485+type instance ByteSink ThreeByte g = Takes3Bytes g
486+newtype ThreeByte = ThreeByte Int
487+instance ByteSource ThreeByte where
488+ f /-/ (ThreeByte w) = f b1 b2 b3
489+ where b1 = fromIntegral (w `unsafeShiftR` 16)
490+ b2 = fromIntegral (w `unsafeShiftR` 8)
491+ b3 = fromIntegral w
492+
493+instance NFData UUID where
494+ rnf = flip seq ()
495+
496+instance Hashable UUID where
497+ hash (toWords -> (w0,w1,w2,w3)) =
498+ hash w0 `hashWithSalt` w1
499+ `hashWithSalt` w2
500+ `hashWithSalt` w3
501+ hashWithSalt s (toWords -> (w0,w1,w2,w3)) =
502+ s `hashWithSalt` w0
503+ `hashWithSalt` w1
504+ `hashWithSalt` w2
505+ `hashWithSalt` w3
506+
507+-- | Pretty prints a 'UUID' (without quotation marks). See also 'toString'.
508+--
509+-- >>> show nil
510+-- "00000000-0000-0000-0000-000000000000"
511+--
512+instance Show UUID where
513+ show = toString
514+
515+instance Read UUID where
516+ readsPrec _ str =
517+ let noSpaces = dropWhile isSpace str
518+ in case fromString (take 36 noSpaces) of
519+ Nothing -> []
520+ Just u -> [(u,drop 36 noSpaces)]
521+
522+-- | This 'Storable' instance uses the memory layout as described in <http://tools.ietf.org/html/rfc4122 RFC 4122>, but in contrast to the 'Binary' instance, __the fields are stored in host byte order__.
523+instance Storable UUID where
524+ sizeOf _ = 16
525+ alignment _ = 4
526+
527+ peekByteOff p off =
528+ pack <$>
529+ (UnpackedUUID
530+ <$> peekByteOff p off -- Word32
531+ <*> peekByteOff p (off+4) -- Word16
532+ <*> peekByteOff p (off+6) -- Word16
533+ <*> peekByteOff p (off+8) -- Word8
534+ <*> peekByteOff p (off+9) -- Word8
535+ <*> peekByteOff p (off+10) -- Word8
536+ <*> peekByteOff p (off+11) -- Word8
537+ <*> peekByteOff p (off+12) -- Word8
538+ <*> peekByteOff p (off+13) -- Word8
539+ <*> peekByteOff p (off+14) -- Word8
540+ <*> peekByteOff p (off+15) -- Word8
541+ )
542+
543+ pokeByteOff p off u =
544+ case unpack u of
545+ (UnpackedUUID x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 x10) ->
546+ do
547+ pokeByteOff p off x0
548+ pokeByteOff p (off+4) x1
549+ pokeByteOff p (off+6) x2
550+ pokeByteOff p (off+8) x3
551+ pokeByteOff p (off+9) x4
552+ pokeByteOff p (off+10) x5
553+ pokeByteOff p (off+11) x6
554+ pokeByteOff p (off+12) x7
555+ pokeByteOff p (off+13) x8
556+ pokeByteOff p (off+14) x9
557+ pokeByteOff p (off+15) x10
558+
559+-- | This 'Binary' instance is compatible with <http://tools.ietf.org/html/rfc4122 RFC 4122>, storing the fields in network order as 16 bytes.
560+instance Binary UUID where
561+ put (UUID w0 w1) = putWord64be w0 >> putWord64be w1
562+ get = liftM2 UUID getWord64be getWord64be
563+
564+
565+-- My goal with this instance was to make it work just enough to do what
566+-- I want when used with the HStringTemplate library.
567+instance Data UUID where
568+ toConstr uu = mkConstr uuidType (show uu) [] (error "fixity")
569+ gunfold _ _ = error "gunfold"
570+ dataTypeOf _ = uuidType
571+
572+uuidType :: DataType
573+uuidType = mkNoRepType "Data.UUID.Types.UUID"
574+
575+deriving instance Lift UUID
uuid-types/src/Data/UUID/Types/Internal/Builder.hsnew file+104
@@ -0,0 +1,104 @@
1+{-# LANGUAGE TypeFamilies #-}
2+{-# LANGUAGE Unsafe #-}
3+
4+{-# OPTIONS_HADDOCK hide #-}
5+
6+-- | Module : Data.UUID.Types.Internal.Builder
7+-- Copyright : (c) 2009 Mark Lentczner
8+--
9+-- License : BSD-style
10+--
11+-- Maintainer : markl@glyphic.com
12+-- Stability : experimental
13+-- Portability : portable
14+--
15+-- This module provides a system that can call a function that takes
16+-- a sequence of some number of Word8 arguments.
17+--
18+-- The twist is that the Word8 arguments can be supplied directly
19+-- from Word8s, or from other sources that may provide more than
20+-- one Word8 apiece. Examples are Word16 and Word32 that supply
21+-- two and four Word8s respectively. Other ByteSource instances
22+-- can be defined.
23+--
24+-- This module is admittedly overkill. There are only three places
25+-- in the uuid package that need to call buildFromBytes with 16
26+-- Word8 values, but each place uses Words of different lengths:
27+-- version 1 uuids: 32-16-16-16-8-8-8-8-8-8
28+-- version 4 uuids: 24-24-32-24-24
29+-- version 5 uuids: 32-32-32-32
30+-- Originally, these three constructions were hand coded but the
31+-- code was ungainly. Using this module makes the code very
32+-- concise, and turns out to optimize to just as fast, or faster!
33+
34+module Data.UUID.Types.Internal.Builder
35+ (ByteSource(..)
36+ ,ByteSink
37+ ,Takes1Byte
38+ ,Takes2Bytes
39+ ,Takes3Bytes
40+ ,Takes4Bytes
41+ ) where
42+
43+import Data.Bits
44+import Data.Word
45+
46+
47+
48+type Takes1Byte g = Word8 -> g
49+type Takes2Bytes g = Word8 -> Word8 -> g
50+type Takes3Bytes g = Word8 -> Word8 -> Word8 -> g
51+type Takes4Bytes g = Word8 -> Word8 -> Word8 -> Word8 -> g
52+type Takes8Bytes g = Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> g
53+
54+-- | Type of function that a given ByteSource needs.
55+-- This function must take as many Word8 arguments as the ByteSource provides
56+type family ByteSink w g
57+type instance ByteSink Word8 g = Takes1Byte g
58+type instance ByteSink Word16 g = Takes2Bytes g
59+type instance ByteSink Word32 g = Takes4Bytes g
60+type instance ByteSink Word64 g = Takes8Bytes g
61+type instance ByteSink Int g = Takes4Bytes g
62+
63+
64+-- | Class of types that can add Word8s to a Builder.
65+-- Instances for Word8, Word16, Word32 and Int provide 1, 2, 4 and 4 bytes,
66+-- respectively, into a ByteSink
67+class ByteSource w where
68+ -- | Apply the source's bytes to the sink
69+ (/-/) :: ByteSink w g -> w -> g
70+
71+infixl 6 /-/
72+
73+instance ByteSource Word8 where
74+ f /-/ w = f w
75+
76+instance ByteSource Word16 where
77+ f /-/ w = f b1 b2
78+ where b1 = fromIntegral (w `shiftR` 8)
79+ b2 = fromIntegral w
80+
81+instance ByteSource Word32 where
82+ f /-/ w = f b1 b2 b3 b4
83+ where b1 = fromIntegral (w `shiftR` 24)
84+ b2 = fromIntegral (w `shiftR` 16)
85+ b3 = fromIntegral (w `shiftR` 8)
86+ b4 = fromIntegral w
87+
88+instance ByteSource Word64 where
89+ f /-/ w = f b1 b2 b3 b4 b5 b6 b7 b8
90+ where b1 = fromIntegral (w `shiftR` 56)
91+ b2 = fromIntegral (w `shiftR` 48)
92+ b3 = fromIntegral (w `shiftR` 40)
93+ b4 = fromIntegral (w `shiftR` 32)
94+ b5 = fromIntegral (w `shiftR` 24)
95+ b6 = fromIntegral (w `shiftR` 16)
96+ b7 = fromIntegral (w `shiftR` 8)
97+ b8 = fromIntegral w
98+
99+instance ByteSource Int where
100+ f /-/ w = f b1 b2 b3 b4
101+ where b1 = fromIntegral (w `shiftR` 24)
102+ b2 = fromIntegral (w `shiftR` 16)
103+ b3 = fromIntegral (w `shiftR` 8)
104+ b4 = fromIntegral w
uuid-types/tests/TestUUID.hsnew file+209
@@ -0,0 +1,209 @@
1+{-# LANGUAGE ViewPatterns #-}
2+{-# LANGUAGE TemplateHaskell #-}
3+
4+{-# OPTIONS_GHC -fno-warn-orphans #-}
5+
6+import Data.Binary (encode)
7+import qualified Data.ByteString.Char8 as BC8
8+import qualified Data.ByteString.Lazy as BL
9+import qualified Data.ByteString.Lazy.Char8 as BL8
10+import Data.Char (ord)
11+import Data.Functor ((<$>))
12+import qualified Data.UUID.Types as U
13+import Data.Word
14+import Foreign (alloca, castPtr, peek, poke,
15+ sizeOf)
16+import GHC.ByteOrder (ByteOrder(..), targetByteOrder)
17+import System.IO.Unsafe (unsafePerformIO)
18+
19+import Test.QuickCheck (Arbitrary (arbitrary), choose)
20+
21+import Test.Tasty (TestTree, defaultMain, testGroup)
22+import Test.Tasty.HUnit (assertBool, testCase, (@=?), (@?=))
23+import Test.Tasty.QuickCheck (testProperty)
24+
25+
26+-- orphan
27+instance Arbitrary U.UUID where
28+ -- the UUID random instance ignores bounds
29+ arbitrary = choose (U.nil, U.nil)
30+
31+type Test = TestTree
32+
33+test_null :: Test
34+test_null =
35+ testCase "nil is null" $
36+ assertBool "" (U.null U.nil)
37+
38+test_nil :: Test
39+test_nil = testGroup "nil" [
40+ testCase "nil string" $ U.toString U.nil @?= "00000000-0000-0000-0000-000000000000",
41+ testCase "nil bytes" $ U.toByteString U.nil @?= BL.pack (replicate 16 0)
42+ ]
43+
44+test_lift :: Test
45+test_lift = testCase "TH.Lift" $ do
46+ let uuid = U.fromWords64 123456789 987654321
47+ uuid @?= $( [| uuid |] )
48+
49+test_conv :: Test
50+test_conv = testGroup "conversions" [
51+ testCase "conv bytes to string" $
52+ maybe "" (U.toString) (U.fromByteString b16) @?= s16,
53+ testCase "conv string to bytes" $
54+ maybe BL.empty (U.toByteString) (U.fromString s16) @?= b16
55+ ]
56+ where b16 = BL.pack [1..16]
57+ s16 = "01020304-0506-0708-090a-0b0c0d0e0f10"
58+
59+-- | Test fromByteString with a fixed-input.
60+test_fromByteString :: Test
61+test_fromByteString =
62+ testCase "UUID fromByteString" $
63+ Just inputUUID @=?
64+ U.fromByteString (BL8.pack "\xa5\xca\x85\x66\xd9\xc5\x48\x35\x99\xc8\xe1\xf1\x3e\x73\xb5\xe2")
65+
66+-- | Test fromWords with a fixed-input
67+test_fromWords :: Test
68+test_fromWords =
69+ testCase "UUID fromWords" $
70+ inputUUID @=? U.fromWords 0xa5ca8566 0xd9c54835 0x99c8e1f1 0x3e73b5e2
71+
72+
73+test_Storeable :: Test
74+test_Storeable =
75+ testCase "UUID Storeable(poke)" $
76+ case targetByteOrder of
77+ LittleEndian -> BC8.pack "\x66\x85\xca\xa5\xc5\xd9\x35\x48\x99\xc8\xe1\xf1\x3e\x73\xb5\xe2" @=? pokeAsBS inputUUID
78+ BigEndian -> BC8.pack "\xa5\xca\x85\x66\xd9\xc5\x48\x35\x99\xc8\xe1\xf1\x3e\x73\xb5\xe2" @=? pokeAsBS inputUUID
79+ where
80+ pokeAsBS :: U.UUID -> BC8.ByteString
81+ pokeAsBS uuid = unsafePerformIO $ do
82+ alloca $ \ptr -> do
83+ poke ptr uuid
84+ BC8.packCStringLen (castPtr ptr, sizeOf uuid)
85+
86+test_Binary :: Test
87+test_Binary =
88+ testCase "UUID Binary(encode)" $
89+ (BL8.pack "\xa5\xca\x85\x66\xd9\xc5\x48\x35\x99\xc8\xe1\xf1\x3e\x73\xb5\xe2") @=? encode inputUUID
90+
91+inputUUID :: U.UUID
92+inputUUID = read "a5ca8566-d9c5-4835-99c8-e1f13e73b5e2"
93+
94+prop_stringRoundTrip :: Test
95+prop_stringRoundTrip = testProperty "String round trip" stringRoundTrip
96+ where stringRoundTrip :: U.UUID -> Bool
97+ stringRoundTrip u = maybe False (== u) $ U.fromString (U.toString u)
98+
99+prop_byteStringRoundTrip :: Test
100+prop_byteStringRoundTrip = testProperty "ByteString round trip" byteStringRoundTrip
101+ where byteStringRoundTrip :: U.UUID -> Bool
102+ byteStringRoundTrip u = maybe False (== u)
103+ $ U.fromByteString (U.toByteString u)
104+
105+prop_stringLength :: Test
106+prop_stringLength = testProperty "String length" stringLength
107+ where stringLength :: U.UUID -> Bool
108+ stringLength u = length (U.toString u) == 36
109+
110+prop_byteStringLength :: Test
111+prop_byteStringLength = testProperty "ByteString length" byteStringLength
112+ where byteStringLength :: U.UUID -> Bool
113+ byteStringLength u = BL.length (U.toByteString u) == 16
114+
115+prop_randomsDiffer :: Test
116+prop_randomsDiffer = testProperty "Randoms differ" randomsDiffer
117+ where randomsDiffer :: (U.UUID, U.UUID) -> Bool
118+ randomsDiffer (u1, u2) = u1 /= u2
119+
120+prop_randomNotNull :: Test
121+prop_randomNotNull = testProperty "Random not null" randomNotNull
122+ where randomNotNull :: U.UUID -> Bool
123+ randomNotNull = not. U.null
124+
125+prop_readShowRoundTrip :: Test
126+prop_readShowRoundTrip = testProperty "Read/Show round-trip" prop
127+ where -- we're using 'Maybe UUID' to add a bit of
128+ -- real-world complexity.
129+ prop :: U.UUID -> Bool
130+ prop uuid = read (show (Just uuid)) == Just uuid
131+
132+-- Mostly going to test for wrong UUIDs
133+fromASCIIBytes_fromString1 :: String -> Bool
134+fromASCIIBytes_fromString1 s =
135+ if all (\c -> ord c < 256) s
136+ then U.fromString s == U.fromASCIIBytes (BC8.pack s)
137+ else True
138+
139+fromASCIIBytes_fromString2 :: U.UUID -> Bool
140+fromASCIIBytes_fromString2 (U.toString -> s) =
141+ U.fromString s == U.fromASCIIBytes (BC8.pack s)
142+
143+toASCIIBytes_toString :: U.UUID -> Bool
144+toASCIIBytes_toString uuid =
145+ U.toString uuid == BC8.unpack (U.toASCIIBytes uuid)
146+
147+fromASCIIBytes_toASCIIBytes :: U.UUID -> Bool
148+fromASCIIBytes_toASCIIBytes (BC8.pack . U.toString -> bs) =
149+ Just bs == (U.toASCIIBytes <$> U.fromASCIIBytes bs)
150+
151+toASCIIBytes_fromASCIIBytes :: U.UUID -> Bool
152+toASCIIBytes_fromASCIIBytes uuid =
153+ Just uuid == U.fromASCIIBytes (U.toASCIIBytes uuid)
154+
155+toWords_fromWords :: U.UUID -> Bool
156+toWords_fromWords uuid =
157+ uuid == myUncurry4 U.fromWords (U.toWords uuid)
158+
159+fromWords_toWords :: (Word32, Word32, Word32, Word32) -> Bool
160+fromWords_toWords wds =
161+ wds == U.toWords (myUncurry4 U.fromWords wds)
162+
163+myUncurry4 :: (x1 -> x2 -> x3 -> x4 -> y) -> (x1, x2, x3, x4) -> y
164+myUncurry4 f (a,b,c,d) = f a b c d
165+
166+prop_storableRoundTrip :: Test
167+prop_storableRoundTrip =
168+ testProperty "Storeable round-trip" $ unsafePerformIO . prop
169+ where
170+ prop :: U.UUID -> IO Bool
171+ prop uuid =
172+ alloca $ \ptr -> do
173+ poke ptr uuid
174+ uuid2 <- peek ptr
175+ return $ uuid == uuid2
176+
177+main :: IO ()
178+main = do
179+ defaultMain $
180+ testGroup "tests" $
181+ concat $
182+ [ [
183+ test_null,
184+ test_nil,
185+ test_lift,
186+ test_conv,
187+ test_fromByteString,
188+ test_fromWords,
189+ test_Storeable,
190+ test_Binary
191+ ]
192+ , [ prop_stringRoundTrip,
193+ prop_readShowRoundTrip,
194+ prop_byteStringRoundTrip,
195+ prop_storableRoundTrip,
196+ prop_stringLength,
197+ prop_byteStringLength,
198+ prop_randomsDiffer,
199+ prop_randomNotNull
200+ ]
201+ , [ testProperty "fromASCIIBytes_fromString1" fromASCIIBytes_fromString1
202+ , testProperty "fromASCIIBytes_fromString2" fromASCIIBytes_fromString2
203+ , testProperty "fromASCIIBytes_toString" toASCIIBytes_toString
204+ , testProperty "fromASCIIBytes_toASCIIBytes" fromASCIIBytes_toASCIIBytes
205+ , testProperty "toASCIIBytes_fromASCIIBytes" toASCIIBytes_fromASCIIBytes
206+ , testProperty "toWords_fromWords" toWords_fromWords
207+ , testProperty "fromWords_toWords" fromWords_toWords
208+ ]
209+ ]
uuid-types/uuid-types.cabalnew file+99
@@ -0,0 +1,99 @@
1+cabal-version: 1.12
2+name: uuid-types
3+version: 1.0.6
4+x-revision: 2
5+copyright:
6+ (c) 2017-2018 Herbert Valerio Riedel
7+ (c) 2008-2014 Antoine Latter
8+
9+author: Antoine Latter
10+maintainer: Oleg Grenrus <oleg.grenrus@iki.fi>
11+license: BSD3
12+license-file: LICENSE
13+category: Data
14+build-type: Simple
15+tested-with:
16+ GHC ==8.6.5
17+ || ==8.8.4
18+ || ==8.10.7
19+ || ==9.0.2
20+ || ==9.2.8
21+ || ==9.4.8
22+ || ==9.6.6
23+ || ==9.8.4
24+ || ==9.10.1
25+ || ==9.12.1
26+
27+synopsis: Type definitions for Universally Unique Identifiers
28+description:
29+ This library contains type definitions for
30+ <https://en.wikipedia.org/wiki/UUID Universally Unique Identifiers (UUID)>
31+ (as specified in
32+ <http://tools.ietf.org/html/rfc4122 RFC 4122>)
33+ and basic conversion functions.
34+ .
35+ See also the <https://hackage.haskell.org/package/uuid 'uuid' package>
36+ providing a high-level API for managing the different UUID versions.
37+
38+homepage: https://github.com/haskell-hvr/uuid
39+bug-reports: https://github.com/haskell-hvr/uuid/issues
40+extra-source-files: ChangeLog.md
41+
42+source-repository head
43+ type: git
44+ location: https://github.com/haskell-hvr/uuid.git
45+ subdir: uuid-types
46+
47+library
48+ build-depends:
49+ base >=4.12.0.0 && <5
50+ , binary >=0.8.6.0 && <0.9
51+ , bytestring >=0.10.8.2 && <0.13
52+ , deepseq >=1.4.4.0 && <1.6
53+ , hashable >=1.4.4.0 && <1.6
54+ , random >=1.2.1.2 && <1.3
55+ , template-haskell >=2.14.0.0 && <2.24
56+ , text >=1.2.3.0 && <1.3 || >=2.0 && <2.2
57+
58+ exposed-modules: Data.UUID.Types
59+
60+ -- Exposed for companion projects; *NOT* part of the official API:
61+ exposed-modules:
62+ Data.UUID.Types.Internal
63+ Data.UUID.Types.Internal.Builder
64+
65+ default-language: Haskell2010
66+ other-extensions:
67+ DeriveDataTypeable
68+ TypeFamilies
69+
70+ ghc-options: -Wall
71+ hs-source-dirs: src
72+
73+test-suite testuuid
74+ type: exitcode-stdio-1.0
75+ main-is: TestUUID.hs
76+ hs-source-dirs: tests
77+ default-language: Haskell2010
78+ other-extensions: ViewPatterns
79+ ghc-options: -Wall
80+ if impl(ghc >= 8.10)
81+ ghc-options: -Wunused-packages
82+
83+ -- inherited constraints
84+ build-depends:
85+ base
86+ , binary
87+ , bytestring
88+ , template-haskell
89+ , uuid-types
90+
91+ -- deps w/o inherited constraints
92+ build-depends:
93+ QuickCheck >=2.14.2 && <2.16
94+ , tasty >=1.4.0.1 && <1.6
95+ , tasty-hunit >=0.10 && <0.11
96+ , tasty-quickcheck >=0.10 && <0.12
97+
98+ if !impl(ghc >=8.4)
99+ build-depends: ghc-byteorder >=4.11 && <4.12
uuid.cabaldeleted−40
@@ -1,40 +0,0 @@
1−Name: uuid
2−Version: 1.2.0
3−Copyright: (c) 2008-2009 Antoine Latter
4−Author: Antoine Latter
5−Maintainer: aslatter@gmail.com
6−License: BSD3
7−License-file: LICENSE
8−
9−Category: Data
10−Build-Type: Simple
11−Cabal-Version: >= 1.6
12−
13−Description:
14− This library is useful for creating, comparing, parsing and
15− printing Universally Unique Identifiers.
16− See <http://en.wikipedia.org/wiki/UUID> for the general idea.
17−
18−Synopsis: For creating, comparing, parsing and printing Universally Unique Identifiers
19−
20−Homepage: http://community.haskell.org/~aslatter/code/uuid/
21−Bug-Reports: mailto:aslatter@gmail.com
22−
23−Extra-Source-Files:
24− CHANGES
25− CONTRIBUTORS
26−
27−Library
28− Build-Depends: random, binary, bytestring, Crypto, maccatcher,
29− time, base >=3, base < 5
30−
31− Exposed-Modules:
32− Data.UUID
33− Data.UUID.V1
34− Data.UUID.V5
35−
36− Other-Modules:
37− Data.UUID.Internal
38−
39− Extensions: DeriveDataTypeable
40−
uuid/CHANGES.mdnew file+186
@@ -0,0 +1,186 @@
1+1.3.16
2+
3+- Support GHC-8.6.5...9.10.1
4+
5+1.3.15
6+
7+- Add (Template Haskell) `Lift UUID` instance
8+
9+1.3.14
10+
11+- Use more compact heap object representation which saves 16 bytes on 64bit platforms.
12+- Add `toWords64`/`fromWords64` functions
13+
14+1.3.13
15+
16+- Optimize `V4.nextRandom` (~3x speed increase)
17+- Optimize UUID V3 & V5 generation (~2x speed increase)
18+- Use `cryptohash-md5`/`cryptohash-sha1`/`entropy` instead
19+ of `memory`/`cryptonite` for better performance and stability,
20+ but GHCJS is now no longer supported.
21+- Update cabal-spec to version 1.10
22+
23+1.3.12
24+
25+- Update package dependencies
26+- Use `cryptonite` for crypto
27+- The function `V4.nextRandom` is now implemented with functions from
28+ `Crypto.Random` in package `cryptonite`. This does slow-down random
29+ UUID generation but provides for far greater randomness. The
30+ `Random` instance for `UUID` can be used to re-gain the old
31+ behavior.
32+
33+1.3.11
34+
35+- Add `toText`/`fromText`
36+
37+1.3.10
38+
39+- Update dependencies in tests and benchmarks.
40+
41+1.3.9
42+
43+- Split definition of UUID data type into separate Cabal package to
44+ enable 3rd party libraries to avoid some of the larger dependencies.
45+
46+1.3.8
47+
48+- Allow building against newer `deepseq`.
49+
50+1.3.7
51+
52+- Allow building against newer `time`.
53+
54+1.3.6
55+
56+- Move to GitHub.
57+
58+1.3.5
59+
60+- Allow building against newer `random`.
61+
62+1.3.4
63+
64+- Allow building against newer `QuickCheck`.
65+
66+1.3.3
67+
68+- More complex version constraints on `hashable`, to avoid building against
69+ versions less than 1.1.1.0 or equal to 1.2.0.*.
70+
71+1.3.2
72+
73+- Fix for building against `bytestring` 0.9.*
74+
75+1.3.1
76+
77+- Allow building against `hashable` 1.1.* in addition to 1.2.*
78+
79+1.3.0
80+
81+- New functions for parsing and printing UUIDs to and from ASCII BytesStrings
82+- New module `Data.UUID.Util`. This module includes the type `UnpackedUUID`,
83+ whose fields correspond to the UUID fields described in RFC 4122.
84+- The `Storable` instance now stores a UUID in host byte-order instead of
85+ big endian.
86+- There is now an instance for `Hashable UUID`.
87+
88+1.2.13
89+
90+Benchmark only changes:
91+
92+- Allow `criterion` 0.8.*
93+
94+1.2.12
95+
96+Test only changes:
97+
98+- Allow `QuickCheck` 2.6.*
99+
100+1.2.11
101+
102+- Allow `binary` 0.7.*
103+
104+1.2.10
105+
106+- Allow `cryptohash` version 0.9.*
107+- Cleanup tests
108+
109+1.2.9
110+
111+- Bumped dependency on `cryptohash`.
112+
113+1.2.8
114+
115+- Bumped various dependencies and cleaned up dependencies in general.
116+
117+1.2.7
118+
119+- Added stricter constraints on `random` package.
120+
121+1.2.6
122+
123+- Add module `V4` to direct attention to our Random instance
124+
125+- In module `V1` seed the generator with a random number
126+ if the hardware MAC address could not be discovered.
127+
128+- Fix and cleanup various haddocks.
129+
130+- In module docs, warn about MD5 use in Data.UUID.V3 and
131+ encourage the reader to use Data.UUID.V5 instead.
132+
133+1.2.5
134+
135+- Use `cryptohash` package for MD5 and SHA1 instead of `Crypto`
136+
137+1.2.4
138+
139+- Unpack Word32 values into UUID constructor.
140+
141+- Update test suite to QuickCheck 2
142+
143+- Bump other dependencies in tests/benchmarks
144+
145+1.2.3
146+
147+- The Read instance now drops leading spaces in the string to be parsed.
148+Thanks to Marc Ziegert for reporting this bug.
149+
150+- The tests have moved over to the new Cabal test running framework.
151+
152+1.2.2
153+
154+- Add functions fromWords/toWords
155+
156+The goal was to have a total function that can be used to construct
157+a UUID, primarily for use by uuid-th.
158+
159+1.2.1
160+
161+- Fix concurrency bug in Data.UUID.V1 (thanks to Neil Mitchell for reporting
162+and a test case)
163+
164+1.2.0
165+ (Contributors: Antoine Latter & Mark Lentczner)
166+
167+- added functions toByteString and fromByteString
168+- added `nil` UUID
169+- added unit tests and benchmarks, built when configured -ftest
170+- major speed up of to/from functions (as well as in general)
171+- added version-3 generation (deterministic based on MD5)
172+- major changes to internal representation
173+ - now uses four strict Word32 values
174+ - internal ByteSource classes for easy construction (see Builder.hs)
175+- Storable instance now stores in memory as system libraries in C do:
176+ 16 bytes derived from the network order of the fields, no matter what
177+ the host native endianess is.
178+- fixed bugs in V1 time and clock stepping, and V1 generated values
179+- builds cleanly under GHC's -Wall
180+- added CHANGES file
181+
182+1.1.1
183+
184+- no longer exporting `null` from the prelude
185+- add `null` predicate on UUIDs
186+- documentation fix (thanks Mark Lentczner)
Demo.hs → uuid/Demo.hsrenamed−1
@@ -13,4 +13,3 @@ main = sequence_ $ replicate count $ do
13 x <- newUUID
13 x <- newUUID
14 y <- newUUID
14 y <- newUUID
15 seq (x == y) $ return ()
15 seq (x == y) $ return ()
16−
uuid/LICENSEnew file+28
@@ -0,0 +1,28 @@
1+Copyright (c) 2008, Antoine Latter
2+
3+All rights reserved.
4+
5+Redistribution and use in source and binary forms, with or without
6+modification, are permitted provided that the following conditions are
7+met:
8+
9+ * Redistributions of source code must retain the above copyright
10+notice, this list of conditions and the following disclaimer.
11+ * Redistributions in binary form must reproduce the above copyright
12+notice, this list of conditions and the following disclaimer in the
13+documentation and/or other materials provided with the distribution.
14+ * The names of the authors may not be used to endorse or promote
15+products derived from this software without specific prior written
16+permission.
17+
18+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
tests/Setup.hs → uuid/Setup.hsrenamed

The content is the same.

uuid/src/Data/UUID.hsnew file+49
@@ -0,0 +1,49 @@
1+{- |
2+Module : Data.UUID
3+Copyright : (c) 2008,2012 Antoine Latter
4+
5+License : BSD-style
6+
7+Maintainer : aslatter@gmail.com
8+Stability : experimental
9+Portability : portable
10+
11+
12+This library is useful for comparing, parsing and
13+printing Universally Unique Identifiers.
14+See <http://en.wikipedia.org/wiki/UUID> for the general idea.
15+See <http://tools.ietf.org/html/rfc4122> for the specification.
16+
17+* Use 'Data.UUID.V4.nextRandom' to generate secure random UUIDs, and your
18+favorite instance of 'System.Random.Random' for faster but insecure
19+generation of UUIDs.
20+
21+* For name-based generation of UUIDs using SHA-1 hashing see
22+"Data.UUID.V5".
23+-}
24+module Data.UUID(UUID
25+ ,toString
26+ ,fromString
27+ ,toText
28+ ,fromText
29+ ,toASCIIBytes
30+ ,fromASCIIBytes
31+ ,toLazyASCIIBytes
32+ ,fromLazyASCIIBytes
33+ ,toByteString
34+ ,fromByteString
35+ ,toWords
36+ ,fromWords
37+ ,toWords64
38+ ,fromWords64
39+ ,null
40+ ,nil
41+ ) where
42+
43+import Prelude () -- we need to hide Prelude.null
44+import Data.UUID.Types
45+
46+-- We use explicit re-exports of everything from Data.UUID.Types in
47+-- preference to just re-exporting the whole module. This is to avoid
48+-- unforeseen transitive API breakage if the Data.UUID.Types module
49+-- should change.
uuid/src/Data/UUID/Named.hsnew file+72
@@ -0,0 +1,72 @@
1+-- |
2+-- Module : Data.UUID.Named
3+-- Copyright : (c) 2008 Antoine Latter
4+--
5+-- License : BSD-style
6+--
7+-- Maintainer : aslatter@gmail.com
8+-- Stability : experimental
9+-- Portability : portable
10+--
11+--
12+-- This module implements Version 3/5 UUIDs as specified
13+-- in RFC 4122.
14+--
15+-- These UUIDs identify an object within a namespace,
16+-- and are deterministic.
17+--
18+-- The namespace is identified by a UUID. Several sample
19+-- namespaces are enclosed.
20+
21+module Data.UUID.Named
22+ (generateNamed
23+ ,namespaceDNS
24+ ,namespaceURL
25+ ,namespaceOID
26+ ,namespaceX500
27+ ) where
28+
29+import Data.UUID.Types.Internal
30+
31+import Control.Applicative ((<*>),(<$>))
32+import Data.Binary.Get (runGet, getWord32be)
33+import Data.Maybe
34+import Data.Word (Word8)
35+
36+import qualified Data.ByteString as B
37+import qualified Data.ByteString.Lazy as BL
38+
39+-- |Generate a 'UUID' within the specified namespace out of the given
40+-- object.
41+generateNamed :: (B.ByteString -> B.ByteString) -- ^Hash
42+ -> Word8 -- ^Version
43+ -> UUID -- ^Namespace
44+ -> [Word8] -- ^Object
45+ -> UUID
46+generateNamed hash version namespace object =
47+ let chunk = B.pack $ toList namespace ++ object
48+ bytes = BL.fromChunks . (:[]) $ hash chunk
49+ w = getWord32be
50+ unpackBytes = runGet $
51+ buildFromWords version <$> w <*> w <*> w <*> w
52+ in unpackBytes bytes
53+
54+
55+unsafeFromString :: String -> UUID
56+unsafeFromString = fromJust . fromString
57+
58+-- |The namespace for DNS addresses
59+namespaceDNS :: UUID
60+namespaceDNS = unsafeFromString "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
61+
62+-- |The namespace for URLs
63+namespaceURL :: UUID
64+namespaceURL = unsafeFromString "6ba7b811-9dad-11d1-80b4-00c04fd430c8"
65+
66+-- |The namespace for ISO OIDs
67+namespaceOID :: UUID
68+namespaceOID = unsafeFromString "6ba7b812-9dad-11d1-80b4-00c04fd430c8"
69+
70+-- |The namespace for X.500 DNs
71+namespaceX500 :: UUID
72+namespaceX500 = unsafeFromString "6ba7b814-9dad-11d1-80b4-00c04fd430c8"
uuid/src/Data/UUID/Util.hsnew file+42
@@ -0,0 +1,42 @@
1+{-# LANGUAGE TypeFamilies #-}
2+module Data.UUID.Util (
3+ UnpackedUUID(..)
4+ , unpack, pack
5+ , version
6+ , extractTime
7+ , setTime
8+ ) where
9+
10+import Prelude hiding (null)
11+import Data.Word
12+import Data.Word.Util
13+import Data.Bits
14+import Data.UUID.Types.Internal
15+import Data.Int (Int64)
16+
17+version :: UUID -> Int
18+version uuid =
19+ fromEnum ((time_hi_and_version unpacked `shiftR` 12) .&. 0xF)
20+ where
21+ unpacked = unpack uuid
22+
23+-- Note UUID time is in 10^-7 seconds.
24+setTime :: (Integral a, Bits a) => UUID -> a -> Maybe UUID
25+setTime uuid t =
26+ if version uuid == 1
27+ then Just $ pack $ (unpack uuid){time_low = new_low_bits, time_mid = new_mid_bits, time_hi_and_version = new_hi_and_version_bits}
28+ else Nothing
29+ where new_low_bits = fromIntegral $ t .&. 0xFFFFFFFF
30+ new_mid_bits = fromIntegral $ (t `shiftR` 32) .&. 0xFFFF
31+ new_hi_and_version_bits = fromIntegral $ 0x1000 .|. ((t `shiftR` 48) .&. 0x0FFF)
32+
33+extractTime :: UUID -> Maybe Int64
34+extractTime uuid =
35+ if version uuid == 1
36+ then Just $ fromIntegral $ w32to64 (w16to32 (timeAndVersionToTime $ time_hi_and_version unpacked) $ time_mid unpacked) (time_low unpacked)
37+ else Nothing
38+ where
39+ unpacked = unpack uuid
40+
41+timeAndVersionToTime :: Word16 -> Word16
42+timeAndVersionToTime tv = tv .&. 0x0FFF
uuid/src/Data/UUID/V3.hsnew file+49
@@ -0,0 +1,49 @@
1+{- |
2+Module : Data.UUID.V3
3+Copyright : (c) 2010,2012 Antoine Latter
4+
5+License : BSD-style
6+
7+Maintainer : aslatter@gmail.com
8+Stability : experimental
9+Portability : portable
10+
11+NOTE\: This module uses MD5 hashing. Unless you know
12+you need to use this module, you should probably be
13+using "Data.UUID.V5", which offers the same sort of
14+functionality as this module except implemented with
15+SHA-1 hashing.
16+
17+This module implements Version 3 UUIDs as specified
18+in RFC 4122.
19+
20+These UUIDs identify an object within a namespace,
21+and are deterministic.
22+
23+The namespace is identified by a UUID. Several sample
24+namespaces are enclosed.
25+-}
26+module Data.UUID.V3
27+ (generateNamed
28+ ,Shared.namespaceDNS
29+ ,Shared.namespaceURL
30+ ,Shared.namespaceOID
31+ ,Shared.namespaceX500
32+ ) where
33+
34+import Data.Word
35+
36+import Data.UUID.Types.Internal
37+import qualified Data.UUID.Named as Shared
38+import qualified Crypto.Hash.MD5 as MD5
39+
40+
41+-- |Generate a 'UUID' within the specified namespace out of the given
42+-- object.
43+--
44+-- Uses an MD5 hash. The UUID is built from first 128 bits of the hash of
45+-- the namespace UUID and the name (as a series of Word8).
46+generateNamed :: UUID -- ^Namespace
47+ -> [Word8] -- ^Object
48+ -> UUID
49+generateNamed = Shared.generateNamed MD5.hash 3
uuid/src/Data/UUID/V4.hsnew file+33
@@ -0,0 +1,33 @@
1+{- |
2+ Module : Data.UUID.V4
3+ Copyright : (c) 2012-2016 Antoine Latter
4+
5+ License : BSD-style
6+
7+ Maintainer : aslatter@gmail.com
8+ Stability : experimental
9+ Portability : portable
10+
11+ This module implements Version 4 UUIDs as specified
12+ in RFC 4122.
13+
14+ These UUIDs are generated from a pseudo-random generator.
15+ We use the 'getEntropy' method from the <https://hackage.haskell.org/package/entropy entropy> package,
16+ which should provide cryptographically secure random data.
17+-}
18+module Data.UUID.V4 (nextRandom) where
19+
20+import Data.UUID
21+import Data.UUID.Types.Internal ( buildFromBytes )
22+
23+import System.Entropy ( getEntropy )
24+import Data.ByteString ( unpack )
25+
26+-- | Generate a crytographically secure, random UUID.
27+--
28+-- @since 1.2.6
29+nextRandom :: IO UUID
30+nextRandom = do
31+ [b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf]
32+ <- unpack `fmap` getEntropy 16
33+ return $ buildFromBytes 4 b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf
uuid/src/Data/UUID/V5.hsnew file+44
@@ -0,0 +1,44 @@
1+-- |
2+-- Module : Data.UUID.V5
3+-- Copyright : (c) 2008-2009 Antoine Latter
4+--
5+-- License : BSD-style
6+--
7+-- Maintainer : aslatter@gmail.com
8+-- Stability : experimental
9+-- Portability : portable
10+--
11+--
12+-- This module implements Version 5 UUIDs as specified
13+-- in RFC 4122.
14+--
15+-- These UUIDs identify an object within a namespace,
16+-- and are deterministic.
17+--
18+-- The namespace is identified by a UUID. Several sample
19+-- namespaces are enclosed.
20+
21+module Data.UUID.V5
22+ (generateNamed
23+ ,Shared.namespaceDNS
24+ ,Shared.namespaceURL
25+ ,Shared.namespaceOID
26+ ,Shared.namespaceX500
27+ ) where
28+
29+import Data.Word
30+
31+import Data.UUID.Types.Internal
32+import qualified Data.UUID.Named as Shared
33+import qualified Crypto.Hash.SHA1 as SHA1
34+
35+
36+-- |Generate a 'UUID' within the specified namespace out of the given
37+-- object.
38+--
39+-- Uses a SHA1 hash. The UUID is built from first 128 bits of the hash of
40+-- the namespace UUID and the name (as a series of Word8).
41+generateNamed :: UUID -- ^Namespace
42+ -> [Word8] -- ^Object
43+ -> UUID
44+generateNamed = Shared.generateNamed SHA1.hash 5
uuid/src/Data/Word/Util.hsnew file+20
@@ -0,0 +1,20 @@
1+
2+-- | Internal utilites
3+module Data.Word.Util where
4+
5+import Data.Bits
6+import Data.Word
7+
8+w16to32 :: Word16 -> Word16 -> Word32
9+w16to32 w0s w1s =
10+ (w0 `shiftL` 16) .|. w1
11+ where
12+ w0 = fromIntegral w0s
13+ w1 = fromIntegral w1s
14+
15+w32to64 :: Word32 -> Word32 -> Word64
16+w32to64 w0s w1s =
17+ (w0 `shiftL` 32) .|. w1
18+ where
19+ w0 = fromIntegral w0s
20+ w1 = fromIntegral w1s
uuid/tests/TestUUID.hsnew file+96
@@ -0,0 +1,96 @@
1+{-# LANGUAGE ViewPatterns #-}
2+
3+import Data.Bits
4+import qualified Data.ByteString.Lazy as BL
5+import Data.Char (ord)
6+import Data.Maybe
7+import Data.Word
8+import qualified Data.UUID as U
9+import qualified Data.UUID.V3 as U3
10+import qualified Data.UUID.V5 as U5
11+
12+import Test.QuickCheck ( Arbitrary(arbitrary) )
13+import Test.Tasty ( TestTree, testGroup, defaultMain )
14+import Test.Tasty.HUnit
15+ ( assertBool, (@?=), testCase )
16+import Test.Tasty.QuickCheck ( testProperty )
17+
18+type Test = TestTree
19+
20+isValidVersion :: Int -> U.UUID -> Bool
21+isValidVersion v u = lenOK && variantOK && versionOK
22+ where bs = U.toByteString u
23+ lenOK = BL.length bs == 16
24+ variantOK = BL.index bs 8 .&. 0xc0 == 0x80
25+ versionOK = BL.index bs 6 .&. 0xf0 == fromIntegral (v `shiftL` 4)
26+
27+
28+instance Arbitrary U.UUID where
29+ -- the UUID random instance ignores bounds
30+ arbitrary = pure U.nil
31+
32+
33+test_null :: Test
34+test_null =
35+ testCase "namespaceDNS is not null" $
36+ assertBool "" (not $ U.null U3.namespaceDNS)
37+
38+test_v3 :: Test
39+test_v3 =
40+ testCase "V3 computation" $
41+ U3.generateNamed U3.namespaceDNS name @?= uV3
42+
43+ where name = map (fromIntegral . ord) "www.widgets.com" :: [Word8]
44+ uV3 = fromJust $ U.fromString "3d813cbb-47fb-32ba-91df-831e1593ac29"
45+
46+test_v5 :: Test
47+test_v5 =
48+ testCase "V5 computation" $
49+ U5.generateNamed U5.namespaceDNS name @?= uV5
50+
51+ where name = map (fromIntegral . ord) "www.widgets.com" :: [Word8]
52+ uV5 = fromJust $ U.fromString "21f7f8de-8051-5b89-8680-0195ef798b6a"
53+
54+
55+prop_randomsValid :: Test
56+prop_randomsValid = testProperty "Random valid" randomsValid
57+ where randomsValid :: U.UUID -> Bool
58+ randomsValid = isValidVersion 4
59+
60+prop_v3NotNull :: Test
61+prop_v3NotNull = testProperty "V3 not null" v3NotNull
62+ where v3NotNull :: [Word8] -> Bool
63+ v3NotNull = not . U.null . U3.generateNamed U3.namespaceDNS
64+
65+prop_v3Valid :: Test
66+prop_v3Valid = testProperty "V3 valid" v3Valid
67+ where v3Valid :: [Word8] -> Bool
68+ v3Valid = isValidVersion 3 . U3.generateNamed U3.namespaceDNS
69+
70+prop_v5NotNull :: Test
71+prop_v5NotNull = testProperty "V5 not null" v5NotNull
72+ where v5NotNull :: [Word8] -> Bool
73+ v5NotNull = not . U.null . U5.generateNamed U5.namespaceDNS
74+
75+prop_v5Valid :: Test
76+prop_v5Valid = testProperty "V5 valid" v5Valid
77+ where v5Valid :: [Word8] -> Bool
78+ v5Valid = isValidVersion 5 . U5.generateNamed U5.namespaceDNS
79+
80+main :: IO ()
81+main = do
82+ defaultMain $
83+ testGroup "tests" $
84+ concat $
85+ [ [
86+ test_null,
87+ test_v3,
88+ test_v5
89+ ]
90+ , [ prop_randomsValid,
91+ prop_v3NotNull,
92+ prop_v3Valid,
93+ prop_v5NotNull,
94+ prop_v5Valid
95+ ]
96+ ]
uuid/uuid.cabalnew file+95
@@ -0,0 +1,95 @@
1+cabal-version: 1.12
2+name: uuid
3+version: 1.3.16
4+x-revision: 2
5+copyright: (c) 2008-2014 Antoine Latter
6+author: Antoine Latter
7+maintainer: Oleg Grenrus <oleg.grenrus@iki.fi>
8+license: BSD3
9+license-file: LICENSE
10+category: Data
11+build-type: Simple
12+tested-with:
13+ GHC ==8.6.5
14+ || ==8.8.4
15+ || ==8.10.7
16+ || ==9.0.2
17+ || ==9.2.8
18+ || ==9.4.8
19+ || ==9.6.6
20+ || ==9.8.4
21+ || ==9.10.1
22+ || ==9.12.1
23+
24+synopsis:
25+ For creating, comparing, parsing and printing Universally Unique Identifiers
26+
27+description:
28+ This library is useful for creating, comparing, parsing and
29+ printing Universally Unique Identifiers.
30+ .
31+ See <http://en.wikipedia.org/wiki/UUID> for the general idea.
32+
33+homepage: https://github.com/haskell-hvr/uuid
34+bug-reports: https://github.com/haskell-hvr/uuid/issues
35+extra-source-files: CHANGES.md
36+
37+source-repository head
38+ type: git
39+ location: https://github.com/haskell-hvr/uuid.git
40+ subdir: uuid
41+
42+library
43+ build-depends:
44+ base >=4.12 && <5
45+ , binary >=0.8.6.0 && <0.9
46+ , bytestring >=0.10.8.2 && <0.13
47+ , cryptohash-md5 >=0.11.100 && <0.12
48+ , cryptohash-sha1 >=0.11.100 && <0.12
49+ , entropy >=0.3.7 && <0.5
50+
51+ -- strict dependency on uuid-types,
52+ -- as we re-rexport datatype, thus leak instances etc.
53+ build-depends: uuid-types >=1.0.6 && <1.0.7
54+ exposed-modules:
55+ Data.UUID
56+ Data.UUID.Util
57+ Data.UUID.V3
58+ Data.UUID.V4
59+ Data.UUID.V5
60+
61+ other-modules:
62+ Data.UUID.Named
63+ Data.Word.Util
64+
65+ default-language: Haskell2010
66+ default-extensions: DeriveDataTypeable
67+ other-extensions: TypeFamilies
68+ ghc-options: -Wall
69+ if impl(ghc >= 8.10)
70+ ghc-options: -Wunused-packages
71+ hs-source-dirs: src
72+
73+test-suite testuuid
74+ type: exitcode-stdio-1.0
75+ main-is: TestUUID.hs
76+ hs-source-dirs: tests
77+ default-language: Haskell2010
78+ default-extensions: DeriveDataTypeable
79+ other-extensions: ViewPatterns
80+ ghc-options: -Wall -fno-warn-orphans
81+ if impl(ghc >= 8.10)
82+ ghc-options: -Wunused-packages
83+
84+ -- inherited constraints
85+ build-depends:
86+ base
87+ , bytestring
88+ , uuid
89+
90+ -- deps w/o inherited constraints
91+ build-depends:
92+ QuickCheck >=2.14.2 && <2.16
93+ , tasty >=1.4.0.1 && <1.6
94+ , tasty-hunit >=0.10 && <0.11
95+ , tasty-quickcheck >=0.10 && <0.12