1{-# LANGUAGE DeriveDataTypeable #-}
5-- Copyright : (c) 2008 Antoine Latter
9-- Maintainer : aslatter@gmail.com
10-- Stability : experimental
11-- Portability : portable
14-- This library is useful for creating, comparing, parsing and
15-- printing Universally Unique Identifiers.
16-- See <http://en.wikipedia.org/wiki/UUID> for the general idea.
37import Data.Generics.Basics
43import Prelude hiding (null)
44import qualified Prelude
46import Data.List (splitAt, foldl', unfoldr)
49import Foreign.Storable
53 {uuid_timeLow :: {-# UNPACK #-} !Word32
54 ,uuid_timeMid :: {-# UNPACK #-} !Word16
55 ,uuid_timeHigh :: {-# UNPACK #-} !Word16 -- includes version number
56 ,uuid_clockSeqHi :: {-# UNPACK #-} !Word8 -- includes reserved field
57 ,uuid_clokcSeqLow :: {-# UNPACK #-} !Word8
58 ,uuid_node :: {-# UNPACK #-} !Node
59 } deriving (Eq, Ord, Typeable)
61instance Random UUID where
62 random g = let (timeLow, g1) = random g
63 (timeMid, g2) = random g1
64 (timeHigh, g3) = random g2
65 (seqHigh, g4) = random g3
66 (seqLow, g5) = random g4
67 (node, g6) = random g5
68 seqHighReserved = (seqHigh .&. reservedMask) .|. reserved
69 timeHighVersion = (timeHigh .&. versionMask) .|. versionRandom
70 in (UUID timeLow timeMid timeHighVersion seqHighReserved seqLow node, g6)
72 randomR _ = random -- range is ignored
74versionMask :: Word16 -- 0000 1111 1111 1111
77versionRandom :: Word16
78versionRandom = shiftL 12 4
80reservedMask :: Word8 -- 0011 1111
93 deriving (Eq, Ord, Typeable)
95instance Random Node where
96 random g = let (w1, g1) = random g
102 in (Node w1 w2 w3 w4 w5 w6, g6)
103 randomR _ = random -- neglect range
105nodeToList :: Node -> [Word8]
106nodeToList (Node w1 w2 w3 w4 w5 w6) = [w1, w2, w3, w4, w5, w6]
108listToNode :: [Word8] -> Maybe Node
109listToNode [w1, w2, w3, w4, w5, w6] = return $ Node w1 w2 w3 w4 w5 w6
110listToNode _ = Nothing
112instance Show UUID where
115instance Read UUID where
116 readsPrec _ str = case fromString (take 36 str) of
118 Just u -> [(u,drop 36 str)]
121instance Storable UUID where
123 alignment _ = 4 -- not sure what to put here
126 tl <- peek $ castPtr p
127 tm <- peekByteOff (castPtr p) 4
128 th <- peekByteOff (castPtr p) 6
129 ch <- peekByteOff (castPtr p) 8
130 cl <- peekByteOff (castPtr p) 9
131 node <- peekByteOff (castPtr p) 10
132 return $ UUID tl tm th ch cl node
134 poke p (UUID tl tm th ch cl node) = do
136 pokeByteOff (castPtr p) 4 tm
137 pokeByteOff (castPtr p) 6 th
138 pokeByteOff (castPtr p) 8 ch
139 pokeByteOff (castPtr p) 9 cl
140 pokeByteOff (castPtr p) 10 node
142instance Storable Node where
144 alignment _ = 1 -- ???
147 w1 <- peek $ castPtr p
148 w2 <- peekByteOff (castPtr p) 1
149 w3 <- peekByteOff (castPtr p) 2
150 w4 <- peekByteOff (castPtr p) 3
151 w5 <- peekByteOff (castPtr p) 4
152 w6 <- peekByteOff (castPtr p) 5
153 return $ Node w1 w2 w3 w4 w5 w6
155 poke p (Node w1 w2 w3 w4 w5 w6) = do
157 pokeByteOff (castPtr p) 1 w2
158 pokeByteOff (castPtr p) 2 w3
159 pokeByteOff (castPtr p) 3 w4
160 pokeByteOff (castPtr p) 4 w5
161 pokeByteOff (castPtr p) 5 w6
163-- My goal with this instance was to make it work just enough to do what
164-- I want when used with the HStringTemplate library.
165instance Data UUID where
166 toConstr uu = mkConstr uuidType (show uu) [] (error "fixity")
167 gunfold _ _ = error "gunfold"
168 dataTypeOf _ = uuidType
170uuidType = mkNorepType "Data.UUID.UUID"
173-- |Creates a new 'UUID'. If \/dev\/urandom is available, it will be used.
174-- Otherwise a UUID will be generated based on the current time and the
175-- hardware MAC address, if available.
177generate = generateRandom
179-- |Create a new 'UUID'. If \/dev\/urandom is available, it will be used.
180-- Otherwise a psuedorandom generator will be used.
181generateRandom :: IO UUID
182generateRandom = randomIO -- not a good solution, as someone could have changed the global generator
184-- |Create a new 'UUID'. The UUID will be generated based on the
185-- current time and the hardware MAC address, if available.
186generateTime :: IO UUID
187generateTime = error "Data.UUID.generateTime: not yet implemented"
189-- |Returns 'True' if the passed-in 'UUID' is the null UUID.
192 where nullUuid = UUID 0 0 0 0 0 $ Node 0 0 0 0 0 0
195-- |If the passed in 'String' can be parsed as a 'UUID', it will be.
196-- The hyphens may not be omitted.
200-- fromString \"c2cc10e1-57d6-4b6f-9899-38d972112d8c\"
203-- Hex digits may be upper or lower-case.
204fromString :: String -> Maybe UUID
205fromString xs | validFmt = Just uuid
206 | otherwise = Nothing
207 where validFmt = length ws == 5 &&
208 map length ws == [8,4,4,4,12] &&
209 all isHexDigit (concat ws) &&
211 ws = splitList '-' xs
212 [tl, tm, th, c, n] = ws
213 ns = unfoldUntil Prelude.null (splitAt 2) n :: [String]
214 node = listToNode $ map hexVal ns :: Maybe Node
215 uuid = UUID (hexVal tl) (hexVal tm) (hexVal th) (hexVal $ take 2 c) (hexVal $ drop 2 c) (fromJust $ node)
217-- | Convert a string to a hex value, assuming the string is already validated.
218hexVal :: Num a => String -> a
219hexVal = fromInteger . foldl' (\n c -> 16*n + digitToInteger c) 0
221digitToInteger :: Char -> Integer
222digitToInteger = fromIntegral . digitToInt
224-- |Returns a 'String' representation of the passed in 'UUID'.
225-- Hex digits occuring in the output will be either upper or
226-- lower-case depending on system defaults and locale.
227toString :: UUID -> String
228toString = toStringLower
231-- | Convert a UUID into a hypenated string using upper-case letters.
232-- example: toStringUpper $ fromString "550e8400-e29b-41d4-a716-446655440000"
233toStringUpper :: UUID -> String
234toStringUpper (UUID tl tm th ch cl n) = printf "%08X-%04X-%04X-%02X%02X-%s" tl tm th ch cl ns
235 where ns = concatMap hexb $ nodeToList n
236 hexb x = printf "%02X" x :: String
238-- | Convert a UUID into a hypenated string using lower-case letters.
239-- example: toStringLower $ fromString "550e8400-e29b-41d4-a716-446655440000"
240toStringLower :: UUID -> String
241toStringLower (UUID tl tm th ch cl n) = printf "%08x-%04x-%04x-%02x%02x-%s" tl tm th ch cl ns
242 where ns = concatMap hexb $ nodeToList n
243 hexb x = printf "%02x" x :: String
245-- remove all occurances of the input element in the inpt list.
246-- non of the sub-lists are empty.
247splitList :: Eq a => a -> [a] -> [[a]]
248splitList c xs = let ys = dropWhile (== c) xs
249 in case span (/= c) ys of
251 (sub,rest) -> sub : splitList c rest
253unfoldUntil :: (b -> Bool) -> (b -> (a, b)) -> b -> [a]
254unfoldUntil p f n = unfoldr g n
255 where g m = case p m of
259-- I'm not sure how fast these instances are, but they'll do for now.
261instance Random Word8 where
262 random g = randomBoundedIntegral g
263 randomR r g = randomRIntegral r g
265instance Random Word16 where
266 random g = randomBoundedIntegral g
267 randomR r g = randomRIntegral r g
269instance Random Word32 where
270 random g = randomBoundedIntegral g
271 randomR r g = randomRIntegral r g
273randomBoundedIntegral :: (RandomGen g, Bounded a, Integral a) => g -> (a, g)
274randomBoundedIntegral g = let (n, g1) = randomR (fromIntegral l, fromIntegral u) g
276 retVal = fromIntegral n `asTypeOf` (l `asTypeOf` u)
281randomRIntegral :: (RandomGen g, Integral a) => (a, a) -> g -> (a, g)
282randomRIntegral (l, u) g = let (val, g1) = randomR (fromIntegral l, fromIntegral u) g
284 in (fromIntegral val, g1)
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