yaml-rpc-0.3: Network/YAML/Instances.hs
{-# LANGUAGE TypeSynonymInstances, MultiParamTypeClasses, OverloadedStrings, FlexibleInstances, IncoherentInstances #-}
module Network.YAML.Instances where
import Data.Maybe
import Data.Default
import Data.Object
import Data.Object.Yaml
import qualified Data.ByteString.Char8 as BS
import Network.YAML.Types
import Network.YAML.Base
-- | Build YamlObject from (key,value) pairs
object :: [(BS.ByteString, YamlScalar)] -> YamlObject
object pairs = Mapping [(toYamlScalar name, Scalar val) | (name,val) <- pairs]
-- | Build YamlObject with single field
field :: (IsYamlScalar a) => BS.ByteString -> a -> YamlObject
field name val = Mapping [(toYamlScalar name, Scalar $ toYamlScalar val)]
instance Default BS.ByteString where
def = BS.empty
instance (IsYamlObject a) => IsYamlObject [a] where
toYaml lst = Sequence $ map toYaml lst
fromYaml (Mapping pairs) = map fromYaml $ map snd pairs
fromYaml (Sequence lst) = map fromYaml lst
fromYaml s@(Scalar _) = [fromYaml s]
tryGet lst k =
if k >= length lst
then def
else lst !! k
instance (IsYamlObject a, IsYamlObject b) => IsYamlObject (a,b) where
toYaml (x,y) = Sequence [toYaml x, toYaml y]
fromYaml obj = (fromYaml x, fromYaml y)
where
list = getList obj
x = tryGet list 0
y = tryGet list 1
instance (IsYamlObject a, IsYamlObject b, IsYamlObject c) => IsYamlObject (a,b,c) where
toYaml (x,y,z) = Sequence [toYaml x, toYaml y, toYaml z]
fromYaml obj = (fromYaml x, fromYaml y, fromYaml z)
where
list = getList obj
x = tryGet list 0
y = tryGet list 1
z = tryGet list 2
instance (Default a, Default b) => Default (a,b) where
def = (def, def)
instance (Default a, Default b, Default c) => Default (a,b,c) where
def = (def, def, def)
_right :: BS.ByteString
_right = "Right"
_left :: BS.ByteString
_left = "Left"
instance (Default a) => Default (Either a b) where
def = Left def
instance (IsYamlObject a, IsYamlObject b) => IsYamlObject (Either a b) where
toYaml (Right a) = Mapping [(toYamlScalar _right, toYaml a)]
toYaml (Left b) = Mapping [(toYamlScalar _left, toYaml b)]
fromYaml (Mapping [(name, val)]) =
if fromYamlScalar name == _right
then Right (fromYaml val)
else if fromYamlScalar name == _left
then Left (fromYaml val)
else def
fromYaml _ = def
instance Default YamlObject where
def = Sequence []
instance IsYamlObject YamlObject where
toYaml = id
fromYaml = id
instance IsYamlObject Double where
fromYaml x = fromMaybe def $ getScalar x
toYaml x = Scalar $ toYamlScalar x
instance IsYamlObject Int where
fromYaml x = fromMaybe def $ getScalar x
toYaml x = Scalar $ toYamlScalar x
instance IsYamlObject Integer where
fromYaml x = fromMaybe def $ getScalar x
toYaml x = Scalar $ toYamlScalar x
instance IsYamlScalar Bool where
toYamlScalar True = stringScalar "True"
toYamlScalar False = stringScalar "False"
fromYamlScalar x =
case fromYamlScalar x :: String of
"True" -> True
_ -> False
instance Default Bool where
def = False
instance IsYamlObject Bool where
toYaml x = Scalar $ toYamlScalar x
fromYaml x = fromMaybe def $ getScalar x
instance IsYamlObject BS.ByteString where
fromYaml x = fromMaybe def $ getScalar x
toYaml x = Scalar $ toYamlScalar x
instance IsYamlObject String where
fromYaml x = fromMaybe def $ getScalar x
toYaml x = Scalar $ toYamlScalar x
mkCall :: BS.ByteString -> YamlObject -> YamlObject
mkCall name args = toYaml $ Call name args
stringScalar :: String -> YamlScalar
stringScalar = toYamlScalar
instance Default Call where
def = Call "defaultMethod" def
instance IsYamlObject Call where
toYaml (Call name args) = Mapping [(stringScalar "call", Scalar $ toYamlScalar name),
(stringScalar "args", args)]
fromYaml obj = Call name args
where
name = fromMaybe "defaultMethod" $ getScalarAttr "call" obj
args = fromMaybe (Sequence []) $ getAttr "args" obj
-- | Convert any (a -> IO b) action to YAML RPC method
yamlMethod :: (IsYamlObject a, IsYamlObject b) => (a -> IO b) -> YamlObject -> IO YamlObject
yamlMethod fn = \obj -> do
let x = fromYaml obj
y <- fn x
return $ toYaml y