1{-# LANGUAGE DeriveDataTypeable, CPP #-}
5-- Copyright : (c) 2008 Antoine Latter
9-- Maintainer : aslatter@gmail.com
10-- Stability : experimental
11-- Portability : portable
13module Data.UUID.Internal
30import Prelude hiding (null)
31import qualified Prelude
37import Data.List (splitAt, foldl', unfoldr)
41#if MIN_VERSION_base(4,0,0)
44import Data.Generics.Basics
48import Foreign.Storable
53import qualified Data.ByteString.Lazy as Lazy
62#define SLOT(x) {-# UNPACK #-} !x
65-- |The UUID type. A 'Random' instance is provided which produces
66-- version 4 UUIDs as specified in RFC 4122. The 'Storable' and
67-- 'Binary' instances are compatable with RFC 4122. The 'Binary'
68-- instance serializes to network byte order.
70 {uuid_timeLow :: SLOT(Word32)
71 ,uuid_timeMid :: SLOT(Word16)
72 ,uuid_timeHigh :: SLOT(Word16) -- includes version number
73 ,uuid_clockSeqHi :: SLOT(Word8) -- includes reserved field
74 ,uuid_clokcSeqLow :: SLOT(Word8)
75 ,uuid_node :: SLOT(Node)
76 } deriving (Eq, Ord, Typeable)
78-- |Returns true if the passed-in UUID is the 'nil' UUID.
80null (UUID 0 0 0 0 0 node) | nullNode node = True
83-- |The nil UUID, as defined in RFC 4122.
84-- It is a UUID of all zeros. @'null' u@ iff @'u' == 'nil'@.
86nil = UUID 0 0 0 0 0 (Node 0 0 0 0 0 0)
88instance Random UUID where
89 random g = let (timeLow, g1) = randomBoundedIntegral g
90 (timeMid, g2) = randomBoundedIntegral g1
91 (timeHigh, g3) = randomBoundedIntegral g2
92 (seqHigh, g4) = randomBoundedIntegral g3
93 (seqLow, g5) = randomBoundedIntegral g4
94 (node, g6) = random g5
95 seqHighReserved = (seqHigh .&. reservedMask) .|. reserved
96 timeHighVersion = (timeHigh .&. versionMask) .|. versionRandom
97 in (UUID timeLow timeMid timeHighVersion seqHighReserved seqLow node, g6)
99 randomR _ = random -- range is ignored
101versionMask :: Word16 -- 0000 1111 1111 1111
104versionRandom :: Word16
105versionRandom = 4 `shiftL` 12
107reservedMask :: Word8 -- 0011 1111
120 deriving (Eq, Ord, Typeable)
122instance Random Node where
123 random g = let (w1, g1) = randomBoundedIntegral g
124 (w2, g2) = randomBoundedIntegral g1
125 (w3, g3) = randomBoundedIntegral g2
126 (w4, g4) = randomBoundedIntegral g3
127 (w5, g5) = randomBoundedIntegral g4
128 (w6, g6) = randomBoundedIntegral g5
129 in (Node w1 w2 w3 w4 w5 w6, g6)
130 randomR _ = random -- neglect range
132nullNode :: Node -> Bool
133nullNode (Node 0 0 0 0 0 0) = True
136nodeToList :: Node -> [Word8]
137nodeToList (Node w1 w2 w3 w4 w5 w6) = [w1, w2, w3, w4, w5, w6]
139listToNode :: [Word8] -> Maybe Node
140listToNode [w1, w2, w3, w4, w5, w6] = return $ Node w1 w2 w3 w4 w5 w6
141listToNode _ = Nothing
143instance Show UUID where
146instance Read UUID where
147 readsPrec _ str = case fromString (take 36 str) of
149 Just u -> [(u,drop 36 str)]
152instance Storable UUID where
154 alignment _ = 4 -- not sure what to put here
157 tl <- peek $ castPtr p
158 tm <- peekByteOff p 4
159 th <- peekByteOff p 6
160 ch <- peekByteOff p 8
161 cl <- peekByteOff p 9
162 node <- peekByteOff p 10
163 return $ UUID tl tm th ch cl node
165 poke p (UUID tl tm th ch cl node) = do
171 pokeByteOff p 10 node
173instance Storable Node where
175 alignment _ = 1 -- ???
178 w1 <- peek $ castPtr p
179 w2 <- peekByteOff p 1
180 w3 <- peekByteOff p 2
181 w4 <- peekByteOff p 3
182 w5 <- peekByteOff p 4
183 w6 <- peekByteOff p 5
184 return $ Node w1 w2 w3 w4 w5 w6
186 poke p (Node w1 w2 w3 w4 w5 w6) = do
194-- Binary instance in network byte-order
195instance Binary UUID where
196 put (UUID tl tm th ch cl n) = do
211 return $ UUID tl tm th ch cl node
213instance Binary Node where
214 put (Node w1 w2 w3 w4 w5 w6) = do
229 return $ Node w1 w2 w3 w4 w5 w6
232-- |Extract a UUID from a 'ByteString' in network byte order.
233-- The argument must be 16 bytes long, otherwise 'Nothing' is returned.
234fromByteString :: Lazy.ByteString -> Maybe UUID
235fromByteString bs | Lazy.length bs == 16 = Just $ decode bs
236 | otherwise = Nothing
238-- |Encode a UUID into a 'ByteString' in network order.
239toByteString :: UUID -> Lazy.ByteString
240toByteString uu = encode uu
242-- My goal with this instance was to make it work just enough to do what
243-- I want when used with the HStringTemplate library.
244instance Data UUID where
245 toConstr uu = mkConstr uuidType (show uu) [] (error "fixity")
246 gunfold _ _ = error "gunfold"
247 dataTypeOf _ = uuidType
249uuidType = mkNorepType "Data.UUID.UUID"
254-- |If the passed in 'String' can be parsed as a 'UUID', it will be.
255-- The hyphens may not be omitted.
259-- fromString \"c2cc10e1-57d6-4b6f-9899-38d972112d8c\"
262-- Hex digits may be upper or lower-case.
263fromString :: String -> Maybe UUID
264fromString xs | validFmt = Just uuid
265 | otherwise = Nothing
266 where validFmt = length ws == 5 &&
267 map length ws == [8,4,4,4,12] &&
268 all isHexDigit (concat ws) &&
270 ws = splitList '-' xs
271 [tl, tm, th, c, n] = ws
272 ns = unfoldUntil Prelude.null (splitAt 2) n :: [String]
273 node = listToNode $ map hexVal ns :: Maybe Node
274 uuid = UUID (hexVal tl) (hexVal tm) (hexVal th) (hexVal $ take 2 c) (hexVal $ drop 2 c) (fromJust $ node)
276-- | Convert a string to a hex value, assuming the string is already validated.
277hexVal :: Num a => String -> a
278hexVal = fromInteger . foldl' (\n c -> 16*n + digitToInteger c) 0
280digitToInteger :: Char -> Integer
281digitToInteger = fromIntegral . digitToInt
284-- | Convert a UUID into a hypenated string using lower-case letters.
288-- toString $ fromString \"550e8400-e29b-41d4-a716-446655440000\"
290toString :: UUID -> String
291toString (UUID tl tm th ch cl n) = printf "%08x-%04x-%04x-%02x%02x-%s" tl tm th ch cl ns
292 where ns = concatMap hexb $ nodeToList n
293 hexb x = printf "%02x" x :: String
296-- remove all occurances of the input element in the inpt list.
297-- none of the sub-lists are empty.
298splitList :: Eq a => a -> [a] -> [[a]]
299splitList c xs = let ys = dropWhile (== c) xs
300 in case span (/= c) ys of
302 (sub,rest) -> sub : splitList c rest
304-- the passed-in predicate signals when to stop unfolding
305unfoldUntil :: (b -> Bool) -> (b -> (a, b)) -> b -> [a]
306unfoldUntil p f n = unfoldr g n
307 where g m | p m = Nothing
308 | otherwise = Just $ f m
311-- no random intance for Data.Word types :-(
312-- this will work, though
314randomBoundedIntegral :: (RandomGen g, Bounded a, Integral a) => g -> (a, g)
315randomBoundedIntegral g =
316 let (n, g1) = randomR (fromIntegral l, fromIntegral u) g
318 retVal = fromIntegral n `asTypeOf` (l `asTypeOf` u)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list