@@ -1,5 +1,13 @@
1−{-# INCLUDE "cbits.h" #-}
1+{-# INCLUDE <uuid/uuid.h> #-}
2−{-# LANGUAGE ForeignFunctionInterface, CPP #-}
2+{-# LANGUAGE ForeignFunctionInterface #-}
4+-- |Haskell bindings to /libuuid/.
5+-- The library /libuuid/ is available as a part of e2fsprogs:
6+-- <http://e2fsprogs.sourceforge.net/>.
8+-- This library is useful for creating, comparing, parsing and
9+-- printing Universally Unique Identifiers.
10+-- See <http://en.wikipedia.org/wiki/UUID> for the general idea.
4module Data.UUID(UUID
12module Data.UUID(UUID
5 ,fromString
13 ,fromString
@@ -15,156 +23,157 @@ where
16import Foreign.C.String
24import Foreign.C.String
17import Foreign.C
25import Foreign.C
26+import Foreign.ForeignPtr
18import Foreign
27import Foreign
22import Prelude hiding (null)
29import Prelude hiding (null)
24−#if defined(__GLASGOW_HASKELL__)
31+import Data.UUID.Internal
25−import GHC.Base (unsafeChr)
28−newtype UUID = U C_UUID
32instance Eq UUID where
33instance Eq UUID where
33− (U a) == (U b) = c_compare a b == 0
34+ a == b = compare a b == EQ
35instance Ord UUID where
36instance Ord UUID where
36− compare (U p1) (U p2) =
37+ compare (U fp1) (U fp2) = unsafePerformIO $
38+ withForeignPtr fp1 $ \p1 ->
39+ withForeignPtr fp2 $ \p2 ->
37 case c_compare p1 p2 of
40 case c_compare p1 p2 of
38− 0 -> EQ
41+ 0 -> return EQ
39− n|n<0 -> LT
42+ n|n<0 -> return LT
40− |n>0 -> GT
43+ |n>0 -> return GT
42instance Show UUID where
45instance Show UUID where
43 show = toString
46 show = toString
48+instance Read UUID where
49+ readsPrec _ str = case fromString (take 36 str) of
51+ Just u -> [(u,drop 36 str)]
53+-- |Creates a new 'UUID'. If \/dev\/urandom is available, it will be used.
54+-- Otherwise a UUID will be generated based on the current time and the
55+-- hardware MAC address, if available.
45generate :: IO UUID
56generate :: IO UUID
46generate = do
57generate = do
47− p <- mallocBytes 16
58+ fp <- mallocForeignPtrArray 16
48− c_generate p
59+ withForeignPtr fp $ \p -> c_generate p
49− return $ U p
60+ return $ U fp
62+-- |Create a new 'UUID'. If \/dev\/urandom is available, it will be used.
63+-- Otherwise a psuedorandom generator will be used.
51generateRandom :: IO UUID
64generateRandom :: IO UUID
52generateRandom = do
65generateRandom = do
53− p <- mallocBytes 16
66+ fp <- mallocForeignPtrArray 16
54− c_generate_random p
67+ withForeignPtr fp $ \p -> c_generate_random p
55− return $ U p
68+ return $ U fp
70+-- |Create a new 'UUID'. The UUID will be generated based on the
71+-- current time and the hardware MAC address, if available.
57generateTime :: IO UUID
72generateTime :: IO UUID
58generateTime = do
73generateTime = do
59− p <- mallocBytes 16
74+ fp <- mallocForeignPtrArray 16
60− c_generate_time p
75+ withForeignPtr fp $ \p -> c_generate_time p
61− return $ U p
76+ return $ U fp
78+-- |Returns 'True' if the passed-in 'UUID' is the null UUID.
63null :: UUID -> Bool
79null :: UUID -> Bool
80+null (U fp) = unsafePerformIO $
81+ withForeignPtr fp $ \p ->
64−null (U p) = c_null p /= 0
82+ return $ c_null p == 1
84+-- |If the passed in 'String' can be parsed as a 'UUID', it will be.
85+-- The hyphens may not be ommited.
89+-- fromString \"c2cc10e1-57d6-4b6f-9899-38d972112d8c\"
92+-- Hex digits may be upper or lower-case.
66fromString :: String -> Maybe UUID
93fromString :: String -> Maybe UUID
67fromString s = unsafePerformIO $ do
94fromString s = unsafePerformIO $ do
68− p <- mallocBytes 16
95+ fp <- mallocForeignPtrArray 16
69− chars <- mallocBytes 37
96+ res <- withCString s $ \chars ->
70− pack 0 s chars
97+ withForeignPtr fp $ \p ->
71− res <- c_read p (castPtr chars)
98+ c_read (castPtr chars) p
72 case res of
99 case res of
73− 0 -> return . Just $ U p
100+ 0 -> return . Just $ U fp
74 _ -> return Nothing
101 _ -> return Nothing
76−pack :: Int -> String -> Ptr Word8 -> IO ()
103+-- |Returns a 'String' representation of the passed in UUID.
77−pack 37 _ p = pokeByteOff p 37 (0 :: Word8)
104+-- Hex digits occuring in the output will be either upper or
78−pack n (c:cs) p = do
105+-- lower-case depending on system defaults and locale.
79− pokeByteOff p n (c2w c)
81−pack n [] p = pokeByteOff p n (0 :: Word8)
83−unpack :: Ptr Word8 -> Int -> IO String
84−unpack p 37 = return []
91− return $ (w2c c) : cs
93toString :: UUID -> String
106toString :: UUID -> String
94−toString (U p) = unsafePerformIO $ do
107+toString (U fp) = unsafePerformIO $ do
95 chars <- mallocBytes 37
108 chars <- mallocBytes 37
96− c_show p chars
109+ withForeignPtr fp $ \p -> c_show p chars
97− unpack (castPtr chars) 0
110+ st <- peekCString chars
114+-- |Returns a 'String' representation of the passed in UUID.
115+-- Hex digits occuring in the output will be lower-case.
99toStringLower :: UUID -> String
116toStringLower :: UUID -> String
100−toStringLower (U p) = unsafePerformIO $ do
117+toStringLower (U fp) = unsafePerformIO $ do
101 chars <- mallocBytes 37
118 chars <- mallocBytes 37
102− c_show_lower p chars
119+ withForeignPtr fp $ \p -> c_show_lower p chars
103− unpack (castPtr chars) 0
120+ st <- peekCString chars
124+-- |Returns a 'String' representation of the passed in UUID.
125+-- Hex digits occuring in the output will be upper-case.
105toStringUpper :: UUID -> String
126toStringUpper :: UUID -> String
106−toStringUpper (U p) = unsafePerformIO $ do
127+toStringUpper (U fp) = unsafePerformIO $ do
107 chars <- mallocBytes 37
128 chars <- mallocBytes 37
108− c_show_upper p chars
129+ withForeignPtr fp $ \p -> c_show_upper p chars
109− unpack (castPtr chars) 0
130+ st <- peekCString chars
111−-- | Conversion between 'Word8' and 'Char'. Should compile to a no-op.
132+ return st
112−-- Shamelessly stolen from the 'bytestring' package.
133+
113−w2c :: Word8 -> Char
134+
114−#if !defined(__GLASGOW_HASKELL__)
135+-- FFI calls to do the work
115−w2c = chr . fromIntegral
136+
116−#else
137+type C_UUID = Ptr CChar
117−w2c = unsafeChr . fromIntegral
121−-- | Unsafe conversion between 'Char' and 'Word8'. This is a no-op and
122−-- silently truncates to 8 bits Chars > '\255'. It is provided as
123−-- convenience for ByteString construction.
124−-- Shamelessly stolen from the 'bytestring' package.
126−c2w = fromIntegral . ord
129-- comparing UUIDs
139-- comparing UUIDs
130−foreign import ccall unsafe "c_compare"
140+foreign import ccall unsafe "uuid_compare"
131 c_compare :: C_UUID -> C_UUID -> CInt
141 c_compare :: C_UUID -> C_UUID -> CInt
133-- making random UUIDs
143-- making random UUIDs
134−foreign import ccall unsafe "c_generate"
144+foreign import ccall unsafe "uuid_generate"
135 c_generate :: C_UUID -> IO ()
145 c_generate :: C_UUID -> IO ()
137−foreign import ccall unsafe "c_generate_time"
147+foreign import ccall unsafe "uuid_generate_time"
138 c_generate_time :: C_UUID -> IO ()
148 c_generate_time :: C_UUID -> IO ()
140−foreign import ccall unsafe "c_generate_random"
150+foreign import ccall unsafe "uuid_generate_random"
141 c_generate_random :: C_UUID -> IO ()
151 c_generate_random :: C_UUID -> IO ()
143-- Null check
153-- Null check
144−foreign import ccall unsafe "c_null"
154+foreign import ccall unsafe "uuid_is_null"
145 c_null :: C_UUID -> CInt
155 c_null :: C_UUID -> CInt
148-- Parsing
157-- Parsing
149−foreign import ccall unsafe "c_read"
158+foreign import ccall unsafe "uuid_parse"
150− c_read :: C_UUID -> CString ->IO CInt
159+ c_read :: CString -> C_UUID ->IO CInt
152-- Showing
161-- Showing
154−foreign import ccall unsafe "c_show"
163+foreign import ccall unsafe "uuid_unparse"
155 c_show :: C_UUID -> CString -> IO ()
164 c_show :: C_UUID -> CString -> IO ()
157−foreign import ccall unsafe "c_show_lower"
166+foreign import ccall unsafe "uuid_unparse_lower"
158 c_show_lower :: C_UUID -> CString -> IO ()
167 c_show_lower :: C_UUID -> CString -> IO ()
160−foreign import ccall unsafe "c_show_upper"
169+foreign import ccall unsafe "uuid_unparse_upper"
161 c_show_upper :: C_UUID -> CString -> IO ()
170 c_show_upper :: C_UUID -> CString -> IO ()
164-- Queries
173-- Queries
166−foreign import ccall unsafe "c_type"
175+foreign import ccall unsafe "uuid_type"
167 c_type :: C_UUID -> CInt
176 c_type :: C_UUID -> CInt
169−foreign import ccall unsafe "c_variant"
178+foreign import ccall unsafe "uuid_variant"
170 c_variant :: C_UUID -> CInt
179 c_variant :: C_UUID -> CInt