1{-# LANGUAGE DeriveDataTypeable #-}
5-- Copyright : (c) 2008 Antoine Latter
9-- Maintainer : aslatter@gmail.com
10-- Stability : experimental
11-- Portability : portable
13module Data.UUID.Internal
29import Data.List (splitAt, foldl', unfoldr)
32import Data.Generics.Basics
35import Foreign.Storable
45-- |The UUID type. A 'Random' instance is provided which produces
46-- version 3 UUIDs as specified in RFC 4122. The 'Storable' and
47-- 'Binary' instances are compatable with RFC 4122. The 'Binary'
48-- instance serializes to network byte order.
50 {uuid_timeLow :: {-# UNPACK #-} !Word32
51 ,uuid_timeMid :: {-# UNPACK #-} !Word16
52 ,uuid_timeHigh :: {-# UNPACK #-} !Word16 -- includes version number
53 ,uuid_clockSeqHi :: {-# UNPACK #-} !Word8 -- includes reserved field
54 ,uuid_clokcSeqLow :: {-# UNPACK #-} !Word8
55 ,uuid_node :: {-# UNPACK #-} !Node
56 } deriving (Eq, Ord, Typeable)
58instance Random UUID where
59 random g = let (timeLow, g1) = randomBoundedIntegral g
60 (timeMid, g2) = randomBoundedIntegral g1
61 (timeHigh, g3) = randomBoundedIntegral g2
62 (seqHigh, g4) = randomBoundedIntegral g3
63 (seqLow, g5) = randomBoundedIntegral g4
64 (node, g6) = random g5
65 seqHighReserved = (seqHigh .&. reservedMask) .|. reserved
66 timeHighVersion = (timeHigh .&. versionMask) .|. versionRandom
67 in (UUID timeLow timeMid timeHighVersion seqHighReserved seqLow node, g6)
69 randomR _ = random -- range is ignored
71versionMask :: Word16 -- 0000 1111 1111 1111
74versionRandom :: Word16
75versionRandom = shiftL 12 4
77reservedMask :: Word8 -- 0011 1111
90 deriving (Eq, Ord, Typeable)
92instance Random Node where
93 random g = let (w1, g1) = randomBoundedIntegral g
94 (w2, g2) = randomBoundedIntegral g1
95 (w3, g3) = randomBoundedIntegral g2
96 (w4, g4) = randomBoundedIntegral g3
97 (w5, g5) = randomBoundedIntegral g4
98 (w6, g6) = randomBoundedIntegral g5
99 in (Node w1 w2 w3 w4 w5 w6, g6)
100 randomR _ = random -- neglect range
103nodeToList :: Node -> [Word8]
104nodeToList (Node w1 w2 w3 w4 w5 w6) = [w1, w2, w3, w4, w5, w6]
106listToNode :: [Word8] -> Maybe Node
107listToNode [w1, w2, w3, w4, w5, w6] = return $ Node w1 w2 w3 w4 w5 w6
108listToNode _ = Nothing
110instance Show UUID where
113instance Read UUID where
114 readsPrec _ str = case fromString (take 36 str) of
116 Just u -> [(u,drop 36 str)]
119instance Storable UUID where
121 alignment _ = 4 -- not sure what to put here
124 tl <- peek $ castPtr p
125 tm <- peekByteOff p 4
126 th <- peekByteOff p 6
127 ch <- peekByteOff p 8
128 cl <- peekByteOff p 9
129 node <- peekByteOff p 10
130 return $ UUID tl tm th ch cl node
132 poke p (UUID tl tm th ch cl node) = do
138 pokeByteOff p 10 node
140instance Storable Node where
142 alignment _ = 1 -- ???
145 w1 <- peek $ castPtr p
146 w2 <- peekByteOff p 1
147 w3 <- peekByteOff p 2
148 w4 <- peekByteOff p 3
149 w5 <- peekByteOff p 4
150 w6 <- peekByteOff p 5
151 return $ Node w1 w2 w3 w4 w5 w6
153 poke p (Node w1 w2 w3 w4 w5 w6) = do
161-- Binary instance in network byte-order
162instance Binary UUID where
163 put (UUID tl tm th ch cl n) = do
178 return $ UUID tl tm th ch cl node
180instance Binary Node where
181 put (Node w1 w2 w3 w4 w5 w6) = do
196 return $ Node w1 w2 w3 w4 w5 w6
199-- My goal with this instance was to make it work just enough to do what
200-- I want when used with the HStringTemplate library.
201instance Data UUID where
202 toConstr uu = mkConstr uuidType (show uu) [] (error "fixity")
203 gunfold _ _ = error "gunfold"
204 dataTypeOf _ = uuidType
206uuidType = mkNorepType "Data.UUID.UUID"
211-- |If the passed in 'String' can be parsed as a 'UUID', it will be.
212-- The hyphens may not be omitted.
216-- fromString \"c2cc10e1-57d6-4b6f-9899-38d972112d8c\"
219-- Hex digits may be upper or lower-case.
220fromString :: String -> Maybe UUID
221fromString xs | validFmt = Just uuid
222 | otherwise = Nothing
223 where validFmt = length ws == 5 &&
224 map length ws == [8,4,4,4,12] &&
225 all isHexDigit (concat ws) &&
227 ws = splitList '-' xs
228 [tl, tm, th, c, n] = ws
229 ns = unfoldUntil Prelude.null (splitAt 2) n :: [String]
230 node = listToNode $ map hexVal ns :: Maybe Node
231 uuid = UUID (hexVal tl) (hexVal tm) (hexVal th) (hexVal $ take 2 c) (hexVal $ drop 2 c) (fromJust $ node)
233-- | Convert a string to a hex value, assuming the string is already validated.
234hexVal :: Num a => String -> a
235hexVal = fromInteger . foldl' (\n c -> 16*n + digitToInteger c) 0
237digitToInteger :: Char -> Integer
238digitToInteger = fromIntegral . digitToInt
241-- | Convert a UUID into a hypenated string using lower-case letters.
245-- toString $ fromString \"550e8400-e29b-41d4-a716-446655440000\"
247toString :: UUID -> String
248toString (UUID tl tm th ch cl n) = printf "%08x-%04x-%04x-%02x%02x-%s" tl tm th ch cl ns
249 where ns = concatMap hexb $ nodeToList n
250 hexb x = printf "%02x" x :: String
253-- remove all occurances of the input element in the inpt list.
254-- non of the sub-lists are empty.
255splitList :: Eq a => a -> [a] -> [[a]]
256splitList c xs = let ys = dropWhile (== c) xs
257 in case span (/= c) ys of
259 (sub,rest) -> sub : splitList c rest
261unfoldUntil :: (b -> Bool) -> (b -> (a, b)) -> b -> [a]
262unfoldUntil p f n = unfoldr g n
263 where g m | p m = Nothing
264 | otherwise = Just $ f m
267-- no random intance for Data.Word types :-(
268-- this will work, though
270randomBoundedIntegral :: (RandomGen g, Bounded a, Integral a) => g -> (a, g)
271randomBoundedIntegral g = let (n, g1) = randomR (fromIntegral l, fromIntegral u) g
273 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