1*273c26a3SBaptiste Daroussin{-# LANGUAGE ForeignFunctionInterface #-} 2*273c26a3SBaptiste Daroussin 3*273c26a3SBaptiste Daroussin-- an example UCL FFI module: 4*273c26a3SBaptiste Daroussin-- uses the Object Model from Messagepack to emit 5*273c26a3SBaptiste Daroussin-- 6*273c26a3SBaptiste Daroussin 7*273c26a3SBaptiste Daroussinmodule Data.UCL ( unpack ) where 8*273c26a3SBaptiste Daroussinimport Foreign.C 9*273c26a3SBaptiste Daroussinimport Foreign.Ptr 10*273c26a3SBaptiste Daroussinimport System.IO.Unsafe ( unsafePerformIO ) 11*273c26a3SBaptiste Daroussinimport qualified Data.Text as T 12*273c26a3SBaptiste Daroussinimport qualified Data.Vector as V 13*273c26a3SBaptiste Daroussinimport qualified Data.MessagePack as MSG 14*273c26a3SBaptiste Daroussin 15*273c26a3SBaptiste Daroussintype ParserHandle = Ptr () 16*273c26a3SBaptiste Daroussintype UCLObjectHandle = Ptr () 17*273c26a3SBaptiste Daroussintype UCLIterHandle = Ptr () 18*273c26a3SBaptiste Daroussintype UCLEmitterType = CInt 19*273c26a3SBaptiste Daroussintype ErrorString = String 20*273c26a3SBaptiste Daroussin 21*273c26a3SBaptiste Daroussin 22*273c26a3SBaptiste Daroussinforeign import ccall "ucl_parser_new" ucl_parser_new :: CInt -> ParserHandle 23*273c26a3SBaptiste Daroussinforeign import ccall "ucl_parser_add_string" ucl_parser_add_string :: ParserHandle -> CString -> CUInt -> IO Bool 24*273c26a3SBaptiste Daroussinforeign import ccall "ucl_parser_add_file" ucl_parser_add_file :: ParserHandle -> CString -> IO Bool 25*273c26a3SBaptiste Daroussinforeign import ccall "ucl_parser_get_object" ucl_parser_get_object :: ParserHandle -> UCLObjectHandle 26*273c26a3SBaptiste Daroussinforeign import ccall "ucl_parser_get_error" ucl_parser_get_error :: ParserHandle -> CString 27*273c26a3SBaptiste Daroussin 28*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_iterate_new" ucl_object_iterate_new :: UCLObjectHandle -> UCLIterHandle 29*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_iterate_safe" ucl_object_iterate_safe :: UCLIterHandle -> Bool -> UCLObjectHandle 30*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_type" ucl_object_type :: UCLObjectHandle -> CUInt 31*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_key" ucl_object_key :: UCLObjectHandle -> CString 32*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_toint" ucl_object_toint :: UCLObjectHandle -> CInt 33*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_todouble" ucl_object_todouble :: UCLObjectHandle -> CDouble 34*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_tostring" ucl_object_tostring :: UCLObjectHandle -> CString 35*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_toboolean" ucl_object_toboolean :: UCLObjectHandle -> Bool 36*273c26a3SBaptiste Daroussin 37*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_emit" ucl_object_emit :: UCLObjectHandle -> UCLEmitterType -> CString 38*273c26a3SBaptiste Daroussinforeign import ccall "ucl_object_emit_len" ucl_object_emit_len :: UCLObjectHandle -> UCLEmitterType -> Ptr CSize -> IO CString 39*273c26a3SBaptiste Daroussin 40*273c26a3SBaptiste Daroussintype UCL_TYPE = CUInt 41*273c26a3SBaptiste Daroussinucl_OBJECT :: UCL_TYPE 42*273c26a3SBaptiste Daroussinucl_OBJECT = 0 43*273c26a3SBaptiste Daroussinucl_ARRAY :: UCL_TYPE 44*273c26a3SBaptiste Daroussinucl_ARRAY = 1 45*273c26a3SBaptiste Daroussinucl_INT :: UCL_TYPE 46*273c26a3SBaptiste Daroussinucl_INT = 2 47*273c26a3SBaptiste Daroussinucl_FLOAT :: UCL_TYPE 48*273c26a3SBaptiste Daroussinucl_FLOAT = 3 49*273c26a3SBaptiste Daroussinucl_STRING :: UCL_TYPE 50*273c26a3SBaptiste Daroussinucl_STRING = 4 51*273c26a3SBaptiste Daroussinucl_BOOLEAN :: UCL_TYPE 52*273c26a3SBaptiste Daroussinucl_BOOLEAN = 5 53*273c26a3SBaptiste Daroussinucl_TIME :: UCL_TYPE 54*273c26a3SBaptiste Daroussinucl_TIME = 6 55*273c26a3SBaptiste Daroussinucl_USERDATA :: UCL_TYPE 56*273c26a3SBaptiste Daroussinucl_USERDATA = 7 57*273c26a3SBaptiste Daroussinucl_NULL :: UCL_TYPE 58*273c26a3SBaptiste Daroussinucl_NULL = 8 59*273c26a3SBaptiste Daroussin 60*273c26a3SBaptiste Daroussinucl_emit_json :: UCLEmitterType 61*273c26a3SBaptiste Daroussinucl_emit_json = 0 62*273c26a3SBaptiste Daroussinucl_emit_json_compact :: UCLEmitterType 63*273c26a3SBaptiste Daroussinucl_emit_json_compact = 1 :: UCLEmitterType 64*273c26a3SBaptiste Daroussinucl_emit_msgpack :: UCLEmitterType 65*273c26a3SBaptiste Daroussinucl_emit_msgpack = 4 :: UCLEmitterType 66*273c26a3SBaptiste Daroussin 67*273c26a3SBaptiste Daroussinucl_parser_parse_string_pure :: String -> Either UCLObjectHandle ErrorString 68*273c26a3SBaptiste Daroussinucl_parser_parse_string_pure s = unsafePerformIO $ do 69*273c26a3SBaptiste Daroussin cs <- newCString s 70*273c26a3SBaptiste Daroussin let p = ucl_parser_new 0x4 71*273c26a3SBaptiste Daroussin didParse <- ucl_parser_add_string p cs (toEnum $ length s) 72*273c26a3SBaptiste Daroussin if didParse 73*273c26a3SBaptiste Daroussin then return $ Left $ ucl_parser_get_object p 74*273c26a3SBaptiste Daroussin else Right <$> peekCString ( ucl_parser_get_error p) 75*273c26a3SBaptiste Daroussin 76*273c26a3SBaptiste Daroussinucl_parser_add_file_pure :: String -> Either UCLObjectHandle ErrorString 77*273c26a3SBaptiste Daroussinucl_parser_add_file_pure s = unsafePerformIO $ do 78*273c26a3SBaptiste Daroussin cs <- newCString s 79*273c26a3SBaptiste Daroussin let p = ucl_parser_new 0x4 80*273c26a3SBaptiste Daroussin didParse <- ucl_parser_add_file p cs 81*273c26a3SBaptiste Daroussin if didParse 82*273c26a3SBaptiste Daroussin then return $ Left $ ucl_parser_get_object p 83*273c26a3SBaptiste Daroussin else Right <$> peekCString ( ucl_parser_get_error p) 84*273c26a3SBaptiste Daroussin 85*273c26a3SBaptiste Daroussinunpack :: MSG.MessagePack a => String -> Either a ErrorString 86*273c26a3SBaptiste Daroussinunpack s = case ucl_parser_parse_string_pure s of 87*273c26a3SBaptiste Daroussin (Right err) -> Right err 88*273c26a3SBaptiste Daroussin (Left obj) -> case MSG.fromObject (ucl_to_msgpack_object obj) of 89*273c26a3SBaptiste Daroussin Nothing -> Right "MessagePack fromObject Error" 90*273c26a3SBaptiste Daroussin (Just a) -> Left a 91*273c26a3SBaptiste Daroussin 92*273c26a3SBaptiste Daroussinucl_to_msgpack_object :: UCLObjectHandle -> MSG.Object 93*273c26a3SBaptiste Daroussinucl_to_msgpack_object o = toMsgPackObj (ucl_object_type o) o 94*273c26a3SBaptiste Daroussin where 95*273c26a3SBaptiste Daroussin toMsgPackObj n obj 96*273c26a3SBaptiste Daroussin |n==ucl_OBJECT = MSG.ObjectMap $ uclObjectToVector obj 97*273c26a3SBaptiste Daroussin |n==ucl_ARRAY = MSG.ObjectArray undefined 98*273c26a3SBaptiste Daroussin |n==ucl_INT = MSG.ObjectInt $ fromEnum $ ucl_object_toint obj 99*273c26a3SBaptiste Daroussin |n==ucl_FLOAT = MSG.ObjectDouble $ realToFrac $ ucl_object_todouble obj 100*273c26a3SBaptiste Daroussin |n==ucl_STRING = MSG.ObjectStr $ T.pack $ unsafePerformIO $ peekCString $ ucl_object_tostring obj 101*273c26a3SBaptiste Daroussin |n==ucl_BOOLEAN = MSG.ObjectBool $ ucl_object_toboolean obj 102*273c26a3SBaptiste Daroussin |n==ucl_TIME = error "time undefined" 103*273c26a3SBaptiste Daroussin |n==ucl_USERDATA = error "userdata undefined" 104*273c26a3SBaptiste Daroussin |n==ucl_NULL = error "null undefined" 105*273c26a3SBaptiste Daroussin |otherwise = error "\"Unknown Type\" Error" 106*273c26a3SBaptiste Daroussin 107*273c26a3SBaptiste DaroussinuclObjectToVector :: UCLObjectHandle -> V.Vector (MSG.Object,MSG.Object) 108*273c26a3SBaptiste DaroussinuclObjectToVector o = iterateObject (ucl_object_iterate_safe iter True ) iter V.empty 109*273c26a3SBaptiste Daroussin where 110*273c26a3SBaptiste Daroussin iter = ucl_object_iterate_new o 111*273c26a3SBaptiste Daroussin iterateObject obj it vec = if ucl_object_type obj == ucl_NULL 112*273c26a3SBaptiste Daroussin then vec 113*273c26a3SBaptiste Daroussin else iterateObject (ucl_object_iterate_safe it True) it (V.snoc vec ( getUclKey obj , ucl_to_msgpack_object obj)) 114*273c26a3SBaptiste Daroussin getUclKey obj = MSG.ObjectStr $ T.pack $ unsafePerformIO $ peekCString $ ucl_object_key obj 115*273c26a3SBaptiste Daroussin 116*273c26a3SBaptiste DaroussinuclArrayToVector :: UCLObjectHandle -> V.Vector MSG.Object 117*273c26a3SBaptiste DaroussinuclArrayToVector o = iterateArray (ucl_object_iterate_safe iter True ) iter V.empty 118*273c26a3SBaptiste Daroussin where 119*273c26a3SBaptiste Daroussin iter = ucl_object_iterate_new o 120*273c26a3SBaptiste Daroussin iterateArray obj it vec = if ucl_object_type obj == ucl_NULL 121*273c26a3SBaptiste Daroussin then vec 122*273c26a3SBaptiste Daroussin else iterateArray (ucl_object_iterate_safe it True) it (V.snoc vec (ucl_to_msgpack_object obj)) 123*273c26a3SBaptiste Daroussin 124