packages feed

heptapod (empty) → 0.2024.8.16

raw patch · 5 files changed

+130/−0 lines, 5 filesdep +basedep +bytestringdep +entropy

Dependencies added: base, bytestring, entropy, time, uuid-types

Files

+ CHANGELOG.md view
@@ -0,0 +1,4 @@+# Change log++Heptapod follows the [Package Versioning Policy](https://pvp.haskell.org).+You can find release notes [on GitHub](https://github.com/tfausak/heptapod/releases).
+ LICENSE.txt view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2024 Taylor Fausak++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.md view
@@ -0,0 +1,3 @@+# Heptapod++Heptapod is a Haskell library for generating version 7 UUIDs.
+ heptapod.cabal view
@@ -0,0 +1,48 @@+cabal-version: 2.2+category: Data+description: Heptapod generates UUIDv7 values.+extra-doc-files:+  CHANGELOG.md+  README.md++license-file: LICENSE.txt+license: MIT+maintainer: Taylor Fausak+name: heptapod+synopsis: Generate UUIDv7 values.+version: 0.2024.8.16++source-repository head+  location: https://github.com/tfausak/heptapod+  type: git++flag pedantic+  default: False+  manual: True++common library+  build-depends: base ^>=4.18.0.0 || ^>=4.19.0.0 || ^>=4.20.0.0+  default-language: Haskell2010+  ghc-options:+    -Weverything+    -Wno-implicit-prelude+    -Wno-missing-export-lists+    -Wno-missing-safe-haskell-mode+    -Wno-prepositive-qualified-module+    -Wno-safe+    -Wno-unsafe++  if flag(pedantic)+    ghc-options: -Werror++library+  import: library+  build-depends:+    bytestring ^>=0.11.5.3 || ^>=0.12.1.0,+    entropy ^>=0.4.1.10,+    time ^>=1.12.2 || ^>=1.14,+    uuid-types ^>=1.0.6,++  -- cabal-gild: discover source/library+  exposed-modules: Heptapod+  hs-source-dirs: source/library
+ source/library/Heptapod.hs view
@@ -0,0 +1,54 @@+-- | This module provides functions for building and generating version 7 UUIDs+-- as defined by section 5.7 of RFC 9562.+--+-- <https://datatracker.ietf.org/doc/html/rfc9562#name-uuid-version-7>+module Heptapod where++import qualified Data.Bits as Bits+import qualified Data.ByteString as ByteString+import qualified Data.Int as Int+import qualified Data.Time.Clock.System as Time+import qualified Data.UUID.Types as UUID+import qualified Data.Word as Word+import qualified System.Entropy as Entropy++-- | Generates a UUIDv7 using the current time (from 'Time.getSystemTime') and+-- random data (from 'Entropy.getEntropy').+generate :: IO UUID.UUID+generate = do+  t <- Time.getSystemTime+  -- Note that we only need 74 bits (12 + 62) of randomness. That's a little+  -- more than 9 bytes (72 bits), so we have to request 10 bytes (80 bits) of+  -- entropy. The extra 6 bits are discarded.+  b <- Entropy.getEntropy 10+  pure $+    let u8_u64 = fromIntegral :: Word.Word8 -> Word.Word64+        f = Bits.shift . u8_u64 . ByteString.index b+        r = f 0 0 + f 1 8+        s = f 2 0 + f 3 8 + f 4 16 + f 5 24 + f 6 32 + f 7 40 + f 8 48 + f 9 56+     in build t r s++-- | Builds a UUIDv7 using the provided fields. Typically you will want to use+-- the 'generate' function instead.+build ::+  -- | Corresponds to the @unix_ts_ms@ field.+  Time.SystemTime ->+  -- | Corresponds to the @rand_a@ field. Only the low 12 bits are used.+  Word.Word64 ->+  -- | Corresponds to the @rand_b@ field. Only the low 62 bits are used.+  Word.Word64 ->+  UUID.UUID+build t r s =+  let i64_u64 = fromIntegral :: Int.Int64 -> Word.Word64+      u32_u64 = fromIntegral :: Word.Word32 -> Word.Word64+      unix_ts_ms =+        Bits.shift+          ( (i64_u64 (Time.systemSeconds t) * 1000)+              + u32_u64 (div (Time.systemNanoseconds t) 1000000)+          )+          16+      ver = Bits.shift 0x7 12 :: Word.Word64+      rand_a = r Bits..&. 0x0fff+      var = Bits.shift 0x2 62 :: Word.Word64+      rand_b = s Bits..&. 0x3fffffffffffffff+   in UUID.fromWords64 (unix_ts_ms + ver + rand_a) (var + rand_b)