cpython-3.5.1: lib/CPython/Simple/Instances.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module CPython.Simple.Instances where
import Control.Exception (Exception(..), throwIO)
import Control.Monad ((<=<))
import Data.Text (Text)
import qualified Data.Text as T
import Data.Typeable
import qualified CPython.Constants as Py
import qualified CPython.Protocols.Object as Py
import qualified CPython.Types as Py
import qualified CPython.Types.Tuple as Py (fromTuple)
-- TODO: ToPy/FromPy for Bool will require some library changes (e.g. adding fromBool)
class ToPy a where
toPy :: a -> IO Py.SomeObject
class FromPy a where
fromPy :: Py.SomeObject -> IO a
data PyCastException = PyCastException String
deriving (Show)
instance Exception PyCastException where
displayException (PyCastException typename) =
"FromPy could not cast to " ++ typename
easyToPy
:: Py.Object c
=> (a -> IO c) -- ^ python to- conversion, e.g. Py.toFloat
-> a -- ^ haskell type being converted
-> IO Py.SomeObject
easyToPy f = fmap Py.toObject . f
easyFromPy
:: (Py.Concrete b, Typeable c)
=> (b -> IO c) -- ^ python from- conversion, e.g. Py.fromFloat
-> Proxy c -- ^ proxy for the type being converted to
-> Py.SomeObject -- ^ python object to cast from
-> IO c
easyFromPy conversion typename obj = do
casted <- Py.cast obj
case casted of
Nothing -> throwIO $ PyCastException (show $ typeRep typename)
Just x -> conversion x
instance ToPy Integer where
toPy = easyToPy Py.toInteger
instance FromPy Integer where
fromPy = easyFromPy Py.fromInteger Proxy
instance ToPy Double where
toPy = easyToPy Py.toFloat
instance FromPy Double where
fromPy = easyFromPy Py.fromFloat Proxy
instance ToPy Text where
toPy = easyToPy Py.toUnicode
instance FromPy Text where
fromPy = easyFromPy Py.fromUnicode Proxy
instance ToPy Char where
toPy = easyToPy Py.toUnicode . T.singleton
instance FromPy Char where
fromPy c = T.head <$> easyFromPy Py.fromUnicode Proxy c
instance ToPy String where
toPy = easyToPy Py.toUnicode . T.pack
instance FromPy String where
fromPy s = T.unpack <$> easyFromPy Py.fromUnicode Proxy s
instance (FromPy a, FromPy b) => FromPy (a, b) where
fromPy val = do
[pyA, pyB] <- easyFromPy Py.fromTuple Proxy val
a <- fromPy pyA
b <- fromPy pyB
pure (a, b)
instance (FromPy a, FromPy b, FromPy c) => FromPy (a, b, c) where
fromPy val = do
[pyA, pyB, pyC] <- easyFromPy Py.fromTuple Proxy val
a <- fromPy pyA
b <- fromPy pyB
c <- fromPy pyC
pure (a, b, c)
instance FromPy a => FromPy (Maybe a) where
fromPy val = do
isNone <- Py.isNone val
if isNone
then pure Nothing
else Just <$> fromPy val
instance ToPy a => ToPy (Maybe a) where
toPy Nothing = Py.none
toPy (Just a) = toPy a
instance FromPy a => FromPy [a] where
fromPy val = do
list <- easyFromPy Py.fromList Proxy val
mapM fromPy list
instance ToPy a => ToPy [a] where
toPy val = do
list <- mapM toPy val
Py.toObject <$> Py.toList list
instance FromPy () where
fromPy _ = pure ()