on master help sign in
47 files changed+2421−875
since splitsnapshots
unifiedsplit
.git-blame-ignore-revs+2 .github/workflows/haskell-ci-bench.yml+241 .github/workflows/haskell-ci.yml+262 .gitignore+13 CHANGES−54 CONTRIBUTORS+7 Data/UUID.hs−36 Data/UUID/Internal.hs−316 Data/UUID/V1.hs−106 Data/UUID/V3.hs−45 Policy.md+11 README.md+12 cabal.bench.project+4 cabal.haskell-ci+7 cabal.project+15 gen-ci.sh+5 tests/TestUUID.hs−168 tests/summarize-bench-results.pl−14 LICENSE → uuid-bench/LICENSE uuid-bench/bench/uuid-benchmark.hs+33 tests/BenchUUID.hs → uuid-bench/bench/uuid-types-benchmark.hs+66−58 uuid-bench/src-uuid+1 uuid-bench/src-uuid-types+1 uuid-bench/uuid-bench.cabal+126 uuid-types/ChangeLog.md+31 uuid-types/LICENSE+28 Setup.hs → uuid-types/Setup.hs uuid-types/cabal.project+1 uuid-types/src/Data/UUID/Types.hs+47 uuid-types/src/Data/UUID/Types/Internal.hs+575 Data/UUID/Builder.hs → uuid-types/src/Data/UUID/Types/Internal/Builder.hs+21−5 uuid-types/tests/TestUUID.hs+209 uuid-types/uuid-types.cabal+99 uuid.cabal−69 uuid/CHANGES.md+186 Demo.hs → uuid/Demo.hs−1 uuid/LICENSE+28 uuid/Setup.hs+4 uuid/src/Data/UUID.hs+49 Data/UUID/Named.hs → uuid/src/Data/UUID/Named.hs+1−1 uuid/src/Data/UUID/Util.hs+42 uuid/src/Data/UUID/V3.hs+49 uuid/src/Data/UUID/V4.hs+33 Data/UUID/V5.hs → uuid/src/Data/UUID/V5.hs+1−2 uuid/src/Data/Word/Util.hs+20 uuid/tests/TestUUID.hs+96 uuid/uuid.cabal+95
.git-blame-ignore-revsnew file+2
@@ -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−54
@@ -1,54 +0,0 @@
1−1.2.5
2−
3−- Use 'cryptohash' package for MD5 and SHA1 instead of 'Crypto'
4−
5−1.2.4
6−
7−- Unpack Word32 values into UUID constructor.
8−
9−- Update test suite to QuickCheck 2
10−
11−- Bump other dependencies in tests/benchmarks
12−
13−1.2.3
14−
15−- The Read instance now drops leading spaces in the string to be parsed.
16−Thanks to Marc Ziegert for reporting this bug.
17−
18−- The tests have moved over to the new Cabal test running framework.
19−
20−1.2.2
21−
22−- Add functions fromWords/toWords
23−
24−The goal was to have a total function that can be used to construct
25−a UUID, primarily for use by uuid-th.
26−
27−1.2.1
28−
29−- Fix concurrency bug in Data.UUID.V1 (thanks to Neil Mitchell for reporting
30−and a test case)
31−
32−1.2.0
33− (Contributors: Antoine Latter & Mark Lentczner)
34−
35−- added functions toByteString and fromByteString
36−- added 'nil' UUID
37−- added unit tests and benchmarks, built when configured -ftest
38−- major speed up of to/from functions (as well as in general)
39−- added version-3 generation (deterministic based on MD5)
40−- major changes to internal representation
41− - now uses four strict Word32 values
42− - internal ByteSource classes for easy construction (see Builder.hs)
43−- Storable instance now stores in memory as system libraries in C do:
44− 16 bytes derived from the network order of the fields, no matter what
45− the host native endianess is.
46−- fixed bugs in V1 time and clock stepping, and V1 generated values
47−- builds cleanly under GHC's -Wall
48−- added CHANGES file
49−
50−1.1.1
51−
52−- no longer exporting 'null' from the prelude
53−- add 'null' predicate on UUIDs
54−- documentation fix (thanks Mark Lentczner)
CONTRIBUTORS+7
@@ -6,3 +6,10 @@ Tim Newsham
66Mark Lentczner
77Neil Mitchell
88Bas 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−36
@@ -1,36 +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− ,toWords
26− ,fromWords
27− ,null
28− ,nil
29− ) where
30−
31−import Prelude () -- we need to hide Prelude.null
32−import Data.UUID.Internal
33−
34−-- Everything is really implemented in Data.UUID.Internal,
35−-- but I don't want to export the constructors out of the
36−-- package.
Data/UUID/Internal.hsdeleted−316
@@ -1,316 +0,0 @@
1−{-# LANGUAGE DeriveDataTypeable, TypeFamilies, CPP #-}
2−
3−-- |
4−-- Module : Data.UUID
5−-- Copyright : (c) 2008-2009, 2012 Antoine Latter
6−-- (c) 2009 Mark Lentczner
7−--
8−-- License : BSD-style
9−--
10−-- Maintainer : aslatter@gmail.com
11−-- Stability : experimental
12−-- Portability : portable
13−
14−module Data.UUID.Internal
15− (UUID(..)
16− ,null
17− ,nil
18− ,fromByteString
19− ,toByteString
20− ,fromString
21− ,toString
22− ,fromWords
23− ,toWords
24− ,toList
25− ,buildFromBytes
26− ,buildFromWords
27− ) where
28−
29−import Prelude hiding (null)
30−
31−import Control.Monad (liftM4)
32−import Data.Char
33−import Data.Maybe
34−import Data.Bits
35−import Data.List (elemIndices)
36−
37−#if MIN_VERSION_base(4,0,0)
38−import Data.Data
39−#else
40−import Data.Generics.Basics
41−#endif
42−
43−import Foreign.Storable
44−
45−import Data.Binary
46−import Data.Binary.Put
47−import Data.Binary.Get
48−import qualified Data.ByteString.Lazy as Lazy
49−
50−import Data.UUID.Builder
51−
52−import System.Random
53−
54−
55−-- |The UUID type. A 'Random' instance is provided which produces
56−-- version 4 UUIDs as specified in RFC 4122. The 'Storable' and
57−-- 'Binary' instances are compatible with RFC 4122, storing the fields
58−-- in network order as 16 bytes.
59−data UUID
60− = UUID
61− {-# UNPACK #-} !Word32
62− {-# UNPACK #-} !Word32
63− {-# UNPACK #-} !Word32
64− {-# UNPACK #-} !Word32
65− deriving (Eq, Ord, Typeable)
66−{-
67− Other representations that we tried are:
68− Mimic V1 structure: !Word32 !Word16 !Word16 !Word16
69− !Word8 !Word8 !Word8 !Word8 !Word8 !Word8
70− Sixteen bytes: !Word8 ... (x 16)
71− Simple list of bytes: [Word8]
72− ByteString (strict) ByteString
73− Immutable array: UArray Int Word8
74− Vector: UArr Word8
75− None was as fast, overall, as the representation used here.
76−-}
77−
78−-- | Covert a 'UUID' into a sequence of 'Word32' values.
79−-- Usefull for when you need to serialize a UUID and
80−-- neither 'Storable' nor 'Binary' are appropriate.
81−toWords :: UUID -> (Word32, Word32, Word32, Word32)
82−toWords (UUID w1 w2 w3 w4) = (w1, w2, w3, w4)
83−
84−-- | Create a 'UUID' from a sequence of 'Word32'. The
85−-- opposite of 'toWords'.
86−fromWords :: Word32 -> Word32 -> Word32 -> Word32 -> UUID
87−fromWords = UUID
88−
89−--
90−-- UTILITIES
91−--
92−
93−-- |Build a Word32 from four Word8 values, presented in big-endian order
94−word :: Word8 -> Word8 -> Word8 -> Word8 -> Word32
95−word a b c d = (fromIntegral a `shiftL` 24)
96− .|. (fromIntegral b `shiftL` 16)
97− .|. (fromIntegral c `shiftL` 8)
98− .|. (fromIntegral d )
99−
100−-- |Extract a Word8 from a Word32. Bytes, high to low, are numbered from 3 to 0,
101−byte :: Int -> Word32 -> Word8
102−byte i w = fromIntegral (w `shiftR` (i * 8))
103−
104−
105−-- |Make a UUID from sixteen Word8 values
106−makeFromBytes :: Word8 -> Word8 -> Word8 -> Word8
107− -> Word8 -> Word8 -> Word8 -> Word8
108− -> Word8 -> Word8 -> Word8 -> Word8
109− -> Word8 -> Word8 -> Word8 -> Word8
110− -> UUID
111−makeFromBytes b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf
112− = UUID w0 w1 w2 w3
113− where w0 = word b0 b1 b2 b3
114− w1 = word b4 b5 b6 b7
115− w2 = word b8 b9 ba bb
116− w3 = word bc bd be bf
117−
118−-- |Make a UUID from four Word32 values
119−makeFromWords :: Word32 -> Word32 -> Word32 -> Word32 -> UUID
120−makeFromWords = UUID
121−
122−-- |A Builder for constructing a UUID of a given version.
123−buildFromBytes :: Word8
124− -> Word8 -> Word8 -> Word8 -> Word8
125− -> Word8 -> Word8 -> Word8 -> Word8
126− -> Word8 -> Word8 -> Word8 -> Word8
127− -> Word8 -> Word8 -> Word8 -> Word8
128− -> UUID
129−buildFromBytes v b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf =
130− makeFromBytes b0 b1 b2 b3 b4 b5 b6' b7 b8' b9 ba bb bc bd be bf
131− where b6' = b6 .&. 0x0f .|. (v `shiftL` 4)
132− b8' = b8 .&. 0x3f .|. 0x80
133−
134−-- |Build a UUID of a given version from Word32 values.
135−buildFromWords :: Word8 -> Word32 -> Word32 -> Word32 -> Word32 -> UUID
136−buildFromWords v w0 w1 w2 w3 = makeFromWords w0 w1' w2' w3
137− where w1' = w1 .&. 0xffff0fff .|. ((fromIntegral v) `shiftL` 12)
138− w2' = w2 .&. 0x3fffffff .|. 0x80000000
139−
140−
141−-- |Return the bytes that make up the UUID
142−toList :: UUID -> [Word8]
143−toList (UUID w0 w1 w2 w3) =
144− [byte 3 w0, byte 2 w0, byte 1 w0, byte 0 w0,
145− byte 3 w1, byte 2 w1, byte 1 w1, byte 0 w1,
146− byte 3 w2, byte 2 w2, byte 1 w2, byte 0 w2,
147− byte 3 w3, byte 2 w3, byte 1 w3, byte 0 w3]
148−
149−-- |Construct a UUID from a list of Word8. Returns Nothing if the list isn't
150−-- exactly sixteen bytes long
151−fromList :: [Word8] -> Maybe UUID
152−fromList [b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf] =
153− Just $ makeFromBytes b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf
154−fromList _ = Nothing
155−
156−
157−--
158−-- UUID API
159−--
160−
161−-- |Returns true if the passed-in UUID is the 'nil' UUID.
162−null :: UUID -> Bool
163−null = (== nil)
164− -- Note: This actually faster than:
165− -- null (UUID 0 0 0 0) = True
166− -- null _ = False
167−
168−-- |The nil UUID, as defined in RFC 4122.
169−-- It is a UUID of all zeros. @'null' u@ iff @'u' == 'nil'@.
170−nil :: UUID
171−nil = UUID 0 0 0 0
172−
173−-- |Extract a UUID from a 'ByteString' in network byte order.
174−-- The argument must be 16 bytes long, otherwise 'Nothing' is returned.
175−fromByteString :: Lazy.ByteString -> Maybe UUID
176−fromByteString = fromList . Lazy.unpack
177−
178−-- |Encode a UUID into a 'ByteString' in network order.
179−toByteString :: UUID -> Lazy.ByteString
180−toByteString = Lazy.pack . toList
181−
182−-- |If the passed in 'String' can be parsed as a 'UUID', it will be.
183−-- The hyphens may not be omitted.
184−-- Example:
185−--
186−-- @
187−-- fromString \"c2cc10e1-57d6-4b6f-9899-38d972112d8c\"
188−-- @
189−--
190−-- Hex digits may be upper or lower-case.
191−fromString :: String -> Maybe UUID
192−fromString xs | validFmt = fromString' xs
193− | otherwise = Nothing
194− where validFmt = elemIndices '-' xs == [8,13,18,23]
195−
196−fromString' :: String -> Maybe UUID
197−fromString' s0 = do
198− (w0, s1) <- hexWord s0
199− (w1, s2) <- hexWord s1
200− (w2, s3) <- hexWord s2
201− (w3, s4) <- hexWord s3
202− if s4 /= "" then Nothing
203− else Just $ UUID w0 w1 w2 w3
204− where hexWord :: String -> Maybe (Word32, String)
205− hexWord s = Just (0, s) >>= hexByte >>= hexByte
206− >>= hexByte >>= hexByte
207−
208− hexByte :: (Word32, String) -> Maybe (Word32, String)
209− hexByte (w, '-':ds) = hexByte (w, ds)
210− hexByte (w, hi:lo:ds)
211− | bothHex = Just ((w `shiftL` 8) .|. octet, ds)
212− | otherwise = Nothing
213− where bothHex = isHexDigit hi && isHexDigit lo
214− octet = fromIntegral (16 * digitToInt hi + digitToInt lo)
215− hexByte _ = Nothing
216−
217−-- | Convert a UUID into a hypenated string using lower-case letters.
218−-- Example:
219−--
220−-- @
221−-- toString $ fromString \"550e8400-e29b-41d4-a716-446655440000\"
222−-- @
223−toString :: UUID -> String
224−toString (UUID w0 w1 w2 w3) = hexw w0 $ hexw' w1 $ hexw' w2 $ hexw w3 ""
225− where hexw :: Word32 -> String -> String
226− hexw w s = hexn w 28 : hexn w 24 : hexn w 20 : hexn w 16
227− : hexn w 12 : hexn w 8 : hexn w 4 : hexn w 0 : s
228−
229− hexw' :: Word32 -> String -> String
230− hexw' w s = '-' : hexn w 28 : hexn w 24 : hexn w 20 : hexn w 16
231− : '-' : hexn w 12 : hexn w 8 : hexn w 4 : hexn w 0 : s
232−
233− hexn :: Word32 -> Int -> Char
234− hexn w r = intToDigit $ fromIntegral ((w `shiftR` r) .&. 0xf)
235−
236−
237−--
238−-- Class Instances
239−--
240−
241−instance Random UUID where
242− random g = (fromGenNext w0 w1 w2 w3 w4, g4)
243− where (w0, g0) = next g
244− (w1, g1) = next g0
245− (w2, g2) = next g1
246− (w3, g3) = next g2
247− (w4, g4) = next g3
248− randomR _ = random -- range is ignored
249−
250−-- |Build a UUID from the results of five calls to next on a StdGen.
251−-- While next on StdGet returns an Int, it doesn't provide 32 bits of
252−-- randomness. This code relies on at last 28 bits of randomness in the
253−-- and optimizes its use so as to make only five random values, not six.
254−fromGenNext :: Int -> Int -> Int -> Int -> Int -> UUID
255−fromGenNext w0 w1 w2 w3 w4 =
256− buildFromBytes 4 /-/ (ThreeByte w0)
257− /-/ (ThreeByte w1)
258− /-/ w2 -- use all 4 bytes because we know the version
259− -- field will "cover" the upper, non-random bits
260− /-/ (ThreeByte w3)
261− /-/ (ThreeByte w4)
262−
263−-- |A ByteSource to extract only three bytes from an Int, since next on StdGet
264−-- only returns 31 bits of randomness.
265−type instance ByteSink ThreeByte g = Takes3Bytes g
266−newtype ThreeByte = ThreeByte Int
267−instance ByteSource ThreeByte where
268− f /-/ (ThreeByte w) = f b1 b2 b3
269− where b1 = fromIntegral (w `shiftR` 16)
270− b2 = fromIntegral (w `shiftR` 8)
271− b3 = fromIntegral w
272−
273−
274−instance Show UUID where
275− show = toString
276−
277−instance Read UUID where
278− readsPrec _ str =
279− let noSpaces = dropWhile isSpace str
280− in case fromString (take 36 noSpaces) of
281− Nothing -> []
282− Just u -> [(u,drop 36 noSpaces)]
283−
284−
285−instance Storable UUID where
286− sizeOf _ = 16
287− alignment _ = 1 -- UUIDs are stored as individual octets
288−
289− peekByteOff p off =
290− mapM (peekByteOff p) [off..(off+15)] >>= return . fromJust . fromList
291−
292− pokeByteOff p off u =
293− sequence_ $ zipWith (pokeByteOff p) [off..] (toList u)
294−
295−
296−instance Binary UUID where
297− put (UUID w0 w1 w2 w3) =
298− putWord32be w0 >> putWord32be w1 >> putWord32be w2 >> putWord32be w3
299− get = liftM4 UUID getWord32be getWord32be getWord32be getWord32be
300−
301−
302−-- My goal with this instance was to make it work just enough to do what
303−-- I want when used with the HStringTemplate library.
304−instance Data UUID where
305− toConstr uu = mkConstr uuidType (show uu) [] (error "fixity")
306− gunfold _ _ = error "gunfold"
307− dataTypeOf _ = uuidType
308−
309−uuidType :: DataType
310−uuidType = mkNoRepType "Data.UUID.UUID"
311−
312−#if !(MIN_VERSION_base(4,2,0))
313−mkNoRepType :: String -> DataType
314−mkNoRepType = mkNorepType
315−#endif
316−
Data/UUID/V1.hsdeleted−106
@@ -1,106 +0,0 @@
1−{-# OPTIONS_GHC -fno-cse #-}
2−{-# LANGUAGE TypeFamilies #-}
3−
4−-- |
5−-- Module : Data.UUID.V1
6−-- Copyright : (c) 2008 Jason Dusek
7−-- (c) 2009 Mark Lentczner
8−-- (c) 2009-2010 Antoine Latter
9−--
10−-- License : BSD-style
11−--
12−-- Maintainer : aslatter@gmail.com
13−-- Stability : experimental
14−-- Portability : portable
15−--
16−-- RFC 4122 Version 1 UUID state machine.
17−
18−module Data.UUID.V1(nextUUID)
19−where
20−
21−import Data.Time
22−
23−import Data.Bits
24−import Data.Word
25−
26−import Control.Concurrent.MVar
27−import System.IO.Unsafe
28−
29−import qualified System.Info.MAC as SysMAC
30−import Data.MAC
31−
32−import Data.UUID.Builder
33−import Data.UUID.Internal
34−
35−-- | Returns a new UUID derived from the local hardware MAC
36−-- address and the current system time.
37−-- Is generated according to the Version 1 UUID sepcified in
38−-- RFC 4122.
39−--
40−-- Returns nothing if the hardware MAC address could not
41−-- be discovered.
42−nextUUID :: IO (Maybe UUID)
43−nextUUID = do
44− res <- stepTime
45− mac <- SysMAC.mac
46− case (res, mac) of
47− (Just (c, t), Just m) -> return $ Just $ makeUUID t c m
48− _ -> return Nothing
49−
50−
51−makeUUID :: Word64 -> Word16 -> MAC -> UUID
52−makeUUID time clock mac =
53− buildFromBytes 1 /-/ tLow /-/ tMid /-/ tHigh /-/ clock /-/ (MACSource mac)
54− where tLow = (fromIntegral time) :: Word32
55− tMid = (fromIntegral (time `shiftR` 32)) :: Word16
56− tHigh = (fromIntegral (time `shiftR` 48)) :: Word16
57−
58−newtype MACSource = MACSource MAC
59−instance ByteSource MACSource where
60− z /-/ (MACSource (MAC a b c d e f)) = z a b c d e f
61−type instance ByteSink MACSource g = Takes3Bytes (Takes3Bytes g)
62−
63−
64−-- |Approximates the clock algorithm in RFC 4122, section 4.2
65−-- Isn't system wide or thread safe, nor does it properly randomize
66−-- the clock value on initialization.
67−stepTime :: IO (Maybe (Word16, Word64))
68−stepTime = do
69− h1 <- fmap hundredsOfNanosSinceGregorianReform getCurrentTime
70− modifyMVar state $ \s@(State c0 h0) ->
71− if h1 > h0
72− then
73− return (State c0 h1, Just (c0, h1))
74− else
75− let
76− c1 = succ c0
77− in if c1 <= 0x3fff -- when clock is initially randomized,
78− -- then this test will need to change
79− then
80− return (State c1 h1, Just (c1, h1))
81− else
82− return (s, Nothing)
83−
84−
85−{-# NOINLINE state #-}
86−state :: MVar State
87−state = unsafePerformIO $ do
88− h0 <- fmap hundredsOfNanosSinceGregorianReform getCurrentTime
89− newMVar $ State 0 h0 -- the 0 should be a random number
90−
91−
92−data State = State
93− {-# UNPACK #-} !Word16
94− {-# UNPACK #-} !Word64
95− deriving (Show)
96−
97−
98−
99−hundredsOfNanosSinceGregorianReform :: UTCTime -> Word64
100−hundredsOfNanosSinceGregorianReform t = floor $ 10000000 * dt
101− where
102− gregorianReform = UTCTime (fromGregorian 1582 10 15) 0
103− dt = t `diffUTCTime` gregorianReform
104−
105−
106−
Data/UUID/V3.hsdeleted−45
@@ -1,45 +0,0 @@
1−-- |
2−-- Module : Data.UUID.V3
3−-- Copyright : (c) 2010 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 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.V3
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.Internal
32−import qualified Data.UUID.Named as Shared
33−import qualified Crypto.Hash.MD5 as MD5
34−
35−
36−-- |Generate a 'UUID' within the specified namespace out of the given
37−-- object.
38−--
39−-- Uses an MD5 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 MD5.hash 3
45−
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/TestUUID.hsdeleted−168
@@ -1,168 +0,0 @@
1−import Control.Monad (replicateM)
2−import Data.Bits
3−import qualified Data.ByteString.Lazy as B
4−import Data.Char (ord)
5−import Data.List (nub, (\\))
6−import Data.Maybe
7−import Data.Word
8−import qualified Data.UUID as U
9−import qualified Data.UUID.V1 as U
10−import qualified Data.UUID.V3 as U3
11−import qualified Data.UUID.V5 as U5
12−import Test.HUnit
13−import Test.QuickCheck hiding ((.&.))
14−import System.IO
15−import System.Random
16−
17−
18−isValidVersion :: Int -> U.UUID -> Bool
19−isValidVersion v u = lenOK && variantOK && versionOK
20− where bs = U.toByteString u
21− lenOK = B.length bs == 16
22− variantOK = (B.index bs 8) .&. 0xc0 == 0x80
23− versionOK = (B.index bs 6) .&. 0xf0 == fromIntegral (v `shiftL` 4)
24−
25−
26−instance Arbitrary U.UUID where
27− -- the UUID random instance ignores bounds
28− arbitrary = choose (U.nil, U.nil)
29−
30−-- instance Arbitrary Word8 where
31−-- arbitrary = (fromIntegral . fst . randomR (0,255::Int)) `fmap` rand
32−
33−
34−test_null :: Test
35−test_null = TestList [
36− "nil is null" ~: assertBool "" (U.null U.nil),
37− "namespaceDNS is not null" ~: assertBool "" (not $ U.null U3.namespaceDNS)
38− ]
39−
40−test_nil :: Test
41−test_nil = TestList [
42− "nil string" ~: U.toString U.nil @?= "00000000-0000-0000-0000-000000000000",
43− "nil bytes" ~: U.toByteString U.nil @?= B.pack (replicate 16 0)
44− ]
45−
46−test_conv :: Test
47−test_conv = TestList [
48− "conv bytes to string" ~:
49− maybe "" (U.toString) (U.fromByteString b16) @?= s16,
50− "conv string to bytes" ~:
51− maybe B.empty (U.toByteString) (U.fromString s16) @?= b16
52− ]
53− where b16 = B.pack [1..16]
54− s16 = "01020304-0506-0708-090a-0b0c0d0e0f10"
55−
56−test_v1 :: [Maybe U.UUID] -> Test
57−test_v1 v1s = TestList [
58− "V1 unique" ~: nub (v1s \\ nub v1s) @?= [],
59− "V1 not null" ~: TestList $ map (testUUID (not . U.null)) v1s,
60− "V1 valid" ~: TestList $ map (testUUID (isValidVersion 1)) v1s
61− ]
62− where testUUID :: (U.UUID -> Bool) -> Maybe U.UUID -> Test
63− testUUID p u = maybe False p u ~? show u
64−
65−test_v3 :: Test
66−test_v3 = TestList [
67− "V3 computation" ~:
68− U3.generateNamed U3.namespaceDNS name @?= uV3
69− ]
70− where name = map (fromIntegral . ord) "www.widgets.com" :: [Word8]
71− uV3 = fromJust $ U.fromString "3d813cbb-47fb-32ba-91df-831e1593ac29"
72−
73−test_v5 :: Test
74−test_v5 = TestList [
75− "V5 computation" ~:
76− U5.generateNamed U5.namespaceDNS name @?= uV5
77− ]
78− where name = map (fromIntegral . ord) "www.widgets.com" :: [Word8]
79− uV5 = fromJust $ U.fromString "21f7f8de-8051-5b89-8680-0195ef798b6a"
80−
81−prop_stringRoundTrip :: Property
82−prop_stringRoundTrip = label "String round trip" stringRoundTrip
83− where stringRoundTrip :: U.UUID -> Bool
84− stringRoundTrip u = maybe False (== u) $ U.fromString (U.toString u)
85−
86−prop_byteStringRoundTrip :: Property
87−prop_byteStringRoundTrip = label "ByteString round trip" byteStringRoundTrip
88− where byteStringRoundTrip :: U.UUID -> Bool
89− byteStringRoundTrip u = maybe False (== u)
90− $ U.fromByteString (U.toByteString u)
91−
92−prop_stringLength :: Property
93−prop_stringLength = label "String length" stringLength
94− where stringLength :: U.UUID -> Bool
95− stringLength u = length (U.toString u) == 36
96−
97−prop_byteStringLength :: Property
98−prop_byteStringLength = label "ByteString length" byteStringLength
99− where byteStringLength :: U.UUID -> Bool
100− byteStringLength u = B.length (U.toByteString u) == 16
101−
102−prop_randomsDiffer :: Property
103−prop_randomsDiffer = label "Randoms differ" randomsDiffer
104− where randomsDiffer :: (U.UUID, U.UUID) -> Bool
105− randomsDiffer (u1, u2) = u1 /= u2
106−
107−prop_randomNotNull :: Property
108−prop_randomNotNull = label "Random not null" randomNotNull
109− where randomNotNull :: U.UUID -> Bool
110− randomNotNull = not. U.null
111−
112−prop_randomsValid :: Property
113−prop_randomsValid = label "Random valid" randomsValid
114− where randomsValid :: U.UUID -> Bool
115− randomsValid = isValidVersion 4
116−
117−prop_v3NotNull :: Property
118−prop_v3NotNull = label "V3 not null" v3NotNull
119− where v3NotNull :: [Word8] -> Bool
120− v3NotNull = not . U.null . U3.generateNamed U3.namespaceDNS
121−
122−prop_v3Valid :: Property
123−prop_v3Valid = label "V3 valid" v3Valid
124− where v3Valid :: [Word8] -> Bool
125− v3Valid = isValidVersion 3 . U3.generateNamed U3.namespaceDNS
126−
127−prop_v5NotNull :: Property
128−prop_v5NotNull = label "V5 not null" v5NotNull
129− where v5NotNull :: [Word8] -> Bool
130− v5NotNull = not . U.null . U5.generateNamed U5.namespaceDNS
131−
132−prop_v5Valid :: Property
133−prop_v5Valid = label "V5 valid" v5Valid
134− where v5Valid :: [Word8] -> Bool
135− v5Valid = isValidVersion 5 . U5.generateNamed U5.namespaceDNS
136−
137−prop_readShowRoundTrip :: Property
138−prop_readShowRoundTrip = label "Read/Show round-trip" prop
139− where -- we're using 'Maybe UUID' to add a bit of
140− -- real-world complexity.
141− prop :: U.UUID -> Bool
142− prop uuid = read (show (Just uuid)) == Just uuid
143−
144−main :: IO ()
145−main = do
146− v1s <- replicateM 100 U.nextUUID
147− runTestText (putTextToHandle stderr False) (TestList [
148− test_null,
149− test_nil,
150− test_conv,
151− test_v1 v1s,
152− test_v3,
153− test_v5
154− ])
155− mapM_ quickCheck $ [
156− prop_stringRoundTrip,
157− prop_readShowRoundTrip,
158− prop_byteStringRoundTrip,
159− prop_stringLength,
160− prop_byteStringLength,
161− prop_randomsDiffer,
162− prop_randomNotNull,
163− prop_randomsValid,
164− prop_v3NotNull,
165− prop_v3Valid,
166− prop_v5NotNull,
167− prop_v5Valid
168− ]
tests/summarize-bench-results.pldeleted−14
@@ -1,14 +0,0 @@
1−#!/usr/bin/env perl
2−
3−
4−while(<>) {
5− if (/^benchmarking (.*)$/) {
6− $name = $1;
7− }
8− if (/^mean:\s*([\d.]*) (\w*),/) {
9− $mean = 1 * $1;
10− $units = $2;
11−
12− printf "%-30s %10.2f %2s\n", $name, $mean, $units;
13− }
14−}
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+ ]
tests/BenchUUID.hs → uuid-bench/bench/uuid-types-benchmark.hsrenamed+66−58
@@ -1,74 +1,83 @@
1−import Control.DeepSeq
2−import Criterion.Main
3−import Data.Char (ord)
4−import Data.IORef
5−import Data.Maybe (fromJust)
6−import Data.Word
7−import qualified Data.Set as Set
8−import qualified Data.ByteString.Lazy as BL
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
97import qualified Data.ByteString.Lazy.Internal as BL
10−import qualified Data.UUID as U
11−import qualified Data.UUID.V1 as U
12−import qualified Data.UUID.V3 as U3
13−import qualified Data.UUID.V5 as U5
14−import System.Random
15−import System.Random.Mersenne.Pure64
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
1617
18+#if !(MIN_VERSION_bytestring(0,10,0))
19+-- orphan
1720instance NFData BL.ByteString where
1821 rnf BL.Empty = ()
1922 rnf (BL.Chunk _ ts) = rnf ts
20−
21−instance NFData U.UUID where
22−
23+#endif
2324
2425main :: IO ()
2526main = do
26− u1 <- randomIO
27− let s1 = U.toString u1
28− b1 = U.toByteString u1
29− n1 = (map (fromIntegral . ord) "http://www.haskell.org/") :: [Word8]
30− nil2 = fromJust $
31− U.fromString "00000000-0000-0000-0000-000000000000"
32− u2a = fromJust $ U.fromString "169a5a43-c051-4a16-98f4-08447ddd5dc0"
33− u2b = fromJust $ U.fromByteString $
34− BL.pack [0x16, 0x9a, 0x5a, 0x43, 0xc0, 0x51, 0x4a, 0x16,
35− 0x98, 0xf4, 0x08, 0x44, 0x7d, 0xdd, 0x5d, 0xc0]
36− u3 = fromJust $ U.fromString "dea6f619-1038-438b-b4af-f1cdec1e6e23"
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
3743
38− -- setup for random generation
39− randomState <- newPureMT >>= newIORef
40− let randomUUID = do
41− state <- readIORef randomState
42− let (uuid, state') = random state
43− writeIORef randomState state'
44− return uuid
44+ poke uuidPtr u1
4545
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− ],
54− bgroup "conversion" [
55− bench "toString" $ nf U.toString u1,
56− bench "fromString" $ nf U.fromString s1,
57− bench "toByteString" $ nf U.toByteString u1,
58− bench "fromByteString" $ nf U.fromByteString b1
59− ],
60− bgroup "generation" [
61− bench "V1" $ nfIO U.nextUUID,
62− bench "V4" $ nfIO (randomUUID :: IO U.UUID),
63− bench "V3" $ nf (U3.generateNamed U3.namespaceURL) n1,
64− bench "V5" $ nf (U5.generateNamed U5.namespaceURL) n1
65− ],
66− bench "set making" $ nf Set.fromList uuids
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
6775 ]
76+ ]
6877
6978-- 50 uuids, so tests can be repeatable
7079uuids :: [U.UUID]
71−uuids
80+uuids
7281 = map (fromJust . U.fromString)
7382 [
7483 "35d42593-1fca-4465-b588-a2e78cb996ba",
@@ -122,4 +131,3 @@ uuids
122131 "8091837c-6456-42c3-a686-f4731a41d4f9",
123132 "2a0e2efb-a11c-4a44-81ee-3efc37379b48"
124133 ]
125−
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
Data/UUID/Builder.hs → uuid-types/src/Data/UUID/Types/Internal/Builder.hsrenamed+21−5
@@ -1,6 +1,9 @@
11{-# LANGUAGE TypeFamilies #-}
2+{-# LANGUAGE Unsafe #-}
23
3−-- Module : Data.UUID.Builder
4+{-# OPTIONS_HADDOCK hide #-}
5+
6+-- | Module : Data.UUID.Types.Internal.Builder
47-- Copyright : (c) 2009 Mark Lentczner
58--
69-- License : BSD-style
@@ -10,14 +13,14 @@
1013-- Portability : portable
1114--
1215-- This module provides a system that can call a function that takes
13−-- a sequence of some number of Word8 arguments.
14−--
16+-- a sequence of some number of Word8 arguments.
17+--
1518-- The twist is that the Word8 arguments can be supplied directly
1619-- from Word8s, or from other sources that may provide more than
1720-- one Word8 apiece. Examples are Word16 and Word32 that supply
1821-- two and four Word8s respectively. Other ByteSource instances
1922-- can be defined.
20−--
23+--
2124-- This module is admittedly overkill. There are only three places
2225-- in the uuid package that need to call buildFromBytes with 16
2326-- Word8 values, but each place uses Words of different lengths:
@@ -28,7 +31,7 @@
2831-- code was ungainly. Using this module makes the code very
2932-- concise, and turns out to optimize to just as fast, or faster!
3033
31−module Data.UUID.Builder
34+module Data.UUID.Types.Internal.Builder
3235 (ByteSource(..)
3336 ,ByteSink
3437 ,Takes1Byte
@@ -46,6 +49,7 @@ type Takes1Byte g = Word8 -> g
4649type Takes2Bytes g = Word8 -> Word8 -> g
4750type Takes3Bytes g = Word8 -> Word8 -> Word8 -> g
4851type Takes4Bytes g = Word8 -> Word8 -> Word8 -> Word8 -> g
52+type Takes8Bytes g = Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> g
4953
5054-- | Type of function that a given ByteSource needs.
5155-- This function must take as many Word8 arguments as the ByteSource provides
@@ -53,6 +57,7 @@ type family ByteSink w g
5357type instance ByteSink Word8 g = Takes1Byte g
5458type instance ByteSink Word16 g = Takes2Bytes g
5559type instance ByteSink Word32 g = Takes4Bytes g
60+type instance ByteSink Word64 g = Takes8Bytes g
5661type instance ByteSink Int g = Takes4Bytes g
5762
5863
@@ -80,6 +85,17 @@ instance ByteSource Word32 where
8085 b3 = fromIntegral (w `shiftR` 8)
8186 b4 = fromIntegral w
8287
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+
8399instance ByteSource Int where
84100 f /-/ w = f b1 b2 b3 b4
85101 where b1 = fromIntegral (w `shiftR` 24)
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−69
@@ -1,69 +0,0 @@
1−Name: uuid
2−Version: 1.2.4
3−Copyright: (c) 2008-2012 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.8
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://projects.haskell.org/uuid/
21−Bug-Reports: mailto:aslatter@gmail.com
22−
23−Extra-Source-Files:
24− CHANGES
25− CONTRIBUTORS
26−
27−
28−Library
29− Build-Depends: random, binary, bytestring, cryptohash, maccatcher,
30− time, base >=3, base < 5
31−
32− Exposed-Modules:
33− Data.UUID
34− Data.UUID.V1
35− Data.UUID.V3
36− Data.UUID.V5
37−
38− Other-Modules:
39− Data.UUID.Builder
40− Data.UUID.Internal
41− Data.UUID.Named
42−
43− Extensions: DeriveDataTypeable
44− Ghc-Prof-Options: -auto-all -caf-all
45− Ghc-Shared-Options:
46− Ghc-Options: -Wall
47−
48−source-repository head
49− type: darcs
50− location: http://code.haskell.org/uuid
51−
52−-- not strictly a test, but we want it to error if
53−-- it can't build
54−Test-Suite benchmark
55− Type: exitcode-stdio-1.0
56− Main-is: BenchUUID.hs
57− Hs-source-dirs: tests
58− Extensions: DeriveDataTypeable, CPP
59− Build-depends: base == 4.*, uuid, random, criterion >= 0.4 && < 0.7, mersenne-random-pure64,
60− bytestring == 0.9.*, containers == 0.4.*, deepseq >= 1.1 && < 1.4
61−
62−Test-Suite testuuid
63− Type: exitcode-stdio-1.0
64− Main-is: TestUUID.hs
65− Hs-source-dirs: tests
66− Extensions: DeriveDataTypeable
67− Ghc-Options: -Wall -fno-warn-orphans
68− Build-Depends: random, bytestring, base >=3, base < 5, uuid,
69− HUnit >=1.2 && < 1.3, QuickCheck >=2.4 && < 2.5
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
1313 x <- newUUID
1414 y <- newUUID
1515 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.
uuid/Setup.hsnew file+4
@@ -0,0 +1,4 @@
1+import Distribution.Simple
2+main :: IO ()
3+main = defaultMain
4+
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.
Data/UUID/Named.hs → uuid/src/Data/UUID/Named.hsrenamed+1−1
@@ -26,7 +26,7 @@ module Data.UUID.Named
2626 ,namespaceX500
2727 ) where
2828
29−import Data.UUID.Internal
29+import Data.UUID.Types.Internal
3030
3131import Control.Applicative ((<*>),(<$>))
3232import Data.Binary.Get (runGet, getWord32be)
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
Data/UUID/V5.hs → uuid/src/Data/UUID/V5.hsrenamed+1−2
@@ -28,7 +28,7 @@ module Data.UUID.V5
2828
2929import Data.Word
3030
31−import Data.UUID.Internal
31+import Data.UUID.Types.Internal
3232import qualified Data.UUID.Named as Shared
3333import qualified Crypto.Hash.SHA1 as SHA1
3434
@@ -42,4 +42,3 @@ generateNamed :: UUID -- ^Namespace
4242 -> [Word8] -- ^Object
4343 -> UUID
4444generateNamed = Shared.generateNamed SHA1.hash 5
45−
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