jsaddle-0.7.0.0: src-ghc/GHCJS/Marshal/Internal.hs
{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable, DefaultSignatures,
TypeOperators, TupleSections, FlexibleContexts, FlexibleInstances,
LambdaCase
#-}
module GHCJS.Marshal.Internal (
FromJSVal(..)
, ToJSVal(..)
, PToJSVal(..)
, PFromJSVal(..)
, Purity(..)
, toJSVal_generic
, fromJSVal_generic
, toJSVal_pure
, fromJSVal_pure
, fromJSValUnchecked_pure
) where
import Control.Monad
import Data.Data
import Data.Maybe
import Data.Coerce (coerce)
import qualified Data.Text as T (pack)
import GHC.Generics
import Language.Javascript.JSaddle.Types (JSM, JSVal, SomeJSArray(..), MutableJSArray, JSString)
import Language.Javascript.JSaddle.Foreign (jsNull, jsTrue, isUndefinedIO)
import Language.Javascript.JSaddle.String (textToStr)
import qualified JavaScript.Object.Internal as OI (Object(..), create, setProp, getProp)
import qualified JavaScript.Array.Internal as AI (create, push, read, fromListIO, toListIO)
data Purity = PureShared -- ^ conversion is pure even if the original value is shared
| PureExclusive -- ^ conversion is pure if the we only convert once
deriving (Eq, Ord, Typeable, Data)
class PToJSVal a where
-- type PureOut a :: Purity
pToJSVal :: a -> JSVal
class PFromJSVal a where
-- type PureIn a :: Purity
pFromJSVal :: JSVal -> a
class ToJSVal a where
toJSVal :: a -> JSM JSVal
toJSValListOf :: [a] -> JSM JSVal
toJSValListOf = fmap coerce . AI.fromListIO <=< mapM toJSVal
default toJSVal :: (Generic a, GToJSVal (Rep a ())) => a -> JSM JSVal
toJSVal = toJSVal_generic id
class FromJSVal a where
fromJSVal :: JSVal -> JSM (Maybe a)
fromJSValUnchecked :: JSVal -> JSM a
fromJSValUnchecked = fmap fromJust . fromJSVal
{-# INLINE fromJSValUnchecked #-}
fromJSValListOf :: JSVal -> JSM (Maybe [a])
fromJSValListOf = fmap sequence . (mapM fromJSVal <=< AI.toListIO . coerce) -- fixme should check that it's an array
fromJSValUncheckedListOf :: JSVal -> JSM [a]
fromJSValUncheckedListOf = mapM fromJSValUnchecked <=< AI.toListIO . coerce
default fromJSVal :: (Generic a, GFromJSVal (Rep a ())) => JSVal -> JSM (Maybe a)
fromJSVal = fromJSVal_generic id
-- -----------------------------------------------------------------------------
class GToJSVal a where
gToJSVal :: (String -> String) -> Bool -> a -> JSM JSVal
class GToJSProp a where
gToJSProp :: (String -> String) -> JSVal -> a -> JSM ()
class GToJSArr a where
gToJSArr :: (String -> String) -> MutableJSArray -> a -> JSM ()
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 (GToJSVal (a p)) => GToJSVal (M1 D c a p) where
gToJSVal f b (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@(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 jsNull
instance GToJSVal (U1 p) where
gToJSVal _ _ _ = return jsTrue
toJSVal_generic :: forall a . (Generic a, GToJSVal (Rep a ()))
=> (String -> String) -> a -> JSM JSVal
toJSVal_generic f x = gToJSVal f False (from x :: Rep a ())
-- -----------------------------------------------------------------------------
class GFromJSVal a where
gFromJSVal :: (String -> String) -> Bool -> JSVal -> JSM (Maybe a)
class GFromJSProp a where
gFromJSProp :: (String -> String) -> JSVal -> JSM (Maybe a)
class GFromJSArr a where
gFromJSArr :: (String -> String) -> MutableJSArray -> Int -> JSM (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 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)
isUndefinedIO r' >>= \case
True -> return Nothing
False -> 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 (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)
isUndefinedIO p >>= \case
True -> return Nothing
False -> 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
isUndefinedIO r >>= \case
True -> return Nothing
False -> 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 -> JSM (Maybe a)
fromJSVal_generic f x = fmap to <$> (gFromJSVal f False x :: JSM (Maybe (Rep a ())))
-- -----------------------------------------------------------------------------
fromJSVal_pure :: PFromJSVal a => JSVal -> JSM (Maybe a)
fromJSVal_pure x = return (Just (pFromJSVal x))
{-# INLINE fromJSVal_pure #-}
fromJSValUnchecked_pure :: PFromJSVal a => JSVal -> JSM a
fromJSValUnchecked_pure x = return (pFromJSVal x)
{-# INLINE fromJSValUnchecked_pure #-}
toJSVal_pure :: PToJSVal a => a -> JSM JSVal
toJSVal_pure x = return (pToJSVal x)
{-# INLINE toJSVal_pure #-}
-- -----------------------------------------------------------------------------
packJSS :: String -> JSString
packJSS = textToStr . T.pack