packages feed

dbus 1.0.1 → 1.1.0

raw patch · 8 files changed

+244/−251 lines, 8 filesdep +conduitdep +exceptionsdep +xml-conduitdep −libxml-saxdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: conduit, exceptions, xml-conduit

Dependencies removed: libxml-sax

Dependency ranges changed: base

API changes (from Hackage documentation)

- DBus.Client: instance GHC.Exception.Exception DBus.Client.ClientError
- DBus.Client: instance GHC.Exception.Exception DBus.Client.MethodExc
- DBus.Internal.Types: instance GHC.Exception.Exception DBus.Internal.Types.SigParseError
- DBus.Socket: instance GHC.Exception.Exception DBus.Socket.SocketError
- DBus.Transport: instance GHC.Exception.Exception DBus.Transport.TransportError
- DBus.Transport: socketTransportOptionBacklog :: TransportOptions SocketTransport -> Int
+ DBus.Client: instance GHC.Exception.Type.Exception DBus.Client.ClientError
+ DBus.Client: instance GHC.Exception.Type.Exception DBus.Client.MethodExc
+ DBus.Internal.Types: instance GHC.Exception.Type.Exception DBus.Internal.Types.SigParseError
+ DBus.Socket: instance GHC.Exception.Type.Exception DBus.Socket.SocketError
+ DBus.Transport: -- a connection.
+ DBus.Transport: -- | Used for transports that listen on a port or address.
+ DBus.Transport: instance GHC.Exception.Type.Exception DBus.Transport.TransportError
- DBus: parseBusName :: String -> Maybe BusName
+ DBus: parseBusName :: MonadThrow m => String -> m BusName
- DBus: parseErrorName :: String -> Maybe ErrorName
+ DBus: parseErrorName :: MonadThrow m => String -> m ErrorName
- DBus: parseInterfaceName :: String -> Maybe InterfaceName
+ DBus: parseInterfaceName :: MonadThrow m => String -> m InterfaceName
- DBus: parseMemberName :: String -> Maybe MemberName
+ DBus: parseMemberName :: MonadThrow m => String -> m MemberName
- DBus: parseObjectPath :: String -> Maybe ObjectPath
+ DBus: parseObjectPath :: MonadThrow m => String -> m ObjectPath
- DBus: parseSignature :: String -> Maybe Signature
+ DBus: parseSignature :: MonadThrow m => String -> m Signature
- DBus.Client: autoMethod :: (AutoMethod fn) => MemberName -> fn -> Method
+ DBus.Client: autoMethod :: AutoMethod fn => MemberName -> fn -> Method
- DBus.Client: autoMethodWithMsg :: (AutoMethod fn) => MemberName -> (MethodCall -> fn) -> Method
+ DBus.Client: autoMethodWithMsg :: AutoMethod fn => MemberName -> (MethodCall -> fn) -> Method
- DBus.Client: autoProperty :: forall v. (IsValue v) => MemberName -> Maybe (IO v) -> Maybe (v -> IO ()) -> Property
+ DBus.Client: autoProperty :: forall v. IsValue v => MemberName -> Maybe (IO v) -> Maybe (v -> IO ()) -> Property
- DBus.Client: readOnlyProperty :: (IsValue v) => MemberName -> IO v -> Property
+ DBus.Client: readOnlyProperty :: IsValue v => MemberName -> IO v -> Property
- DBus.Internal.Address: Address :: String -> (Map String String) -> Address
+ DBus.Internal.Address: Address :: String -> Map String String -> Address
- DBus.Internal.Types: Array :: Type -> (Vector Value) -> Array
+ DBus.Internal.Types: Array :: Type -> Vector Value -> Array
- DBus.Internal.Types: Dictionary :: Type -> Type -> (Map Atom Value) -> Dictionary
+ DBus.Internal.Types: Dictionary :: Type -> Type -> Map Atom Value -> Dictionary
- DBus.Internal.Types: ValueMap :: Type -> Type -> (Map Atom Value) -> Value
+ DBus.Internal.Types: ValueMap :: Type -> Type -> Map Atom Value -> Value
- DBus.Internal.Types: ValueVector :: Type -> (Vector Value) -> Value
+ DBus.Internal.Types: ValueVector :: Type -> Vector Value -> Value
- DBus.Internal.Types: maybeParseString :: Parser a -> String -> Maybe a
+ DBus.Internal.Types: maybeParseString :: MonadThrow m => Parser a -> String -> m a
- DBus.Internal.Types: parseBusName :: String -> Maybe BusName
+ DBus.Internal.Types: parseBusName :: MonadThrow m => String -> m BusName
- DBus.Internal.Types: parseErrorName :: String -> Maybe ErrorName
+ DBus.Internal.Types: parseErrorName :: MonadThrow m => String -> m ErrorName
- DBus.Internal.Types: parseInterfaceName :: String -> Maybe InterfaceName
+ DBus.Internal.Types: parseInterfaceName :: MonadThrow m => String -> m InterfaceName
- DBus.Internal.Types: parseMemberName :: String -> Maybe MemberName
+ DBus.Internal.Types: parseMemberName :: MonadThrow m => String -> m MemberName
- DBus.Internal.Types: parseObjectPath :: String -> Maybe ObjectPath
+ DBus.Internal.Types: parseObjectPath :: MonadThrow m => String -> m ObjectPath
- DBus.Internal.Types: parseSigFast :: ByteString -> Maybe Signature
+ DBus.Internal.Types: parseSigFast :: MonadThrow m => ByteString -> m Signature
- DBus.Internal.Types: parseSigFull :: ByteString -> Maybe Signature
+ DBus.Internal.Types: parseSigFull :: MonadThrow m => ByteString -> m Signature
- DBus.Internal.Types: parseSignature :: String -> Maybe Signature
+ DBus.Internal.Types: parseSignature :: MonadThrow m => String -> m Signature
- DBus.Internal.Types: parseSignatureBytes :: ByteString -> Maybe Signature
+ DBus.Internal.Types: parseSignatureBytes :: MonadThrow m => ByteString -> m Signature
- DBus.Internal.Types: peekWord8AsInt :: Ptr Word8 -> Int -> IO Int
+ DBus.Internal.Types: peekWord8AsInt :: ByteString -> Int -> Int

