{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable, DefaultSignatures,
TypeOperators, TupleSections, FlexibleContexts, FlexibleInstances
#-}
module GHCJS.Marshal.Internal ( FromJSVal(..)
, ToJSVal(..)
, PToJSVal(..)
, PFromJSVal(..)
, Purity(..)
, toJSVal_generic
, fromJSVal_generic
, toJSVal_pure
, fromJSVal_pure
, fromJSValUnchecked_pure
) where
import Control.Applicative
import Control.Monad
import Data.Data
import Data.Maybe
import Data.Typeable
import GHC.Generics
import qualified GHCJS.Prim as Prim
import qualified GHCJS.Foreign as F
import GHCJS.Types
import qualified Data.JSString.Internal.Type as JSS
import JavaScript.Array (MutableJSArray)
import qualified JavaScript.Array.Internal as AI
import JavaScript.Object (Object)
import qualified JavaScript.Object.Internal as OI
data Purity = PureShared
| PureExclusive
deriving (Eq, Ord, Typeable, Data)
class PToJSVal a where
pToJSVal :: a -> JSVal
class PFromJSVal a where
pFromJSVal :: JSVal -> a
class ToJSVal a where
toJSVal :: a -> IO JSVal
toJSValListOf :: [a] -> IO JSVal
toJSValListOf = Prim.toJSArray <=< mapM toJSVal
default toJSVal :: (Generic a, GToJSVal (Rep a ())) => a -> IO JSVal
toJSVal = toJSVal_generic id
class FromJSVal a where
fromJSVal :: JSVal -> IO (Maybe a)
fromJSValUnchecked :: JSVal -> IO a
fromJSValUnchecked = fmap fromJust . fromJSVal
{-# INLINE fromJSValUnchecked #-}
fromJSValListOf :: JSVal -> IO (Maybe [a])
fromJSValListOf = fmap sequence . (mapM fromJSVal <=< Prim.fromJSArray)
fromJSValUncheckedListOf :: JSVal -> IO [a]
fromJSValUncheckedListOf = mapM fromJSValUnchecked <=< Prim.fromJSArray
default fromJSVal :: (Generic a, GFromJSVal (Rep a ())) => JSVal -> IO (Maybe a)
fromJSVal = fromJSVal_generic id
class GToJSVal a where
gToJSVal :: (String -> String) -> Bool -> a -> IO JSVal
class GToJSProp a where
gToJSProp :: (String -> String) -> JSVal -> a -> IO ()
class GToJSArr a where
gToJSArr :: (String -> String) -> MutableJSArray -> a -> IO ()
instance (ToJSVal b) => GToJSVal (K1 a b c) where
gToJSVal _ _ (K1 x) = toJSVal x
instance GToJSVal p => GToJSVal (Par1 p) where
gToJSVal f b (Par1 p) = gToJSVal f b p
instance GToJSVal (f p) => GToJSVal (Rec1 f p) where
gToJSVal f b (Rec1 x) = gToJSVal f b x
instance (GToJSVal (a p), GToJSVal (b p)) => GToJSVal ((a :+: b) p) where
gToJSVal f _ (L1 x) = gToJSVal f True x
gToJSVal f _ (R1 x) = gToJSVal f True x
instance (Datatype c, GToJSVal (a p)) => GToJSVal (M1 D c a p) where
gToJSVal f b m@(M1 x) = gToJSVal f b x
instance (Constructor c, GToJSVal (a p)) => GToJSVal (M1 C c a p) where
gToJSVal f True m@(M1 x) = do
obj@(OI.Object obj') <- OI.create
v <- gToJSVal f (conIsRecord m) x
OI.setProp (packJSS . f $ conName m) v obj
return obj'
gToJSVal f _ m@(M1 x) = gToJSVal f (conIsRecord m) x
instance (GToJSArr (a p), GToJSArr (b p), GToJSProp (a p), GToJSProp (b p)) => GToJSVal ((a :*: b) p) where
gToJSVal f True xy = do
(OI.Object obj') <- OI.create
gToJSProp f obj' xy
return obj'
gToJSVal f False xy = do
arr@(AI.SomeJSArray arr') <- AI.create
gToJSArr f arr xy
return arr'
instance GToJSVal (a p) => GToJSVal (M1 S c a p) where
gToJSVal f b (M1 x) = gToJSVal f b x
instance (GToJSProp (a p), GToJSProp (b p)) => GToJSProp ((a :*: b) p) where
gToJSProp f o (x :*: y) = gToJSProp f o x >> gToJSProp f o y
instance (Selector c, GToJSVal (a p)) => GToJSProp (M1 S c a p) where
gToJSProp f o m@(M1 x) = do
r <- gToJSVal f False x
OI.setProp (packJSS . f $ selName m) r (OI.Object o)
instance (GToJSArr (a p), GToJSArr (b p)) => GToJSArr ((a :*: b) p) where
gToJSArr f a (x :*: y) = gToJSArr f a x >> gToJSArr f a y
instance GToJSVal (a p) => GToJSArr (M1 S c a p) where
gToJSArr f a (M1 x) = do
r <- gToJSVal f False x
AI.push r a
instance GToJSVal (V1 p) where
gToJSVal _ _ _ = return Prim.jsNull
instance GToJSVal (U1 p) where
gToJSVal _ _ _ = return F.jsTrue
toJSVal_generic :: forall a . (Generic a, GToJSVal (Rep a ()))
=> (String -> String) -> a -> IO JSVal
toJSVal_generic f x = gToJSVal f False (from x :: Rep a ())
class GFromJSVal a where
gFromJSVal :: (String -> String) -> Bool -> JSVal -> IO (Maybe a)
class GFromJSProp a where
gFromJSProp :: (String -> String) -> JSVal -> IO (Maybe a)
class GFromJSArr a where
gFromJSArr :: (String -> String) -> MutableJSArray -> Int -> IO (Maybe (a,Int))
instance FromJSVal b => GFromJSVal (K1 a b c) where
gFromJSVal _ _ r = fmap K1 <$> fromJSVal r
instance GFromJSVal p => GFromJSVal (Par1 p) where
gFromJSVal f b r = gFromJSVal f b r
instance GFromJSVal (f p) => GFromJSVal (Rec1 f p) where
gFromJSVal f b r = gFromJSVal f b r
instance (GFromJSVal (a p), GFromJSVal (b p)) => GFromJSVal ((a :+: b) p) where
gFromJSVal f b r = do
l <- gFromJSVal f True r
case l of
Just x -> return (L1 <$> Just x)
Nothing -> fmap R1 <$> gFromJSVal f True r
instance (Datatype c, GFromJSVal (a p)) => GFromJSVal (M1 D c a p) where
gFromJSVal f b r = fmap M1 <$> gFromJSVal f b r
instance forall c a p . (Constructor c, GFromJSVal (a p)) => GFromJSVal (M1 C c a p) where
gFromJSVal f True r = do
r' <- OI.getProp (packJSS . f $ conName (undefined :: M1 C c a p)) (OI.Object r)
if isUndefined r'
then return Nothing
else fmap M1 <$> gFromJSVal f (conIsRecord (undefined :: M1 C c a p)) r'
gFromJSVal f _ r = fmap M1 <$> gFromJSVal f (conIsRecord (undefined :: M1 C c a p)) r
instance (GFromJSArr (a p), GFromJSArr (b p), GFromJSProp (a p), GFromJSProp (b p)) => GFromJSVal ((a :*: b) p) where
gFromJSVal f True r = gFromJSProp f r
gFromJSVal f False r = fmap fst <$> gFromJSArr f (AI.SomeJSArray r) 0
instance GFromJSVal (a p) => GFromJSVal (M1 S c a p) where
gFromJSVal f b r = fmap M1 <$> gFromJSVal f b r
instance (GFromJSProp (a p), GFromJSProp (b p)) => GFromJSProp ((a :*: b) p) where
gFromJSProp f r = do
a <- gFromJSProp f r
case a of
Nothing -> return Nothing
Just a' -> fmap (a':*:) <$> gFromJSProp f r
instance forall c a p . (Selector c, GFromJSVal (a p)) => GFromJSProp (M1 S c a p) where
gFromJSProp f o = do
p <- OI.getProp (packJSS . f $ selName (undefined :: M1 S c a p)) (OI.Object o)
if isUndefined p
then return Nothing
else fmap M1 <$> gFromJSVal f False p
instance (GFromJSArr (a p), GFromJSArr (b p)) => GFromJSArr ((a :*: b) p) where
gFromJSArr f r n = do
a <- gFromJSArr f r 0
case a of
Just (a',an) -> do
b <- gFromJSArr f r an
case b of
Just (b',bn) -> return (Just (a' :*: b',bn))
_ -> return Nothing
instance (GFromJSVal (a p)) => GFromJSArr (M1 S c a p) where
gFromJSArr f o n = do
r <- AI.read n o
if isUndefined r
then return Nothing
else fmap ((,n+1) . M1) <$> gFromJSVal f False r
instance GFromJSVal (V1 p) where
gFromJSVal _ _ _ = return Nothing
instance GFromJSVal (U1 p) where
gFromJSVal _ _ _ = return (Just U1)
fromJSVal_generic :: forall a . (Generic a, GFromJSVal (Rep a ()))
=> (String -> String) -> JSVal -> IO (Maybe a)
fromJSVal_generic f x = fmap to <$> (gFromJSVal f False x :: IO (Maybe (Rep a ())))
fromJSVal_pure :: PFromJSVal a => JSVal -> IO (Maybe a)
fromJSVal_pure x = return (Just (pFromJSVal x))
{-# INLINE fromJSVal_pure #-}
fromJSValUnchecked_pure :: PFromJSVal a => JSVal -> IO a
fromJSValUnchecked_pure x = return (pFromJSVal x)
{-# INLINE fromJSValUnchecked_pure #-}
toJSVal_pure :: PToJSVal a => a -> IO JSVal
toJSVal_pure x = return (pToJSVal x)
{-# INLINE toJSVal_pure #-}
packJSS :: String -> JSString
packJSS = JSS.JSString . Prim.toJSString