@@ -233,7 +233,7 @@ fromString' s0 = do
233-- Example:
233-- Example:
236−-- toString $ fromString \"550e8400-e29b-41d4-a716-446655440000\"
236+-- toString \<$\> fromString \"550e8400-e29b-41d4-a716-446655440000\"
238toString :: UUID -> String
238toString :: UUID -> String
239toString (UUID w0 w1 w2 w3) = hexw w0 $ hexw' w1 $ hexw' w2 $ hexw w3 ""
239toString (UUID w0 w1 w2 w3) = hexw w0 $ hexw' w1 $ hexw' w2 $ hexw w3 ""
@@ -248,6 +248,104 @@ toString (UUID w0 w1 w2 w3) = hexw w0 $ hexw' w1 $ hexw' w2 $ hexw w3 ""
248 hexn :: Word32 -> Int -> Char
248 hexn :: Word32 -> Int -> Char
249 hexn w r = intToDigit $ fromIntegral ((w `shiftR` r) .&. 0xf)
249 hexn w r = intToDigit $ fromIntegral ((w `shiftR` r) .&. 0xf)
251+-- | Convert a UUID into a hyphentated string using lower-case letters, packed
252+-- as ASCII bytes into `B.ByteString`.
254+-- This should be equivalent to `toString` with `Data.ByteString.Char8.pack`.
255+toASCIIBytes :: UUID -> B.ByteString
256+toASCIIBytes uuid = BI.unsafeCreate 36 (pokeASCII uuid)
258+-- | Helper function for `toASCIIBytes`
259+pokeASCII :: UUID -> Ptr Word8 -> IO ()
260+pokeASCII uuid ptr = do
270+ (w0, w1, w2, w3) = toWords uuid
273+ pokeDash ix = pokeElemOff ptr ix 45
275+ pokeSingle ix w = do
277+ pokeWord (ix + 1) w 24
278+ pokeWord (ix + 2) w 20
279+ pokeWord (ix + 3) w 16
280+ pokeWord (ix + 4) w 12
281+ pokeWord (ix + 5) w 8
282+ pokeWord (ix + 6) w 4
283+ pokeWord (ix + 7) w 0
285+ -- We skip the dash in the middle
286+ pokeDouble ix w = do
288+ pokeWord (ix + 1) w 24
289+ pokeWord (ix + 2) w 20
290+ pokeWord (ix + 3) w 16
291+ pokeWord (ix + 5) w 12
292+ pokeWord (ix + 6) w 8
293+ pokeWord (ix + 7) w 4
294+ pokeWord (ix + 8) w 0
297+ pokeElemOff ptr ix (fromIntegral (toDigit ((w `shiftR` r) .&. 0xf)))
299+ toDigit :: Word32 -> Word32
300+ toDigit w = if w < 10 then 48 + w else 97 + w - 10
302+-- | If the passed in `B.ByteString` can be parsed as an ASCII representation of
303+-- a `UUID`, it will be. The hyphens may not be omitted.
305+-- This should be equivalent to `fromString` with `Data.ByteString.Char8.unpack`.
306+fromASCIIBytes :: B.ByteString -> Maybe UUID
307+fromASCIIBytes bs = do
309+ fromWords <$> single 0 <*> double 9 14 <*> double 19 24 <*> single 28
312+ dashIx bs' ix = BU.unsafeIndex bs' ix == 45
314+ -- Important: check the length first, given the `unsafeIndex` later.
316+ B.length bs == 36 && dashIx bs 8 && dashIx bs 13 &&
317+ dashIx bs 18 && dashIx bs 23
319+ single ix = combine <$> octet ix <*> octet (ix + 2)
320+ <*> octet (ix + 4) <*> octet (ix + 6)
321+ double ix0 ix1 = combine <$> octet ix0 <*> octet (ix0 + 2)
322+ <*> octet ix1 <*> octet (ix1 + 2)
324+ combine o0 o1 o2 o3 = shiftL o0 24 .|. shiftL o1 16 .|. shiftL o2 8 .|. o3
327+ hi <- fromIntegral <$> toDigit (BU.unsafeIndex bs ix)
328+ lo <- fromIntegral <$> toDigit (BU.unsafeIndex bs (ix + 1))
329+ return (16 * hi + lo)
331+ toDigit :: Word8 -> Maybe Word8
334+ | w >= 48 && w <= 57 = Just (w - 48)
336+ | w >= 65 && w <= 70 = Just (10 + w - 65)
338+ | w >= 97 && w <= 102 = Just (10 + w - 97)
339+ | otherwise = Nothing
341+-- | Similar to `toASCIIBytes` except we produce a lazy `BL.ByteString`.
342+toLazyASCIIBytes :: UUID -> BL.ByteString
343+toLazyASCIIBytes = BL.fromStrict . toASCIIBytes
345+-- | Similar to `fromASCIIBytes` except parses from a lazy `BL.ByteString`.
346+fromLazyASCIIBytes :: BL.ByteString -> Maybe UUID
347+fromLazyASCIIBytes bs =
348+ if BL.length bs == 36 then fromASCIIBytes (BL.toStrict bs) else Nothing
253-- Class Instances
351-- Class Instances
@@ -285,6 +383,9 @@ instance ByteSource ThreeByte where
285 b2 = fromIntegral (w `shiftR` 8)
383 b2 = fromIntegral (w `shiftR` 8)
286 b3 = fromIntegral w
384 b3 = fromIntegral w
386+instance NFData UUID where
288instance Hashable UUID where
389instance Hashable UUID where
289 hash (UUID w0 w1 w2 w3) =
390 hash (UUID w0 w1 w2 w3) =
290 hash w0 `hashWithSalt` w1
391 hash w0 `hashWithSalt` w1
@@ -339,93 +440,3 @@ mkNoRepType :: String -> DataType
339mkNoRepType = mkNorepType
440mkNoRepType = mkNorepType
342−fromASCIIBytes :: B.ByteString -> Maybe UUID
343−fromASCIIBytes bs = do
345− fromWords <$> single 0 <*> double 9 14 <*> double 19 24 <*> single 28
348− dashIx bs' ix = BU.unsafeIndex bs' ix == 45
350− -- Important: check the length first, given the `unsafeIndex` later.
352− B.length bs == 36 && dashIx bs 8 && dashIx bs 13 &&
353− dashIx bs 18 && dashIx bs 23
355− single ix = combine <$> octet ix <*> octet (ix + 2)
356− <*> octet (ix + 4) <*> octet (ix + 6)
357− double ix0 ix1 = combine <$> octet ix0 <*> octet (ix0 + 2)
358− <*> octet ix1 <*> octet (ix1 + 2)
360− combine o0 o1 o2 o3 = shiftL o0 24 .|. shiftL o1 16 .|. shiftL o2 8 .|. o3
363− hi <- fromIntegral <$> toDigit (BU.unsafeIndex bs ix)
364− lo <- fromIntegral <$> toDigit (BU.unsafeIndex bs (ix + 1))
365− return (16 * hi + lo)
367− toDigit :: Word8 -> Maybe Word8
370− | w >= 48 && w <= 57 = Just (w - 48)
372− | w >= 65 && w <= 70 = Just (10 + w - 65)
374− | w >= 97 && w <= 102 = Just (10 + w - 97)
375− | otherwise = Nothing
377−toASCIIBytes :: UUID -> B.ByteString
378−toASCIIBytes uuid = BI.unsafeCreate 36 (pokeASCII uuid)
380−pokeASCII :: UUID -> Ptr Word8 -> IO ()
381−pokeASCII uuid ptr = do
391− (w0, w1, w2, w3) = toWords uuid
394− pokeDash ix = pokeElemOff ptr ix 45
396− pokeSingle ix w = do
398− pokeWord (ix + 1) w 24
399− pokeWord (ix + 2) w 20
400− pokeWord (ix + 3) w 16
401− pokeWord (ix + 4) w 12
402− pokeWord (ix + 5) w 8
403− pokeWord (ix + 6) w 4
404− pokeWord (ix + 7) w 0
406− -- We skip the dash in the middle
407− pokeDouble ix w = do
409− pokeWord (ix + 1) w 24
410− pokeWord (ix + 2) w 20
411− pokeWord (ix + 3) w 16
412− pokeWord (ix + 5) w 12
413− pokeWord (ix + 6) w 8
414− pokeWord (ix + 7) w 4
415− pokeWord (ix + 8) w 0
418− pokeElemOff ptr ix (fromIntegral (toDigit ((w `shiftR` r) .&. 0xf)))
420− toDigit :: Word32 -> Word32
421− toDigit w = if w < 10 then 48 + w else 97 + w - 10
423−fromLazyASCIIBytes :: BL.ByteString -> Maybe UUID
424−fromLazyASCIIBytes bs =
425− if BL.length bs == 36 then fromASCIIBytes (BL.toStrict bs) else Nothing
427−toLazyASCIIBytes :: UUID -> BL.ByteString
428−toLazyASCIIBytes = BL.fromStrict . toASCIIBytes
430−instance NFData UUID where