Files

benchmarks/DBusBenchmarks.hs view
@@ -40,13 +40,16 @@ benchUnmarshal name msg = bench name (whnf unmarshal bytes) where     Right bytes = marshal LittleEndian (serial 0) msg +parseSig :: String -> Maybe Signature+parseSig = parseSignature+ benchmarks :: [Benchmark] benchmarks =     [  bgroup "Types"         [ bgroup "Signature"-            [ bench "parseSignature/small" (nf parseSignature "y")-            , bench "parseSignature/medium" (nf parseSignature "yyyyuua(yv)")-            , bench "parseSignature/large" (nf parseSignature "a{s(asiiiiasa(siiia{s(iiiiv)}))}")+            [ bench "parseSignature/small" (nf parseSig "y")+            , bench "parseSignature/medium" (nf parseSig "yyyyuua(yv)")+            , bench "parseSignature/large" (nf parseSig "a{s(asiiiiasa(siiia{s(iiiiv)}))}")             ]         , bgroup "ObjectPath"             [ bench "objectPath_/small" (nf objectPath_ "/")
dbus.cabal view
@@ -1,5 +1,5 @@ name: dbus-version: 1.0.1+version: 1.1.0 license: Apache-2.0 license-file: license.txt author: John Millikin <john@john-millikin.com>@@ -83,11 +83,12 @@       base >=4 && <5     , bytestring     , cereal+    , conduit     , containers     , deepseq+    , exceptions     , filepath     , lens-    , libxml-sax     , network     , parsec     , random@@ -98,6 +99,7 @@     , transformers     , unix     , vector+    , xml-conduit     , xml-types    exposed-modules:@@ -128,7 +130,6 @@     , directory     , extra     , filepath-    , libxml-sax     , network     , parsec     , process@@ -142,7 +143,6 @@     , transformers     , unix     , vector-    , xml-types    other-modules:     DBusTests.Address
lib/DBus/Generation.hs view
@@ -356,7 +356,7 @@           buildSignature $ AppT (ConT ''IO) $                          AppT (AppT (ConT ''Either)                                       (ConT ''M.MethodError)) $ getArgType propType-        setterSigType = buildSignature $+        setterSigType = buildSignature $ addTypeArg (getArgType propType) $                         AppT (ConT ''IO) $ AppT (ConT ''Maybe) (ConT ''M.MethodError)         buildArgs rest = clientN:addArgIf takeBusArg busN                          (addArgIf takeObjectPathArg objectPathN rest)
lib/DBus/Internal/Types.hs view
@@ -1,15 +1,11 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE IncoherentInstances #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeSynonymInstances #-}  -- Copyright (C) 2009-2012 John Millikin <john@john-millikin.com>------ This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- any later version.@@ -25,13 +21,11 @@ module DBus.Internal.Types where  import           Control.DeepSeq-import           Control.Exception (Exception, handle, throwIO) import           Control.Monad (liftM, when, (>=>))-import qualified Data.ByteString-import           Data.ByteString (ByteString)-import qualified Data.ByteString.Char8 as Char8-import qualified Data.ByteString.Lazy-import qualified Data.ByteString.Unsafe+import           Control.Monad.Catch+import qualified Data.ByteString as BS+import qualified Data.ByteString.Char8 as BS8+import qualified Data.ByteString.Lazy as BL import           Data.Char (ord) import           Data.Coerce import           Data.Int@@ -47,10 +41,8 @@ import qualified Data.Vector import           Data.Vector (Vector) import           Data.Word-import qualified Foreign import           GHC.Generics import qualified Language.Haskell.TH.Lift as THL-import           System.IO.Unsafe (unsafePerformIO) import           System.Posix.Types (Fd) import           Text.ParserCombinators.Parsec ((<|>), oneOf) import qualified Text.ParserCombinators.Parsec as Parsec@@ -188,29 +180,29 @@  -- | Parse a signature string into a valid signature. ----- Returns @Nothing@ if the given string is not a valid signature.-parseSignature :: String -> Maybe Signature+-- Throws if the given string is not a valid signature.+parseSignature :: MonadThrow m => String -> m Signature parseSignature s = do-    when (length s > 255) Nothing-    when (any (\c -> ord c > 0x7F) s) Nothing-    parseSignatureBytes (Char8.pack s)+    when (length s > 255) $ throwM $ userError "string too long"+    when (any (\c -> ord c > 0x7F) s) $ throwM $ userError "invalid signature"+    parseSignatureBytes (BS8.pack s) -parseSignatureBytes :: ByteString -> Maybe Signature+parseSignatureBytes :: MonadThrow m => BS.ByteString -> m Signature parseSignatureBytes bytes =-    case Data.ByteString.length bytes of-        0 -> Just (Signature [])+    case BS.length bytes of+        0 -> pure (Signature [])         1 -> parseSigFast bytes         len | len <= 255 -> parseSigFull bytes-        _ -> Nothing+        _ -> throwM $ userError "string too long" -parseSigFast :: ByteString -> Maybe Signature+parseSigFast :: MonadThrow m => BS.ByteString -> m Signature parseSigFast bytes =-    let byte = Data.ByteString.Unsafe.unsafeHead bytes in-    parseAtom (fromIntegral byte)-        (\t -> Just (Signature [t]))-        (case byte of-            0x76 -> Just (Signature [TypeVariant])-            _ -> Nothing)+    let byte = BS.head bytes+     in parseAtom (fromIntegral byte)+            (\t -> pure (Signature [t]))+            (case byte of+                0x76 -> pure (Signature [TypeVariant])+                _ -> throwM $ userError "invalid signature")  parseAtom :: Int -> (Type -> a) -> a -> a parseAtom byte yes no = case byte of@@ -235,94 +227,82 @@  instance Exception SigParseError -peekWord8AsInt :: Foreign.Ptr Word8 -> Int -> IO Int-peekWord8AsInt ptr off = do-    w <- Foreign.peekElemOff ptr off-    return (fromIntegral w)--parseSigFull :: ByteString -> Maybe Signature-parseSigFull bytes = unsafePerformIO io where-    io = handle-        (\SigParseError -> return Nothing)-        $ Data.ByteString.Unsafe.unsafeUseAsCStringLen bytes-        $ \(ptr, len) -> do-            ts <- parseSigBuf (Foreign.castPtr ptr, len)-            return (Just (Signature ts))+peekWord8AsInt :: BS.ByteString -> Int -> Int+peekWord8AsInt str i = fromIntegral $ BS.index str i -    parseSigBuf (buf, len) = mainLoop [] 0 where+parseSigFull :: MonadThrow m => BS.ByteString -> m Signature+parseSigFull bytes = Signature <$> mainLoop [] 0+  where+    len = BS.length bytes+    mainLoop acc ii | ii >= len = pure (reverse acc)+    mainLoop acc ii = do+        let c = peekWord8AsInt bytes ii+        let next t = mainLoop (t : acc) (ii + 1)+        parseAtom c next $ case c of+            0x76 -> next TypeVariant+            0x28 -> do -- '('+                (ii', t) <- structure (ii + 1)+                mainLoop (t : acc) ii'+            0x61 -> do -- 'a'+                (ii', t) <- array (ii + 1)+                mainLoop (t : acc) ii'+            _ -> throwM SigParseError -        mainLoop acc ii | ii >= len = return (reverse acc)-        mainLoop acc ii = do-            c <- peekWord8AsInt buf ii-            let next t = mainLoop (t : acc) (ii + 1)+    structure = loop [] where+        loop _ ii | ii >= len = throwM SigParseError+        loop acc ii = do+            let c = peekWord8AsInt bytes ii+            let next t = loop (t : acc) (ii + 1)             parseAtom c next $ case c of                 0x76 -> next TypeVariant                 0x28 -> do -- '('                     (ii', t) <- structure (ii + 1)-                    mainLoop (t : acc) ii'+                    loop (t : acc) ii'                 0x61 -> do -- 'a'                     (ii', t) <- array (ii + 1)-                    mainLoop (t : acc) ii'-                _ -> throwIO SigParseError--        structure :: Int -> IO (Int, Type)-        structure = loop [] where-            loop _ ii | ii >= len = throwIO SigParseError-            loop acc ii = do-                c <- peekWord8AsInt buf ii-                let next t = loop (t : acc) (ii + 1)-                parseAtom c next $ case c of-                    0x76 -> next TypeVariant-                    0x28 -> do -- '('-                        (ii', t) <- structure (ii + 1)-                        loop (t : acc) ii'-                    0x61 -> do -- 'a'-                        (ii', t) <- array (ii + 1)-                        loop (t : acc) ii'-                    -- ')'-                    0x29 -> case acc of-                        [] -> throwIO SigParseError-                        _ -> return (ii + 1, TypeStructure (reverse acc))-                    _ -> throwIO SigParseError+                    loop (t : acc) ii'+                -- ')'+                0x29 -> case acc of+                    [] -> throwM SigParseError+                    _ -> pure (ii + 1, TypeStructure (reverse acc))+                _ -> throwM SigParseError -        array :: Int -> IO (Int, Type)-        array ii | ii >= len = throwIO SigParseError-        array ii = do-            c <- peekWord8AsInt buf ii-            let next t = return (ii + 1, TypeArray t)-            parseAtom c next $ case c of-                0x76 -> next TypeVariant-                0x7B -> dict (ii + 1) -- '{'-                0x28 -> do -- '('-                    (ii', t) <- structure (ii + 1)-                    return (ii', TypeArray t)-                0x61 -> do -- 'a'-                    (ii', t) <- array (ii + 1)-                    return (ii', TypeArray t)-                _ -> throwIO SigParseError+    array ii | ii >= len = throwM SigParseError+    array ii = do+        let c = peekWord8AsInt bytes ii+        let next t = pure (ii + 1, TypeArray t)+        parseAtom c next $ case c of+            0x76 -> next TypeVariant+            0x7B -> dict (ii + 1) -- '{'+            0x28 -> do -- '('+                (ii', t) <- structure (ii + 1)+                pure (ii', TypeArray t)+            0x61 -> do -- 'a'+                (ii', t) <- array (ii + 1)+                pure (ii', TypeArray t)+            _ -> throwM SigParseError -        dict :: Int -> IO (Int, Type)-        dict ii | ii + 1 >= len = throwIO SigParseError-        dict ii = do-            c1 <- peekWord8AsInt buf ii-            c2 <- peekWord8AsInt buf (ii + 1)+    dict ii | ii + 1 >= len = throwM SigParseError+    dict ii = do+        let c1 = peekWord8AsInt bytes ii+        let c2 = peekWord8AsInt bytes (ii + 1) -            let next t = return (ii + 2, t)-            (ii', t2) <- parseAtom c2 next $ case c2 of-                0x76 -> next TypeVariant-                0x28 -> structure (ii + 2) -- '('-                0x61 -> array (ii + 2) -- 'a'-                _ -> throwIO SigParseError+        let next t = pure (ii + 2, t)+        (ii', t2) <- parseAtom c2 next $ case c2 of+            0x76 -> next TypeVariant+            0x28 -> structure (ii + 2) -- '('+            0x61 -> array (ii + 2) -- 'a'+            _ -> throwM SigParseError -            if ii' >= len-                then throwIO SigParseError-                else do-                    c3 <- peekWord8AsInt buf ii'-                    if c3 == 0x7D-                        then do-                            t1 <- parseAtom c1 return (throwIO SigParseError)-                            return (ii' + 1, TypeDictionary t1 t2)-                        else throwIO SigParseError+        if ii' >= len+            then throwM SigParseError+            else do+                let c3 = peekWord8AsInt bytes ii'+                if c3 == 0x7D+                    then do+                        t1 <- parseAtom c1 pure (throwM SigParseError)+                        pure (ii' + 1, TypeDictionary t1 t2)+                    else throwM SigParseError  extractFromVariant :: IsValue a => Variant -> Maybe a extractFromVariant (Variant (ValueVariant v)) = extractFromVariant v@@ -359,7 +339,7 @@ data Value     = ValueAtom Atom     | ValueVariant Variant-    | ValueBytes ByteString+    | ValueBytes BS.ByteString     | ValueVector Type (Vector Value)     | ValueMap Type Type (Map Atom Value)     | ValueStructure [Value]@@ -427,8 +407,8 @@ showThings :: String -> (a -> String) -> String -> [a] -> String showThings a s z xs = a ++ intercalate ", " (map s xs) ++ z -vectorToBytes :: Vector Value -> ByteString-vectorToBytes = Data.ByteString.pack+vectorToBytes :: Vector Value -> BS.ByteString+vectorToBytes = BS.pack               . Data.Vector.toList               . Data.Vector.map (\(ValueAtom (AtomWord8 x)) -> x) @@ -556,26 +536,26 @@     toVariant = toVariant . Data.Vector.fromList     fromVariant = fmap Data.Vector.toList . fromVariant -instance IsValue ByteString where+instance IsValue BS.ByteString where     typeOf _ = TypeArray TypeWord8     toValue = ValueBytes     fromValue (ValueBytes bs) = Just bs     fromValue (ValueVector TypeWord8 v) = Just (vectorToBytes v)     fromValue _ = Nothing -instance IsVariant ByteString where+instance IsVariant BS.ByteString where     toVariant = Variant . toValue     fromVariant (Variant val) = fromValue val -instance IsValue Data.ByteString.Lazy.ByteString where+instance IsValue BL.ByteString where     typeOf _ = TypeArray TypeWord8     toValue = toValue-            . Data.ByteString.concat-            . Data.ByteString.Lazy.toChunks-    fromValue = fmap (\bs -> Data.ByteString.Lazy.fromChunks [bs])+            . BS.concat+            . BL.toChunks+    fromValue = fmap (\bs -> BL.fromChunks [bs])               . fromValue -instance IsVariant Data.ByteString.Lazy.ByteString where+instance IsVariant BL.ByteString where     toVariant = Variant . toValue     fromVariant (Variant val) = fromValue val @@ -663,7 +643,7 @@ formatObjectPath :: ObjectPath -> String formatObjectPath (ObjectPath s) = s -parseObjectPath :: String -> Maybe ObjectPath+parseObjectPath :: MonadThrow m => String -> m ObjectPath parseObjectPath s = do     maybeParseString parserObjectPath s     return (ObjectPath s)@@ -706,9 +686,9 @@ formatInterfaceName :: InterfaceName -> String formatInterfaceName (InterfaceName s) = s -parseInterfaceName :: String -> Maybe InterfaceName+parseInterfaceName :: MonadThrow m => String -> m InterfaceName parseInterfaceName s = do-    when (length s > 255) Nothing+    when (length s > 255) $ throwM $ userError "name too long"     maybeParseString parserInterfaceName s     return (InterfaceName s) @@ -746,9 +726,9 @@ formatMemberName :: MemberName -> String formatMemberName (MemberName s) = s -parseMemberName :: String -> Maybe MemberName+parseMemberName :: MonadThrow m => String -> m MemberName parseMemberName s = do-    when (length s > 255) Nothing+    when (length s > 255) $ throwM $ userError "name too long"     maybeParseString parserMemberName s     return (MemberName s) @@ -783,9 +763,9 @@ formatErrorName :: ErrorName -> String formatErrorName (ErrorName s) = s -parseErrorName :: String -> Maybe ErrorName+parseErrorName :: MonadThrow m => String -> m ErrorName parseErrorName s = do-    when (length s > 255) Nothing+    when (length s > 255) $ throwM $ userError "name too long"     maybeParseString parserInterfaceName s     return (ErrorName s) @@ -813,9 +793,9 @@ formatBusName :: BusName -> String formatBusName (BusName s) = s -parseBusName :: String -> Maybe BusName+parseBusName :: MonadThrow m => String -> m BusName parseBusName s = do-    when (length s > 255) Nothing+    when (length s > 255) $ throwM $ userError "name too long"     maybeParseString parserBusName s     return (BusName s) @@ -883,7 +863,7 @@ -- 'IsValue'. data Array     = Array Type (Vector Value)-    | ArrayBytes ByteString+    | ArrayBytes BS.ByteString  instance Show Array where     show (Array t xs) = showValue True (ValueVector t xs)@@ -904,7 +884,7 @@  arrayItems :: Array -> [Variant] arrayItems (Array _ xs) = map Variant (Data.Vector.toList xs)-arrayItems (ArrayBytes bs) = map toVariant (Data.ByteString.unpack bs)+arrayItems (ArrayBytes bs) = map toVariant (BS.unpack bs)  -- | A D-Bus Dictionary is a container type similar to Haskell maps, storing -- zero or more associations between keys and values.@@ -1365,9 +1345,9 @@     Just x -> x     Nothing -> error ("Invalid " ++ label ++ ": " ++ show str) -maybeParseString :: Parsec.Parser a -> String -> Maybe a+maybeParseString :: MonadThrow m => Parsec.Parser a -> String -> m a maybeParseString parser s = case Parsec.parse parser "" s of-    Left _ -> Nothing-    Right a -> Just a+    Left err -> throwM $ userError $ show err+    Right a -> pure a  THL.deriveLiftMany [''BusName, ''ObjectPath, ''InterfaceName, ''MemberName]
lib/DBus/Introspection.hs view
@@ -29,16 +29,15 @@     , Property(..)     ) where +import           Conduit import qualified Control.Applicative-import           Control.Monad ((>=>), ap, liftM)-import           Control.Monad.ST (runST)+import           Control.Monad (ap, liftM)+import qualified Data.ByteString.Lazy.Char8 as BL8 import           Data.List (isPrefixOf)-import qualified Data.STRef as ST-import qualified Data.Text-import           Data.Text (Text)-import qualified Data.Text.Encoding-import qualified Data.XML.Types as X-import qualified Text.XML.LibXML.SAX as SAX+import           Data.Maybe+import qualified Data.Text as Text+import           Data.XML.Types+import qualified Text.XML.Stream.Parse as X  import qualified DBus as T @@ -93,124 +92,130 @@     }     deriving (Show, Eq) -parseXML :: T.ObjectPath -> String -> Maybe Object-parseXML path xml = do-    root <- parseElement (Data.Text.pack xml)-    parseRoot path root+data ObjectChildren+    = InterfaceDefinition Interface+    | SubNode Object -parseElement :: Text -> Maybe X.Element-parseElement xml = runST $ do-    stackRef <- ST.newSTRef [([], [])]-    let onError _ = do-        ST.writeSTRef stackRef []-        return False-    let onBegin _ attrs = do-        ST.modifySTRef stackRef ((attrs, []):)-        return True-    let onEnd name = do-        stack <- ST.readSTRef stackRef-        let (attrs, children'):stack' = stack-        let e = X.Element name attrs (map X.NodeElement (reverse children'))-        let (pAttrs, pChildren):stack'' = stack'-        let parent = (pAttrs, e:pChildren)-        ST.writeSTRef stackRef (parent:stack'')-        return True+data InterfaceChildren+    = MethodDefinition Method+    | SignalDefinition Signal+    | PropertyDefinition Property -    p <- SAX.newParserST Nothing-    SAX.setCallback p SAX.parsedBeginElement onBegin-    SAX.setCallback p SAX.parsedEndElement onEnd-    SAX.setCallback p SAX.reportError onError-    SAX.parseBytes p (Data.Text.Encoding.encodeUtf8 xml)-    SAX.parseComplete p-    stack <- ST.readSTRef stackRef-    return $ case stack of-        [] -> Nothing-        (_, children'):_ -> Just (head children')+parseXML :: T.ObjectPath -> String -> Maybe Object+parseXML path xml =+    runConduit $ X.parseLBS X.def (BL8.pack xml) .| X.force "parse error" (parseObject $ getRootName path) -parseRoot :: T.ObjectPath -> X.Element -> Maybe Object-parseRoot defaultPath e = do-    path <- case X.attributeText "name" e of-        Nothing -> Just defaultPath-        Just x  -> T.parseObjectPath (Data.Text.unpack x)-    parseObject path e+getRootName :: T.ObjectPath -> X.AttrParser T.ObjectPath+getRootName defaultPath = do+    nodeName <- X.attr "name"+    pure $ maybe defaultPath (T.objectPath_ . Text.unpack) nodeName -parseChild :: T.ObjectPath -> X.Element -> Maybe Object-parseChild parentPath e = do+getChildName :: T.ObjectPath -> X.AttrParser T.ObjectPath+getChildName parentPath = do+    nodeName <- X.requireAttr "name"     let parentPath' = case T.formatObjectPath parentPath of             "/" -> "/"             x   -> x ++ "/"-    pathSegment <- X.attributeText "name" e-    path <- T.parseObjectPath (parentPath' ++ Data.Text.unpack pathSegment)-    parseObject path e--parseObject :: T.ObjectPath -> X.Element -> Maybe Object-parseObject path e | X.elementName e == "node" = do-    interfaces <- children parseInterface (X.isNamed "interface") e-    children' <- children (parseChild path) (X.isNamed "node") e-    return (Object path interfaces children')-parseObject _ _ = Nothing--parseInterface :: X.Element -> Maybe Interface-parseInterface e = do-    name <- T.parseInterfaceName =<< attributeString "name" e-    methods <- children parseMethod (X.isNamed "method") e-    signals <- children parseSignal (X.isNamed "signal") e-    properties <- children parseProperty (X.isNamed "property") e-    return (Interface name methods signals properties)--parseMethod :: X.Element -> Maybe Method-parseMethod e = do-    name <- T.parseMemberName =<< attributeString "name" e-    args <- children parseMethodArg (isArg ["in", "out", ""]) e-    return (Method name args)--parseSignal :: X.Element -> Maybe Signal-parseSignal e = do-    name <- T.parseMemberName =<< attributeString "name" e-    args <- children parseSignalArg (isArg ["out", ""]) e-    return (Signal name args)+    pure $ T.objectPath_ (parentPath' ++ Text.unpack nodeName) -parseType :: X.Element -> Maybe T.Type-parseType e = do-    typeStr <- attributeString "type" e-    sig <- T.parseSignature typeStr-    case T.signatureTypes sig of-        [t] -> Just t-        _ -> Nothing+parseObject+    :: X.AttrParser T.ObjectPath+    -> ConduitT Event o Maybe (Maybe Object)+parseObject getPath = X.tag' "node" getPath parseContent+  where+    parseContent objPath = do+        elems <- X.many $ X.choose+            [ fmap SubNode <$> parseObject (getChildName objPath)+            , fmap InterfaceDefinition <$> parseInterface+            ]+        let base = Object objPath [] []+            addElem e (Object p is cs) = case e of+                InterfaceDefinition i -> Object p (i:is) cs+                SubNode c -> Object p is (c:cs)+        pure $ foldr addElem base elems -parseMethodArg :: X.Element -> Maybe MethodArg-parseMethodArg e = do-    t <- parseType e-    let dir = case getattr "direction" e of-            "out" -> Out-            _ -> In-    Just (MethodArg (getattr "name" e) t dir)+parseInterface+    :: ConduitT Event o Maybe (Maybe Interface)+parseInterface = X.tag' "interface" getName parseContent+  where+    getName = do+        ifName <- X.requireAttr "name"+        pure $ T.interfaceName_ (Text.unpack ifName)+    parseContent ifName = do+        elems <- X.many $ X.choose+            [ parseMethod+            , parseSignal+            , parseProperty+            ]+        let base = Interface ifName [] [] []+            addElem e (Interface n ms ss ps) = case e of+                MethodDefinition m -> Interface n (m:ms) ss ps+                SignalDefinition s -> Interface n ms (s:ss) ps+                PropertyDefinition p -> Interface n ms ss (p:ps)+        pure $ foldr addElem base elems -parseSignalArg :: X.Element -> Maybe SignalArg-parseSignalArg e = do-    t <- parseType e-    Just (SignalArg (getattr "name" e) t)+parseMethod :: ConduitT Event o Maybe (Maybe InterfaceChildren)+parseMethod = X.tag' "method" getName parseArgs+  where+    getName = do+        ifName <- X.requireAttr "name"+        T.parseMemberName (Text.unpack ifName)+    parseArgs name = do+        args <- X.many $+            X.tag' "arg" getArg pure+        pure $ MethodDefinition $ Method name args+    getArg = do+        name <- fromMaybe "" <$> X.attr "name"+        typeStr <- X.requireAttr "type"+        dirStr <- fromMaybe "in" <$> X.attr "direction"+        X.ignoreAttrs+        typ <- parseType typeStr+        let dir = if dirStr == "in" then In else Out+        pure $ MethodArg (Text.unpack name) typ dir -isArg :: [String] -> X.Element -> [X.Element]-isArg dirs = X.isNamed "arg" >=> checkDir where-    checkDir e = [e | getattr "direction" e `elem` dirs]+parseSignal :: ConduitT Event o Maybe (Maybe InterfaceChildren)+parseSignal = X.tag' "signal" getName parseArgs+  where+    getName = do+        ifName <- X.requireAttr "name"+        T.parseMemberName (Text.unpack ifName)+    parseArgs name = do+        args <- X.many $+            X.tag' "arg" getArg pure+        pure $ SignalDefinition $ Signal name args+    getArg = do+        name <- fromMaybe "" <$> X.attr "name"+        typeStr <- X.requireAttr "type"+        X.ignoreAttrs+        typ <- parseType typeStr+        pure $ SignalArg (Text.unpack name) typ -parseProperty :: X.Element -> Maybe Property-parseProperty e = do-    t <- parseType e-    (canRead, canWrite) <- case getattr "access" e of-        ""          -> Just (False, False)-        "read"      -> Just (True, False)-        "write"     -> Just (False, True)-        "readwrite" -> Just (True, True)-        _           -> Nothing-    Just (Property (getattr "name" e) t canRead canWrite)+parseProperty :: ConduitT Event o Maybe (Maybe InterfaceChildren)+parseProperty = X.tag' "property" getProp $ \p -> do+    X.many_ X.ignoreAnyTreeContent+    pure p+  where+    getProp = do+        name <- Text.unpack <$> X.requireAttr "name"+        typeStr <- X.requireAttr "type"+        accessStr <- fromMaybe "" <$> X.attr "access"+        X.ignoreAttrs+        typ <- parseType typeStr+        (canRead, canWrite) <- case accessStr of+            ""          -> pure (False, False)+            "read"      -> pure (True, False)+            "write"     -> pure (False, True)+            "readwrite" -> pure (True, True)+            _           -> throwM $ userError "invalid access value" -getattr :: X.Name -> X.Element -> String-getattr name e = maybe "" Data.Text.unpack (X.attributeText name e)+        pure $ PropertyDefinition $ Property name typ canRead canWrite -children :: Monad m => (X.Element -> m b) -> (X.Element -> [X.Element]) -> X.Element -> m [b]-children f p = mapM f . concatMap p . X.elementChildren+parseType :: MonadThrow m => Text.Text -> m T.Type+parseType typeStr = do+    typ <- T.parseSignature (Text.unpack typeStr)+    case T.signatureTypes typ of+        [t] -> pure t+        _ -> throwM $ userError "invalid type sig"  newtype XmlWriter a = XmlWriter { runXmlWriter :: Maybe (a, String) } @@ -317,8 +322,8 @@         , ("access", readS ++ writeS)         ] -attributeString :: X.Name -> X.Element -> Maybe String-attributeString name e = fmap Data.Text.unpack (X.attributeText name e)+--attributeString :: X.Name -> X.Element -> Maybe String+--attributeString name e = fmap Data.Text.unpack (X.attributeText name e)  writeElement :: String -> [(String, String)] -> XmlWriter () -> XmlWriter () writeElement name attrs content = do
lib/DBus/TH.hs view
@@ -6,7 +6,6 @@ import           DBus.Generation import           System.FilePath - generateSignalsFromInterface defaultGenerationParams $                              buildIntrospectionInterface $                              buildPropertiesInterface undefined
tests/DBusTests/Generation.hs view
@@ -26,6 +26,11 @@ testInterface =   defaultInterface { interfaceMethods =                        [autoMethod "SampleMethod1" sampleMethod1]+                   , interfaceProperties =+                     [autoProperty "SampleWriteProperty"+                                     (Just $ return (1 :: Int32))+                                     (Just $ const $ return ())+                     ]                    , interfaceName = "org.TestInterface"                    , interfaceSignals = testSignals                    }
tests/DBusTests/Introspection.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedStrings #-} -- Copyright (C) 2010-2012 John Millikin <john@john-millikin.com> -- -- Licensed under the Apache License, Version 2.0 (the "License");