@@ -2,20 +2,17 @@
2{-# LANGUAGE DeriveDataTypeable #-}
2{-# LANGUAGE DeriveDataTypeable #-}
3{-# LANGUAGE TypeFamilies #-}
3{-# LANGUAGE TypeFamilies #-}
4{-# LANGUAGE ViewPatterns #-}
4{-# LANGUAGE ViewPatterns #-}
5−{-# LANGUAGE Unsafe #-}
6−{-# LANGUAGE DeriveLift #-}
7−{-# LANGUAGE StandaloneDeriving #-}
8{-# OPTIONS_HADDOCK hide #-}
5{-# OPTIONS_HADDOCK hide #-}
11-- Module : Data.UUID.Types.Internal
8-- Module : Data.UUID.Types.Internal
12−-- Copyright : (c) 2017-2018 Herbert Valerio Riedel
13−-- (c) 2008-2009, 2012 Antoine Latter
9+-- Copyright : (c) 2008-2009, 2012 Antoine Latter
14-- (c) 2009 Mark Lentczner
10-- (c) 2009 Mark Lentczner
16-- License : BSD-style
12-- License : BSD-style
18−-- Maintainer : hvr@gnu.org
14+-- Maintainer : aslatter@gmail.com
15+-- Stability : experimental
19-- Portability : portable
16-- Portability : portable
21module Data.UUID.Types.Internal
18module Data.UUID.Types.Internal
@@ -30,8 +27,6 @@ module Data.UUID.Types.Internal
31 , fromWords
28 , fromWords
36 , buildFromBytes
31 , buildFromBytes
37 , buildFromWords
32 , buildFromWords
@@ -46,15 +41,22 @@ module Data.UUID.Types.Internal
47import Prelude hiding (null)
42import Prelude hiding (null)
44+import Control.Applicative ((<*>))
49import Control.DeepSeq (NFData (..))
45import Control.DeepSeq (NFData (..))
50import Control.Monad (guard, liftM2)
46import Control.Monad (guard, liftM2)
51import Data.Bits
47import Data.Bits
52import Data.Char
48import Data.Char
53−import Data.Data
49+import Data.Functor ((<$>))
54import Data.Hashable
50import Data.Hashable
55import Data.List (elemIndices)
51import Data.List (elemIndices)
56import Foreign.Ptr (Ptr)
52import Foreign.Ptr (Ptr)
54+#if MIN_VERSION_base(4,0,0)
57+import Data.Generics.Basics
58import Foreign.Storable
60import Foreign.Storable
60import Data.Binary
62import Data.Binary
@@ -65,19 +67,19 @@ import qualified Data.ByteString.Internal as BI
65import qualified Data.ByteString.Lazy as BL
67import qualified Data.ByteString.Lazy as BL
66import qualified Data.ByteString.Unsafe as BU
68import qualified Data.ByteString.Unsafe as BU
67import Data.Text (Text)
69import Data.Text (Text)
68−import qualified Data.Text.Encoding as T
70+import qualified Data.Text as T
70import Data.UUID.Types.Internal.Builder
72import Data.UUID.Types.Internal.Builder
72−import System.Random (Random (..), uniform)
74+import System.Random
73−import System.Random.Stateful (Uniform (..), uniformWord64)
75−import Language.Haskell.TH.Syntax (Lift)
77−-- | Type representing <https://en.wikipedia.org/wiki/UUID Universally Unique Identifiers (UUID)> as specified in
77+-- |The UUID type. A 'Random' instance is provided which produces
78−-- <http://tools.ietf.org/html/rfc4122 RFC 4122>.
78+-- insecure version 4 UUIDs as specified in RFC 4122. The 'Storable' and
79+-- 'Binary' instances are compatible with RFC 4122, storing the fields in
80+-- network order as 16 bytes.
79data UUID = UUID {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64
81data UUID = UUID {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64
80− deriving (Eq, Ord)
82+ deriving (Eq, Ord, Typeable)
82 Prior to uuid-types-1.0.4:
84 Prior to uuid-types-1.0.4:
83 !Word32 !Word32 !Word32 !Word32
85 !Word32 !Word32 !Word32 !Word32
@@ -92,18 +94,10 @@ data UUID = UUID {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64
92 None was as fast, overall, as the representation used here.
94 None was as fast, overall, as the representation used here.
95−-- | Convert a 'UUID' into a sequence of 'Word32' values.
97+-- | Covert a 'UUID' into a sequence of 'Word32' values.
96-- Useful for when you need to serialize a UUID and
98-- Useful for when you need to serialize a UUID and
97-- neither 'Storable' nor 'Binary' are appropriate.
99-- neither 'Storable' nor 'Binary' are appropriate.
98−--
100+-- Introduced in version 1.2.2.
99−-- >>> toWords <$> fromString "550e8400-e29b-41d4-a716-446655440000"
100−-- Just (1427014656,3801825748,2803254374,1430519808)
102−-- See also 'toWords64'.
104−-- /Since: @uuid-1.2.2@/
107toWords :: UUID -> (Word32, Word32, Word32, Word32)
101toWords :: UUID -> (Word32, Word32, Word32, Word32)
108toWords (UUID w12 w34) = (w1, w2, w3, w4)
102toWords (UUID w12 w34) = (w1, w2, w3, w4)
@@ -113,36 +107,12 @@ toWords (UUID w12 w34) = (w1, w2, w3, w4)
113 w4 = fromIntegral w34
107 w4 = fromIntegral w34
115-- | Create a 'UUID' from a sequence of 'Word32'. The
109-- | Create a 'UUID' from a sequence of 'Word32'. The
116−-- inverse of 'toWords'. Useful when you need a total
110+-- opposite of 'toWords'. Useful when you need a total
117-- function for constructing 'UUID' values.
111-- function for constructing 'UUID' values.
118−--
112+-- Introduced in version 1.2.2.
119−-- See also 'fromWords64'.
121−-- /Since: @uuid-1.2.2@/
124fromWords :: Word32 -> Word32 -> Word32 -> Word32 -> UUID
113fromWords :: Word32 -> Word32 -> Word32 -> Word32 -> UUID
125fromWords w1 w2 w3 w4 = UUID (w32to64 w1 w2) (w32to64 w3 w4)
114fromWords w1 w2 w3 w4 = UUID (w32to64 w1 w2) (w32to64 w3 w4)
127−-- | Convert a 'UUID' into a pair of 'Word64's.
129−-- >>> toWords64 <$> fromString "550e8400-e29b-41d4-a716-446655440000"
130−-- Just (6128981282234515924,12039885860129472512)
132−-- See also 'toWords'.
135−toWords64 :: UUID -> (Word64, Word64)
136−toWords64 (UUID w12 w34) = (w12,w34)
138−-- | Create a 'UUID' from a pair of 'Word64's.
140−-- Inverse of 'toWords64'. See also 'fromWords'.
143−fromWords64 :: Word64 -> Word64 -> UUID
146data UnpackedUUID =
116data UnpackedUUID =
147 UnpackedUUID {
117 UnpackedUUID {
148 time_low :: Word32 -- 0-3
118 time_low :: Word32 -- 0-3
@@ -195,10 +165,10 @@ pack unpacked =
196-- |Build a Word32 from four Word8 values, presented in big-endian order
166-- |Build a Word32 from four Word8 values, presented in big-endian order
197word :: Word8 -> Word8 -> Word8 -> Word8 -> Word32
167word :: Word8 -> Word8 -> Word8 -> Word8 -> Word32
198−word a b c d = (fromIntegral a `unsafeShiftL` 24)
168+word a b c d = (fromIntegral a `shiftL` 24)
199− .|. (fromIntegral b `unsafeShiftL` 16)
169+ .|. (fromIntegral b `shiftL` 16)
200− .|. (fromIntegral c `unsafeShiftL` 8)
170+ .|. (fromIntegral c `shiftL` 8)
201− .|. (fromIntegral d )
171+ .|. (fromIntegral d )
203-- |Extract a Word8 from a Word64. Bytes, high to low, are numbered from 7 to 0,
173-- |Extract a Word8 from a Word64. Bytes, high to low, are numbered from 7 to 0,
204byte :: Int -> Word64 -> Word8
174byte :: Int -> Word64 -> Word8
@@ -207,7 +177,7 @@ byte i w = fromIntegral (w `shiftR` (i * 8))
207-- |Build a Word16 from two Word8 values, presented in big-endian order.
177-- |Build a Word16 from two Word8 values, presented in big-endian order.
208w8to16 :: Word8 -> Word8 -> Word16
178w8to16 :: Word8 -> Word8 -> Word16
209w8to16 w0s w1s =
179w8to16 w0s w1s =
210− (w0 `unsafeShiftL` 8) .|. w1
180+ (w0 `shiftL` 8) .|. w1
212 w0 = fromIntegral w0s
182 w0 = fromIntegral w0s
213 w1 = fromIntegral w1s
183 w1 = fromIntegral w1s
@@ -241,7 +211,7 @@ buildFromBytes v b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf =
241 where b6' = b6 .&. 0x0f .|. (v `shiftL` 4)
211 where b6' = b6 .&. 0x0f .|. (v `shiftL` 4)
242 b8' = b8 .&. 0x3f .|. 0x80
212 b8' = b8 .&. 0x3f .|. 0x80
244−-- |Build a UUID of a given version from 'Word32' values.
214+-- |Build a UUID of a given version from Word32 values.
245buildFromWords :: Word8 -> Word32 -> Word32 -> Word32 -> Word32 -> UUID
215buildFromWords :: Word8 -> Word32 -> Word32 -> Word32 -> Word32 -> UUID
246buildFromWords v w0 w1 w2 w3 = fromWords w0 w1' w2' w3
216buildFromWords v w0 w1 w2 w3 = fromWords w0 w1' w2' w3
247 where w1' = w1 .&. 0xffff0fff .|. ((fromIntegral v) `shiftL` 12)
217 where w1' = w1 .&. 0xffff0fff .|. ((fromIntegral v) `shiftL` 12)
@@ -275,8 +245,8 @@ null = (== nil)
275 -- null (UUID 0 0 0 0) = True
245 -- null (UUID 0 0 0 0) = True
276 -- null _ = False
246 -- null _ = False
278−-- |The 'nil' UUID, as defined in <http://tools.ietf.org/html/rfc4122 RFC 4122>.
248+-- |The nil UUID, as defined in RFC 4122.
279−-- It is a UUID of all zeros. @'null' u@ /iff/ @'u' == 'nil'@.
249+-- It is a UUID of all zeros. @'null' u@ iff @'u' == 'nil'@.
280nil :: UUID
250nil :: UUID
281nil = UUID 0 0
251nil = UUID 0 0
@@ -286,8 +256,6 @@ fromByteString :: BL.ByteString -> Maybe UUID
286fromByteString = fromList . BL.unpack
256fromByteString = fromList . BL.unpack
288-- |Encode a UUID into a 'ByteString' in network order.
258-- |Encode a UUID into a 'ByteString' in network order.
290−-- This uses the same encoding as the 'Binary' instance.
291toByteString :: UUID -> BL.ByteString
259toByteString :: UUID -> BL.ByteString
292toByteString = BL.pack . toList
260toByteString = BL.pack . toList
@@ -295,8 +263,9 @@ toByteString = BL.pack . toList
295-- The hyphens may not be omitted.
263-- The hyphens may not be omitted.
296-- Example:
264-- Example:
298−-- >>> fromString "c2cc10e1-57d6-4b6f-9899-38d972112d8c"
267+-- fromString \"c2cc10e1-57d6-4b6f-9899-38d972112d8c\"
299−-- Just c2cc10e1-57d6-4b6f-9899-38d972112d8c
268+-- @
301-- Hex digits may be upper or lower-case.
270-- Hex digits may be upper or lower-case.
302fromString :: String -> Maybe UUID
271fromString :: String -> Maybe UUID
@@ -328,39 +297,32 @@ fromString' s0 = do
328-- | Convert a UUID into a hypenated string using lower-case letters.
297-- | Convert a UUID into a hypenated string using lower-case letters.
329-- Example:
298-- Example:
331−-- >>> toString <$> fromString "550e8400-e29b-41d4-a716-446655440000"
301+-- toString \<$\> fromString \"550e8400-e29b-41d4-a716-446655440000\"
332−-- Just "550e8400-e29b-41d4-a716-446655440000"
302+-- @
335toString :: UUID -> String
303toString :: UUID -> String
336−toString uuid = hexw0 w0 $ hexw1 w1 ""
304+toString uuid = hexw w0 $ hexw' w1 $ hexw' w2 $ hexw w3 ""
337− where hexw0 :: Word64 -> String -> String
305+ where hexw :: Word32 -> 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
306+ hexw w s = 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
307+ : hexn w 12 : hexn w 8 : hexn w 4 : hexn w 0 : s
344− hexw1 :: Word64 -> String -> String
309+ hexw' :: Word32 -> String -> String
345− hexw1 w s = '-' : hexn w 60 : hexn w 56 : hexn w 52 : hexn w 48
310+ hexw' w s = '-' : hexn w 28 : hexn w 24 : hexn w 20 : hexn w 16
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
311+ : '-' : hexn w 12 : hexn w 8 : hexn w 4 : hexn w 0 : s
351− hexn :: Word64 -> Int -> Char
313+ hexn :: Word32 -> Int -> Char
352 hexn w r = intToDigit $ fromIntegral ((w `shiftR` r) .&. 0xf)
314 hexn w r = intToDigit $ fromIntegral ((w `shiftR` r) .&. 0xf)
354− (w0,w1) = toWords64 uuid
316+ (w0,w1,w2,w3) = toWords uuid
356-- | If the passed in `Text` can be parsed as an ASCII representation of
318-- | 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.
319-- a `UUID`, it will be. The hyphens may not be omitted.
358fromText :: Text -> Maybe UUID
320fromText :: Text -> Maybe UUID
359−fromText = fromASCIIBytes . T.encodeUtf8
321+fromText = fromString . T.unpack
361-- | Convert a UUID into a hyphentated string using lower-case letters.
323-- | Convert a UUID into a hyphentated string using lower-case letters.
362toText :: UUID -> Text
324toText :: UUID -> Text
363−toText = T.decodeLatin1 . toASCIIBytes
325+toText = T.pack . toString
365-- | Convert a UUID into a hyphentated string using lower-case letters, packed
327-- | Convert a UUID into a hyphentated string using lower-case letters, packed
366-- as ASCII bytes into `B.ByteString`.
328-- as ASCII bytes into `B.ByteString`.
@@ -455,30 +417,49 @@ fromASCIIBytes bs = do
455-- | Similar to `toASCIIBytes` except we produce a lazy `BL.ByteString`.
417-- | Similar to `toASCIIBytes` except we produce a lazy `BL.ByteString`.
456toLazyASCIIBytes :: UUID -> BL.ByteString
418toLazyASCIIBytes :: UUID -> BL.ByteString
457toLazyASCIIBytes =
419toLazyASCIIBytes =
420+#if MIN_VERSION_bytestring(0,10,0)
458 BL.fromStrict
421 BL.fromStrict
423+ BL.fromChunks . return
459 . toASCIIBytes
425 . toASCIIBytes
461-- | Similar to `fromASCIIBytes` except parses from a lazy `BL.ByteString`.
427-- | Similar to `fromASCIIBytes` except parses from a lazy `BL.ByteString`.
462fromLazyASCIIBytes :: BL.ByteString -> Maybe UUID
428fromLazyASCIIBytes :: BL.ByteString -> Maybe UUID
463fromLazyASCIIBytes bs =
429fromLazyASCIIBytes bs =
464− if BL.length bs == 36 then fromASCIIBytes (BL.toStrict bs) else Nothing
430+ if BL.length bs == 36 then fromASCIIBytes (
431+#if MIN_VERSION_bytestring(0,10,0)
434+ B.concat $ BL.toChunks bs
467-- Class Instances
439-- Class Instances
470−-- | This 'Random' instance produces __insecure__ version 4 UUIDs as
471−-- specified in <http://tools.ietf.org/html/rfc4122 RFC 4122>.
472instance Random UUID where
442instance Random UUID where
473− random = uniform
443+ random g = (fromGenNext w0 w1 w2 w3 w4, g4)
444+ where (w0, g0) = next g
474 randomR _ = random -- range is ignored
449 randomR _ = random -- range is ignored
476−-- @since 1.0.4
451+-- |Build a UUID from the results of five calls to next on a StdGen.
477−instance Uniform UUID where
452+-- While next on StdGet returns an Int, it doesn't provide 32 bits of
478− uniformM gen = do
453+-- randomness. This code relies on at last 28 bits of randomness in the
479− w0 <- uniformWord64 gen
454+-- and optimizes its use so as to make only five random values, not six.
480− w1 <- uniformWord64 gen
455+fromGenNext :: Int -> Int -> Int -> Int -> Int -> UUID
456+fromGenNext w0 w1 w2 w3 w4 =
481− pure $ buildFromBytes 4 /-/ w0 /-/ w1
457+ buildFromBytes 4 /-/ (ThreeByte w0)
459+ /-/ w2 -- use all 4 bytes because we know the version
460+ -- field will "cover" the upper, non-random bits
483-- |A ByteSource to extract only three bytes from an Int, since next on StdGet
464-- |A ByteSource to extract only three bytes from an Int, since next on StdGet
484-- only returns 31 bits of randomness.
465-- only returns 31 bits of randomness.
@@ -486,8 +467,8 @@ type instance ByteSink ThreeByte g = Takes3Bytes g
486newtype ThreeByte = ThreeByte Int
467newtype ThreeByte = ThreeByte Int
487instance ByteSource ThreeByte where
468instance ByteSource ThreeByte where
488 f /-/ (ThreeByte w) = f b1 b2 b3
469 f /-/ (ThreeByte w) = f b1 b2 b3
489− where b1 = fromIntegral (w `unsafeShiftR` 16)
470+ where b1 = fromIntegral (w `shiftR` 16)
490− b2 = fromIntegral (w `unsafeShiftR` 8)
471+ b2 = fromIntegral (w `shiftR` 8)
491 b3 = fromIntegral w
472 b3 = fromIntegral w
493instance NFData UUID where
474instance NFData UUID where
@@ -504,11 +485,6 @@ instance Hashable UUID where
504 `hashWithSalt` w2
485 `hashWithSalt` w2
505 `hashWithSalt` w3
486 `hashWithSalt` w3
507−-- | Pretty prints a 'UUID' (without quotation marks). See also 'toString'.
510−-- "00000000-0000-0000-0000-000000000000"
512instance Show UUID where
488instance Show UUID where
513 show = toString
489 show = toString
@@ -519,7 +495,7 @@ instance Read UUID where
519 Nothing -> []
495 Nothing -> []
520 Just u -> [(u,drop 36 noSpaces)]
496 Just u -> [(u,drop 36 noSpaces)]
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__.
498+
523instance Storable UUID where
499instance Storable UUID where
524 sizeOf _ = 16
500 sizeOf _ = 16
525 alignment _ = 4
501 alignment _ = 4
@@ -556,7 +532,6 @@ instance Storable UUID where
556 pokeByteOff p (off+14) x9
532 pokeByteOff p (off+14) x9
557 pokeByteOff p (off+15) x10
533 pokeByteOff p (off+15) x10
559−-- | This 'Binary' instance is compatible with <http://tools.ietf.org/html/rfc4122 RFC 4122>, storing the fields in network order as 16 bytes.
560instance Binary UUID where
535instance Binary UUID where
561 put (UUID w0 w1) = putWord64be w0 >> putWord64be w1
536 put (UUID w0 w1) = putWord64be w0 >> putWord64be w1
562 get = liftM2 UUID getWord64be getWord64be
537 get = liftM2 UUID getWord64be getWord64be
@@ -572,4 +547,13 @@ instance Data UUID where
572uuidType :: DataType
547uuidType :: DataType
573uuidType = mkNoRepType "Data.UUID.Types.UUID"
548uuidType = mkNoRepType "Data.UUID.Types.UUID"
575−deriving instance Lift UUID
550+#if !(MIN_VERSION_base(4,2,0))
551+mkNoRepType :: String -> DataType
552+mkNoRepType = mkNorepType
555+#if !MIN_VERSION_base(4,5,0)
556+unsafeShiftR, unsafeShiftL :: Word64 -> Int -> Word64
557+unsafeShiftR = shiftR
558+unsafeShiftL = shiftL