mmzk-typeid 0.7.0.0 → 0.7.0.1
raw patch · 7 files changed
+64/−12 lines, 7 filesdep +hint
Dependencies added: hint
Files
- CHANGELOG.md +11/−0
- mmzk-typeid.cabal +4/−3
- src/Data/KindID/Internal.hs +2/−1
- src/Data/TypeID/Internal.hs +2/−1
- src/Data/UUID/V7.hs +1/−6
- src/Data/UUID/Versions.hs +2/−1
- test/Spec.hs +42/−0
CHANGELOG.md view
@@ -1,6 +1,17 @@ # Revision history for mmzk-typeid +## 0.7.0.1 -- 2024-10-10++* Add `Generic` derivation to `TypeID'`, `KindID'`, and `UUIDVersion`.++* Test the type-level constraints of `KindID` using an external GHC interpreter.++* Stop testing on GHC 9.2, replacing with tests on GHC 9.4.++* Update description in "Data.UUID.V7" to reflect the fact that UUIDv7 standard has been finalised.++ ## 0.7.0.0 -- 2024-07-03 * Use `String`s instead of `Text`s inside the constructors of `TypeIDError` so that it is easier to use the promoted constructors.
mmzk-typeid.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: mmzk-typeid-version: 0.7.0.0+version: 0.7.0.1 synopsis: A TypeID and UUIDv7 implementation for Haskell description:@@ -35,8 +35,8 @@ maintainer: Yitang Chen <mmzk1526@outlook.com> category: Data, UUID, UUIDv7, TypeID tested-with:- GHC == 9.2.8- GHC == 9.6.1+ GHC == 9.4.8+ GHC == 9.6.4 GHC == 9.8.2 extra-source-files: CHANGELOG.md@@ -173,6 +173,7 @@ containers ^>=0.6, entropy, hashable,+ hint ^>=0.9, hspec ^>=2.11, random, text,
src/Data/KindID/Internal.hs view
@@ -32,6 +32,7 @@ import qualified Data.UUID.V7 as V7 import Data.UUID.Versions import Foreign+import GHC.Generics (Generic) import GHC.TypeLits (symbolVal) -- | A TypeID with the prefix encoded at type level.@@ -39,7 +40,7 @@ -- It is dubbed 'Data.KindID.V7.KindID' because the prefix here is a data kind -- rather than a type. newtype KindID' (version :: UUIDVersion) prefix = KindID' UUID- deriving (Eq, Ord, Data, Typeable)+ deriving (Eq, Ord, Data, Typeable, Generic) instance (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => Show (KindID' version prefix) where
src/Data/TypeID/Internal.hs view
@@ -41,6 +41,7 @@ import qualified Data.UUID.V5 as V5 import qualified Data.UUID.V7 as V7 import Data.UUID.Versions+import GHC.Generics (Generic) import Foreign import System.Random @@ -50,7 +51,7 @@ -- The constructor is not exposed to the public API to prevent generating -- invalid 'TypeID''s. data TypeID' (version :: UUIDVersion) = TypeID' Text UUID- deriving (Eq, Ord, Data, Typeable)+ deriving (Eq, Ord, Data, Typeable, Generic) instance Show (TypeID' version) where show :: TypeID' version -> String
src/Data/UUID/V7.hs view
@@ -9,10 +9,6 @@ -- UUIDv7 is not currently present in the uuid package, therefore I have to -- make a quick patch of my own. ----- Note that since the specification for v7 is not yet finalised, this module's--- implementation may change in the future according to the potential--- adjustments in the specification.--- module Data.UUID.V7 ( -- * Data type@@ -39,7 +35,6 @@ import Data.IORef import Data.Time.Clock.POSIX import Data.UUID.Types.Internal- import Data.UUID.Versions import System.Entropy import System.IO.Unsafe (unsafePerformIO)@@ -141,7 +136,7 @@ -- | The global mutable state of (timestamp, sequence number). ----- The "NOINLINE" pragma is IMPORTANT! The logic would be flawed if it is+-- The \"NOINLINE\" pragma is IMPORTANT! The logic would be flawed if it is -- is inlined by its definition. __state__ :: IORef (Word64, Word16) __state__ = unsafePerformIO (newIORef (0, 0))
src/Data/UUID/Versions.hs view
@@ -16,11 +16,12 @@ import Data.Bits import Data.UUID.Types.Internal+import GHC.Generics (Generic) -- | The supported 'UUID' versions. These constructors are used as type-level -- tags for 'Data.TypeID.TypeID''. data UUIDVersion = V1 | V4 | V5 | V7- deriving (Eq, Ord, Bounded, Enum, Show)+ deriving (Eq, Ord, Bounded, Enum, Show, Generic) toInt :: Num a => UUIDVersion -> a toInt V1 = 1
test/Spec.hs view
@@ -36,6 +36,19 @@ import Data.UUID.Versions import Foreign import GHC.Generics (Generic)+import Language.Haskell.Interpreter+ ( Extension(..)+ , OptionVal(..)+ , InterpreterError(..)+ , GhcError(..)+ , eval+ , runInterpreter+ , set+ , languageExtensions+ , loadModules+ , setImports+ , searchPath+ , runStmt ) import Test.Hspec data TestData = TestData { name :: String@@ -64,6 +77,20 @@ anyTypeIDError :: Selector TypeIDError anyTypeIDError = const True +prefixHasExpectedError :: String -> String -> IO ()+prefixHasExpectedError str expectedErr = do+ result <- runInterpreter do+ set [languageExtensions := [AllowAmbiguousTypes, DataKinds, TypeFamilies], searchPath := ["./src"]]+ loadModules ["Data.KindID.Class"]+ setImports ["Prelude", "Data.KindID.Class"]+ runStmt $ "foo :: ValidPrefix " <> show str <> " => () <- return ()"+ eval "foo"+ case result of+ Left (WontCompile [e]) -> head (lines (errMsg e)) `shouldBe` expectedErr+ Left (WontCompile _) -> fail "Unexpected number of type errors!"+ Left _ -> fail "Impossible: cannot interpret!"+ Right _ -> fail "Unexpected success!"+ withCheck :: HasCallStack => (IDConv a, IDGen a) => IO a -> IO a withCheck action = do tid <- action@@ -84,10 +111,25 @@ main :: IO () main = hspec do+ typeLevelTest v7Test v1Test v4Test v5Test++typeLevelTest :: Spec+typeLevelTest = describe "Reject malformed KindID previx at compile time" do+ it "rejects invalid alphabet" do+ prefixHasExpectedError "sZb" "The prefix \"sZb\" contains invalid character 'Z'!"+ it "rejects single underscore" do+ prefixHasExpectedError "_" "The underscore separator should not be present if the prefix is empty!"+ it "rejects trailing underscore" do+ prefixHasExpectedError "a_" "The prefix \"a_\" should not end with an underscore!"+ it "rejects starting underscore" do+ prefixHasExpectedError "_a" "The prefix \"_a\" should not start with an underscore!"+ it "rejects long prefix" do+ prefixHasExpectedError "qwertyuiopasdfghjklzxcvbnm____________qwertyuiopasdfghjklzxcvbnm"+ "The prefix \"qwertyuiopasdfghjklzxcvbnm____________qwertyuiopasdfghjklzxcvbnm\" with 64 characters is too long!" v7Test :: Spec v7Test = do