{-#LANGUAGE CPP #-}
{-#LANGUAGE OverloadedStrings #-}
{-#LANGUAGE MultiParamTypeClasses #-}
{-#LANGUAGE FlexibleInstances #-}
{-#LANGUAGE ScopedTypeVariables #-}
{-#LANGUAGE RankNTypes #-}

-- | GVal is a generic unitype value, representing the kind of values that
-- Ginger can understand.
--
-- Most of the types in this module are parametrized over an 'm' type, which
-- is the host monad for template execution, as passed to 'runGingerT'. For
-- most kinds of values, 'm' is transparent, and in many cases a 'ToGVal'
-- instance can be written that works for all possible 'm'; the reason we need
-- to parametrize the values themselves over the carrier monad is because we
-- want to support impure functions, which requires access to the underlying
-- carrier monad (e.g. 'IO').
module Text.Ginger.GVal
where

import Prelude ( (.), ($), (==), (/=)
               , (++), (+), (-), (*), (/), div
               , (=<<), (>>=), return
               , (||), (&&)
               , undefined, otherwise, id, const
               , fmap
               , Maybe (..)
               , Bool (..)
               , Either (..)
               , Char
               , Int
               , Integer
               , Double
               , Show, show
               , Integral
               , fromIntegral, floor
               , not
               , fst, snd
               , Monad
               , Functor
               )
import Control.Monad.Fail (MonadFail)
import qualified Prelude
import Data.Maybe ( fromMaybe, catMaybes, isJust, mapMaybe )
import Data.Text (Text)
import Data.String (IsString, fromString)
import qualified Data.Text as Text
import qualified Data.Text.Lazy as LText
import qualified Data.List as List
import Safe (readMay, atMay)
import Data.Monoid
import Data.Scientific ( Scientific
                       , floatingOrInteger
                       , toBoundedInteger
                       , toRealFloat
                       , scientific
                       , coefficient
                       , base10Exponent
                       )
import Data.Fixed (Fixed (..), Pico)
import Control.Applicative
import qualified Data.Aeson as JSON
#if MIN_VERSION_aeson(2,0,0)
import qualified Data.Aeson.Key as AK
import qualified Data.Aeson.KeyMap as AKM
#endif
import qualified Data.HashMap.Strict as HashMap
import Data.HashMap.Strict (HashMap)
import qualified Data.Map.Strict as Map
import Data.Map.Strict (Map)
import qualified Data.Vector as Vector
import Control.Monad ((<=<), forM, mapM)
import Control.Monad.Trans (MonadTrans, lift)
import Data.Default (Default, def)
import Text.Printf
import Debug.Trace (trace)
import Data.Time ( Day (..)
                 , defaultTimeLocale
                 , toModifiedJulianDay
                 , formatTime
                 , toGregorian
                 , fromGregorian
                 , LocalTime (..)
                 , ZonedTime (..)
                 , TimeOfDay (..)
                 , TimeZone (..)
                 , TimeLocale (..)
                 )
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import Data.Text.Encoding (encodeUtf8, decodeUtf8)
import qualified Data.Text.Lazy.Encoding as LText

import Text.Ginger.Html

-- * The Ginger Value type
--
-- | A variant type designed as the unitype for the template language. Any
-- value referenced in a template, returned from within a template, or used
-- in a template context, will be a 'GVal'.
-- @m@, in most cases, should be a 'Monad'.
--
-- Some laws apply here, most notably:
--
-- - when 'isNull' is 'True', then all of 'asFunction', 'asText', 'asNumber',
--   'asHtml', 'asList', 'asDictItems', and 'length' should produce 'Nothing'
-- - when 'isNull' is 'True', then 'asBoolean' should produce 'False'
-- - when 'asNumber' is not 'Nothing', then 'asBoolean' should only return
--   'False' for exactly zero
-- - 'Nothing'-ness of 'length' should match one or both of 'asList' / 'asDictItems'
data GVal m =
    GVal
        { GVal m -> Maybe [GVal m]
asList :: Maybe [GVal m] -- ^ Convert value to list, if possible
        , GVal m -> Maybe [(Text, GVal m)]
asDictItems :: Maybe [(Text, GVal m)] -- ^ Convert value to association list ("dictionary"), if possible
        , GVal m -> Maybe (Text -> Maybe (GVal m))
asLookup :: Maybe (Text -> Maybe (GVal m)) -- ^ Convert value to a lookup function
        , GVal m -> Html
asHtml :: Html -- ^ Render value as HTML
        , GVal m -> Text
asText :: Text -- ^ Render value as plain-text
        , GVal m -> Bool
asBoolean :: Bool -- ^ Get value's truthiness
        , GVal m -> Maybe Scientific
asNumber :: Maybe Scientific -- ^ Convert value to a number, if possible
        , GVal m -> Maybe (Function m)
asFunction :: Maybe (Function m) -- ^ Access value as a callable function, if it is one
        , GVal m -> Maybe ByteString
asBytes :: Maybe ByteString -- ^ Access as raw bytes
        , GVal m -> Maybe Int
length :: Maybe Int -- ^ Get length of value, if it is a collection (list/dict)
        , GVal m -> Bool
isNull :: Bool -- ^ Check if the value is null
        , GVal m -> Maybe Value
asJSON :: Maybe JSON.Value -- ^ Provide a custom JSON representation of the value
        }

gappend :: GVal m -> GVal m -> GVal m
gappend :: GVal m -> GVal m -> GVal m
gappend GVal m
a GVal m
b =
  GVal :: forall (m :: * -> *).
Maybe [GVal m]
-> Maybe [(Text, GVal m)]
-> Maybe (Text -> Maybe (GVal m))
-> Html
-> Text
-> Bool
-> Maybe Scientific
-> Maybe (Function m)
-> Maybe ByteString
-> Maybe Int
-> Bool
-> Maybe Value
-> GVal m
GVal
    { asList :: Maybe [GVal m]
asList = [GVal m] -> [GVal m] -> [GVal m]
forall a. [a] -> [a] -> [a]
(++) ([GVal m] -> [GVal m] -> [GVal m])
-> Maybe [GVal m] -> Maybe ([GVal m] -> [GVal m])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList GVal m
a Maybe ([GVal m] -> [GVal m]) -> Maybe [GVal m] -> Maybe [GVal m]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList GVal m
b
    , asDictItems :: Maybe [(Text, GVal m)]
asDictItems = [(Text, GVal m)] -> [(Text, GVal m)] -> [(Text, GVal m)]
forall a. [a] -> [a] -> [a]
(++) ([(Text, GVal m)] -> [(Text, GVal m)] -> [(Text, GVal m)])
-> Maybe [(Text, GVal m)]
-> Maybe ([(Text, GVal m)] -> [(Text, GVal m)])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe [(Text, GVal m)]
forall (m :: * -> *). GVal m -> Maybe [(Text, GVal m)]
asDictItems GVal m
a Maybe ([(Text, GVal m)] -> [(Text, GVal m)])
-> Maybe [(Text, GVal m)] -> Maybe [(Text, GVal m)]
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> GVal m -> Maybe [(Text, GVal m)]
forall (m :: * -> *). GVal m -> Maybe [(Text, GVal m)]
asDictItems GVal m
b
    , asLookup :: Maybe (Text -> Maybe (GVal m))
asLookup = do
        Text -> Maybe (GVal m)
lookupA <- GVal m -> Maybe (Text -> Maybe (GVal m))
forall (m :: * -> *). GVal m -> Maybe (Text -> Maybe (GVal m))
asLookup GVal m
a
        Text -> Maybe (GVal m)
lookupB <- GVal m -> Maybe (Text -> Maybe (GVal m))
forall (m :: * -> *). GVal m -> Maybe (Text -> Maybe (GVal m))
asLookup GVal m
b
        (Text -> Maybe (GVal m)) -> Maybe (Text -> Maybe (GVal m))
forall (m :: * -> *) a. Monad m => a -> m a
return ((Text -> Maybe (GVal m)) -> Maybe (Text -> Maybe (GVal m)))
-> (Text -> Maybe (GVal m)) -> Maybe (Text -> Maybe (GVal m))
forall a b. (a -> b) -> a -> b
$ \Text
k -> Text -> Maybe (GVal m)
lookupA Text
k Maybe (GVal m) -> Maybe (GVal m) -> Maybe (GVal m)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Text -> Maybe (GVal m)
lookupB Text
k
    , asHtml :: Html
asHtml = GVal m -> Html
forall (m :: * -> *). GVal m -> Html
asHtml GVal m
a Html -> Html -> Html
forall a. Semigroup a => a -> a -> a
<> GVal m -> Html
forall (m :: * -> *). GVal m -> Html
asHtml GVal m
b
    , asText :: Text
asText = GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText GVal m
a Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText GVal m
b
    , asBytes :: Maybe ByteString
asBytes = GVal m -> Maybe ByteString
forall (m :: * -> *). GVal m -> Maybe ByteString
asBytes GVal m
a Maybe ByteString -> Maybe ByteString -> Maybe ByteString
forall a. Semigroup a => a -> a -> a
<> GVal m -> Maybe ByteString
forall (m :: * -> *). GVal m -> Maybe ByteString
asBytes GVal m
b
    , asBoolean :: Bool
asBoolean = (GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
asBoolean GVal m
a Bool -> Bool -> Bool
|| GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
asBoolean GVal m
b) Bool -> Bool -> Bool
&& Bool -> Bool
not (GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
isNull GVal m
a Bool -> Bool -> Bool
|| GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
isNull GVal m
b)
    , asNumber :: Maybe Scientific
asNumber = String -> Maybe Scientific
forall a. Read a => String -> Maybe a
readMay (String -> Maybe Scientific)
-> (Text -> String) -> Text -> Maybe Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
Text.unpack (Text -> Maybe Scientific) -> Text -> Maybe Scientific
forall a b. (a -> b) -> a -> b
$ (GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText GVal m
a Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText GVal m
b)
    , asFunction :: Maybe (Function m)
asFunction = Maybe (Function m)
forall a. Maybe a
Nothing
    , isNull :: Bool
isNull = GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
isNull GVal m
a Bool -> Bool -> Bool
|| GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
isNull GVal m
b
    , asJSON :: Maybe Value
asJSON = case (GVal m -> Value
forall a. ToJSON a => a -> Value
JSON.toJSON GVal m
a, GVal m -> Value
forall a. ToJSON a => a -> Value
JSON.toJSON GVal m
b) of
        (JSON.Array Array
x, JSON.Array Array
y) -> Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Array -> Value
JSON.Array (Array
x Array -> Array -> Array
forall a. Semigroup a => a -> a -> a
<> Array
y)
        (JSON.Object Object
x, JSON.Object Object
y) -> Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Object -> Value
JSON.Object (Object
x Object -> Object -> Object
forall a. Semigroup a => a -> a -> a
<> Object
y)
        (JSON.String Text
x, JSON.String Text
y) -> Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Text -> Value
JSON.String (Text
x Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
y)
        (Value
JSON.Null, Value
b) -> Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Value
b
        (Value
a, Value
JSON.Null) -> Value -> Maybe Value
forall a. a -> Maybe a
Just (Value -> Maybe Value) -> Value -> Maybe Value
forall a b. (a -> b) -> a -> b
$ Value
a
        (Value, Value)
_ -> Maybe Value
forall a. Maybe a
Nothing -- If JSON tags mismatch, use default toJSON impl
    , length :: Maybe Int
length = Int -> Int -> Int
forall a. Num a => a -> a -> a
(+) (Int -> Int -> Int) -> Maybe Int -> Maybe (Int -> Int)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe Int
forall (m :: * -> *). GVal m -> Maybe Int
length GVal m
a Maybe (Int -> Int) -> Maybe Int -> Maybe Int
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> GVal m -> Maybe Int
forall (m :: * -> *). GVal m -> Maybe Int
length GVal m
b
    }

-- | Marshal a GVal between carrier monads.
-- This will lose 'asFunction' information, because functions cannot be
-- transferred to other carrier monads, but it will keep all other data
-- structures intact.
marshalGVal :: GVal m -> GVal n
marshalGVal :: GVal m -> GVal n
marshalGVal GVal m
g =
    GVal :: forall (m :: * -> *).
Maybe [GVal m]
-> Maybe [(Text, GVal m)]
-> Maybe (Text -> Maybe (GVal m))
-> Html
-> Text
-> Bool
-> Maybe Scientific
-> Maybe (Function m)
-> Maybe ByteString
-> Maybe Int
-> Bool
-> Maybe Value
-> GVal m
GVal
        { asList :: Maybe [GVal n]
asList = (GVal m -> GVal n) -> [GVal m] -> [GVal n]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap GVal m -> GVal n
forall (m :: * -> *) (n :: * -> *). GVal m -> GVal n
marshalGVal ([GVal m] -> [GVal n]) -> Maybe [GVal m] -> Maybe [GVal n]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList GVal m
g
        , asDictItems :: Maybe [(Text, GVal n)]
asDictItems = ([(Text, GVal m)] -> [(Text, GVal n)])
-> Maybe [(Text, GVal m)] -> Maybe [(Text, GVal n)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\[(Text, GVal m)]
items -> [(Text
k, GVal m -> GVal n
forall (m :: * -> *) (n :: * -> *). GVal m -> GVal n
marshalGVal GVal m
v) | (Text
k, GVal m
v) <- [(Text, GVal m)]
items]) (GVal m -> Maybe [(Text, GVal m)]
forall (m :: * -> *). GVal m -> Maybe [(Text, GVal m)]
asDictItems GVal m
g)
        , asLookup :: Maybe (Text -> Maybe (GVal n))
asLookup = ((Text -> Maybe (GVal m)) -> Text -> Maybe (GVal n))
-> Maybe (Text -> Maybe (GVal m)) -> Maybe (Text -> Maybe (GVal n))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((GVal m -> GVal n) -> Maybe (GVal m) -> Maybe (GVal n)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap GVal m -> GVal n
forall (m :: * -> *) (n :: * -> *). GVal m -> GVal n
marshalGVal (Maybe (GVal m) -> Maybe (GVal n))
-> (Text -> Maybe (GVal m)) -> Text -> Maybe (GVal n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) (GVal m -> Maybe (Text -> Maybe (GVal m))
forall (m :: * -> *). GVal m -> Maybe (Text -> Maybe (GVal m))
asLookup GVal m
g)
        , asHtml :: Html
asHtml = GVal m -> Html
forall (m :: * -> *). GVal m -> Html
asHtml GVal m
g
        , asText :: Text
asText = GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText GVal m
g
        , asBytes :: Maybe ByteString
asBytes = GVal m -> Maybe ByteString
forall (m :: * -> *). GVal m -> Maybe ByteString
asBytes GVal m
g
        , asBoolean :: Bool
asBoolean = GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
asBoolean GVal m
g
        , asNumber :: Maybe Scientific
asNumber = GVal m -> Maybe Scientific
forall (m :: * -> *). GVal m -> Maybe Scientific
asNumber GVal m
g
        , asFunction :: Maybe (Function n)
asFunction = Maybe (Function n)
forall a. Maybe a
Nothing
        , isNull :: Bool
isNull = GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
isNull GVal m
g
        , length :: Maybe Int
length = GVal m -> Maybe Int
forall (m :: * -> *). GVal m -> Maybe Int
length GVal m
g
        , asJSON :: Maybe Value
asJSON = GVal m -> Maybe Value
forall (m :: * -> *). GVal m -> Maybe Value
asJSON GVal m
g
        }

-- | Marshal a GVal between carrier monads.
-- Unlike 'marshalGVal', 'asFunction' information is retained by hoisting
-- them using the provided hoisting functions. For 'Run' monads, which is
-- what 'GVal' is typically used with, the 'hoistRun' function can be used
-- to construct suitable hoisting functions.
marshalGValEx :: (Functor m, Functor n)
              => (forall a. m a -> n a)
              -> (forall a. n a -> m a)
              -> GVal m
              -> GVal n
marshalGValEx :: (forall a. m a -> n a)
-> (forall a. n a -> m a) -> GVal m -> GVal n
marshalGValEx forall a. m a -> n a
hoist forall a. n a -> m a
unhoist GVal m
g =
    GVal :: forall (m :: * -> *).
Maybe [GVal m]
-> Maybe [(Text, GVal m)]
-> Maybe (Text -> Maybe (GVal m))
-> Html
-> Text
-> Bool
-> Maybe Scientific
-> Maybe (Function m)
-> Maybe ByteString
-> Maybe Int
-> Bool
-> Maybe Value
-> GVal m
GVal
        { asList :: Maybe [GVal n]
asList = (GVal m -> GVal n) -> [GVal m] -> [GVal n]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((forall a. m a -> n a)
-> (forall a. n a -> m a) -> GVal m -> GVal n
forall (m :: * -> *) (n :: * -> *).
(Functor m, Functor n) =>
(forall a. m a -> n a)
-> (forall a. n a -> m a) -> GVal m -> GVal n
marshalGValEx forall a. m a -> n a
hoist forall a. n a -> m a
unhoist) ([GVal m] -> [GVal n]) -> Maybe [GVal m] -> Maybe [GVal n]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList GVal m
g
        , asDictItems :: Maybe [(Text, GVal n)]
asDictItems = ([(Text, GVal m)] -> [(Text, GVal n)])
-> Maybe [(Text, GVal m)] -> Maybe [(Text, GVal n)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\[(Text, GVal m)]
items -> [(Text
k, (forall a. m a -> n a)
-> (forall a. n a -> m a) -> GVal m -> GVal n
forall (m :: * -> *) (n :: * -> *).
(Functor m, Functor n) =>
(forall a. m a -> n a)
-> (forall a. n a -> m a) -> GVal m -> GVal n
marshalGValEx forall a. m a -> n a
hoist forall a. n a -> m a
unhoist GVal m
v) | (Text
k, GVal m
v) <- [(Text, GVal m)]
items]) (GVal m -> Maybe [(Text, GVal m)]
forall (m :: * -> *). GVal m -> Maybe [(Text, GVal m)]
asDictItems GVal m
g)
        , asLookup :: Maybe (Text -> Maybe (GVal n))
asLookup = ((Text -> Maybe (GVal m)) -> Text -> Maybe (GVal n))
-> Maybe (Text -> Maybe (GVal m)) -> Maybe (Text -> Maybe (GVal n))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((GVal m -> GVal n) -> Maybe (GVal m) -> Maybe (GVal n)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((forall a. m a -> n a)
-> (forall a. n a -> m a) -> GVal m -> GVal n
forall (m :: * -> *) (n :: * -> *).
(Functor m, Functor n) =>
(forall a. m a -> n a)
-> (forall a. n a -> m a) -> GVal m -> GVal n
marshalGValEx forall a. m a -> n a
hoist forall a. n a -> m a
unhoist) (Maybe (GVal m) -> Maybe (GVal n))
-> (Text -> Maybe (GVal m)) -> Text -> Maybe (GVal n)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) (GVal m -> Maybe (Text -> Maybe (GVal m))
forall (m :: * -> *). GVal m -> Maybe (Text -> Maybe (GVal m))
asLookup GVal m
g)
        , asHtml :: Html
asHtml = GVal m -> Html
forall (m :: * -> *). GVal m -> Html
asHtml GVal m
g
        , asText :: Text
asText = GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText GVal m
g
        , asBytes :: Maybe ByteString
asBytes = GVal m -> Maybe ByteString
forall (m :: * -> *). GVal m -> Maybe ByteString
asBytes GVal m
g
        , asBoolean :: Bool
asBoolean = GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
asBoolean GVal m
g
        , asNumber :: Maybe Scientific
asNumber = GVal m -> Maybe Scientific
forall (m :: * -> *). GVal m -> Maybe Scientific
asNumber GVal m
g
        , asFunction :: Maybe (Function n)
asFunction = (forall a. m a -> n a)
-> (forall a. n a -> m a) -> Function m -> Function n
forall (m :: * -> *) (n :: * -> *).
(Functor m, Functor n) =>
(forall a. m a -> n a)
-> (forall a. n a -> m a) -> Function m -> Function n
marshalFunction forall a. m a -> n a
hoist forall a. n a -> m a
unhoist (Function m -> Function n)
-> Maybe (Function m) -> Maybe (Function n)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe (Function m)
forall (m :: * -> *). GVal m -> Maybe (Function m)
asFunction GVal m
g
        , isNull :: Bool
isNull = GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
isNull GVal m
g
        , length :: Maybe Int
length = GVal m -> Maybe Int
forall (m :: * -> *). GVal m -> Maybe Int
length GVal m
g
        , asJSON :: Maybe Value
asJSON = GVal m -> Maybe Value
forall (m :: * -> *). GVal m -> Maybe Value
asJSON GVal m
g
        }

marshalFunction :: (Functor m, Functor n) => (forall a. m a -> n a) -> (forall a. n a -> m a) -> Function m -> Function n
-- [(Maybe Text, GVal m)] -> m (GVal m)
marshalFunction :: (forall a. m a -> n a)
-> (forall a. n a -> m a) -> Function m -> Function n
marshalFunction forall a. m a -> n a
hoist forall a. n a -> m a
unhoist Function m
f [(Maybe Text, GVal n)]
args =
    let args' :: [(Maybe Text, GVal m)]
args' = [ (Maybe Text
name, (forall a. n a -> m a)
-> (forall a. m a -> n a) -> GVal n -> GVal m
forall (m :: * -> *) (n :: * -> *).
(Functor m, Functor n) =>
(forall a. m a -> n a)
-> (forall a. n a -> m a) -> GVal m -> GVal n
marshalGValEx forall a. n a -> m a
unhoist forall a. m a -> n a
hoist GVal n
value)
                | (Maybe Text
name, GVal n
value) <- [(Maybe Text, GVal n)]
args
                ]
    in (forall a. m a -> n a)
-> (forall a. n a -> m a) -> GVal m -> GVal n
forall (m :: * -> *) (n :: * -> *).
(Functor m, Functor n) =>
(forall a. m a -> n a)
-> (forall a. n a -> m a) -> GVal m -> GVal n
marshalGValEx forall a. m a -> n a
hoist forall a. n a -> m a
unhoist (GVal m -> GVal n) -> n (GVal m) -> n (GVal n)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m (GVal m) -> n (GVal m)
forall a. m a -> n a
hoist (Function m
f [(Maybe Text, GVal m)]
args')

-- | Convenience wrapper around 'asDictItems' to represent a 'GVal' as a
-- 'HashMap'.
asHashMap :: GVal m -> Maybe (HashMap Text (GVal m))
asHashMap :: GVal m -> Maybe (HashMap Text (GVal m))
asHashMap GVal m
g = [(Text, GVal m)] -> HashMap Text (GVal m)
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList ([(Text, GVal m)] -> HashMap Text (GVal m))
-> Maybe [(Text, GVal m)] -> Maybe (HashMap Text (GVal m))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe [(Text, GVal m)]
forall (m :: * -> *). GVal m -> Maybe [(Text, GVal m)]
asDictItems GVal m
g

-- | The default 'GVal' is equivalent to NULL.
instance Default (GVal m) where
    def :: GVal m
def = GVal :: forall (m :: * -> *).
Maybe [GVal m]
-> Maybe [(Text, GVal m)]
-> Maybe (Text -> Maybe (GVal m))
-> Html
-> Text
-> Bool
-> Maybe Scientific
-> Maybe (Function m)
-> Maybe ByteString
-> Maybe Int
-> Bool
-> Maybe Value
-> GVal m
GVal
            { asList :: Maybe [GVal m]
asList = Maybe [GVal m]
forall a. Maybe a
Nothing
            , asDictItems :: Maybe [(Text, GVal m)]
asDictItems = Maybe [(Text, GVal m)]
forall a. Maybe a
Nothing
            , asLookup :: Maybe (Text -> Maybe (GVal m))
asLookup = Maybe (Text -> Maybe (GVal m))
forall a. Maybe a
Nothing
            , asHtml :: Html
asHtml = Text -> Html
unsafeRawHtml Text
""
            , asText :: Text
asText = Text
""
            , asBytes :: Maybe ByteString
asBytes = Maybe ByteString
forall a. Maybe a
Nothing
            , asBoolean :: Bool
asBoolean = Bool
False
            , asNumber :: Maybe Scientific
asNumber = Maybe Scientific
forall a. Maybe a
Nothing
            , asFunction :: Maybe (Function m)
asFunction = Maybe (Function m)
forall a. Maybe a
Nothing
            , isNull :: Bool
isNull = Bool
True
            , length :: Maybe Int
length = Maybe Int
forall a. Maybe a
Nothing
            , asJSON :: Maybe Value
asJSON = Maybe Value
forall a. Maybe a
Nothing
            }

-- | Conversion to JSON values attempts the following conversions, in order:
--
-- - check the 'isNull' property; if it is 'True', always return 'Null',
--   even if the GVal implements 'asJSON'
-- - 'asJSON'
-- - 'asList'
-- - 'asDictItems' (through 'asHashMap')
-- - 'asNumber'
-- - 'asText'
--
-- Note that the default conversions will never return booleans unless 'asJSON'
-- explicitly does this, because 'asText' will always return *something*.
instance JSON.ToJSON (GVal m) where
    toJSON :: GVal m -> Value
toJSON GVal m
g =
        if GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
isNull GVal m
g
            then Value
JSON.Null
            else Value -> Maybe Value -> Value
forall a. a -> Maybe a -> a
fromMaybe (Text -> Value
forall a. ToJSON a => a -> Value
JSON.toJSON (Text -> Value) -> Text -> Value
forall a b. (a -> b) -> a -> b
$ GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText GVal m
g) (Maybe Value -> Value) -> Maybe Value -> Value
forall a b. (a -> b) -> a -> b
$
                    GVal m -> Maybe Value
forall (m :: * -> *). GVal m -> Maybe Value
asJSON GVal m
g Maybe Value -> Maybe Value -> Maybe Value
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
                    ([GVal m] -> Value
forall a. ToJSON a => a -> Value
JSON.toJSON ([GVal m] -> Value) -> Maybe [GVal m] -> Maybe Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList GVal m
g) Maybe Value -> Maybe Value -> Maybe Value
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
                    (HashMap Text (GVal m) -> Value
forall a. ToJSON a => a -> Value
JSON.toJSON (HashMap Text (GVal m) -> Value)
-> Maybe (HashMap Text (GVal m)) -> Maybe Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe (HashMap Text (GVal m))
forall (m :: * -> *). GVal m -> Maybe (HashMap Text (GVal m))
asHashMap GVal m
g) Maybe Value -> Maybe Value -> Maybe Value
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|>
                    (Scientific -> Value
forall a. ToJSON a => a -> Value
JSON.toJSON (Scientific -> Value) -> Maybe Scientific -> Maybe Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe Scientific
forall (m :: * -> *). GVal m -> Maybe Scientific
asNumber GVal m
g)

-- | For convenience, 'Show' is implemented in a way that looks similar to
-- JavaScript / JSON
instance Show (GVal m) where
    show :: GVal m -> String
show GVal m
v
        | GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
isNull GVal m
v = String
"null"
        | Maybe (Function m) -> Bool
forall a. Maybe a -> Bool
isJust (GVal m -> Maybe (Function m)
forall (m :: * -> *). GVal m -> Maybe (Function m)
asFunction GVal m
v) = String
"<<function>>"
        | Maybe [(Text, GVal m)] -> Bool
forall a. Maybe a -> Bool
isJust (GVal m -> Maybe [(Text, GVal m)]
forall (m :: * -> *). GVal m -> Maybe [(Text, GVal m)]
asDictItems GVal m
v) =
            let items :: [String]
items = [ Text -> String
forall a. Show a => a -> String
show Text
k String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
": " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> GVal m -> String
forall a. Show a => a -> String
show GVal m
v | (Text
k, GVal m
v) <- [(Text, GVal m)] -> Maybe [(Text, GVal m)] -> [(Text, GVal m)]
forall a. a -> Maybe a -> a
fromMaybe [] (GVal m -> Maybe [(Text, GVal m)]
forall (m :: * -> *). GVal m -> Maybe [(Text, GVal m)]
asDictItems GVal m
v) ]
                      [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [ Integer -> String
forall a. Show a => a -> String
show Integer
k String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
": " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> GVal m -> String
forall a. Show a => a -> String
show GVal m
v | (Integer
k, GVal m
v) <- [Integer] -> [GVal m] -> [(Integer, GVal m)]
forall a b. [a] -> [b] -> [(a, b)]
Prelude.zip [Integer
0..] ([GVal m] -> Maybe [GVal m] -> [GVal m]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [GVal m] -> [GVal m]) -> Maybe [GVal m] -> [GVal m]
forall a b. (a -> b) -> a -> b
$ GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList GVal m
v) ]
            in String
"{" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> ([String] -> String
forall a. Monoid a => [a] -> a
mconcat ([String] -> String)
-> ([String] -> [String]) -> [String] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String] -> [String]
forall a. a -> [a] -> [a]
List.intersperse String
", " ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ [String]
items) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"}"
        | Maybe [GVal m] -> Bool
forall a. Maybe a -> Bool
isJust (GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList GVal m
v) = String
"[" String -> ShowS
forall a. Semigroup a => a -> a -> a
<> ([String] -> String
forall a. Monoid a => [a] -> a
mconcat ([String] -> String)
-> ([GVal m] -> [String]) -> [GVal m] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String] -> [String]
forall a. a -> [a] -> [a]
List.intersperse String
", " ([String] -> [String])
-> ([GVal m] -> [String]) -> [GVal m] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GVal m -> String) -> [GVal m] -> [String]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map GVal m -> String
forall a. Show a => a -> String
show ([GVal m] -> String) -> [GVal m] -> String
forall a b. (a -> b) -> a -> b
$ [GVal m] -> Maybe [GVal m] -> [GVal m]
forall a. a -> Maybe a -> a
fromMaybe [] (GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList GVal m
v)) String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
"]"
        | Maybe Scientific -> Bool
forall a. Maybe a -> Bool
isJust (GVal m -> Maybe Scientific
forall (m :: * -> *). GVal m -> Maybe Scientific
asNumber GVal m
v) =
            case Scientific -> Either Double Integer
forall r i. (RealFloat r, Integral i) => Scientific -> Either r i
floatingOrInteger (Scientific -> Either Double Integer)
-> Maybe Scientific -> Maybe (Either Double Integer)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe Scientific
forall (m :: * -> *). GVal m -> Maybe Scientific
asNumber GVal m
v :: Maybe (Either Double Integer) of
                Just (Left Double
x) -> Maybe Scientific -> String
forall a. Show a => a -> String
show (GVal m -> Maybe Scientific
forall (m :: * -> *). GVal m -> Maybe Scientific
asNumber GVal m
v)
                Just (Right Integer
x) -> Integer -> String
forall a. Show a => a -> String
show Integer
x
                Maybe (Either Double Integer)
Nothing -> String
""
        | Bool
otherwise = Text -> String
forall a. Show a => a -> String
show (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText GVal m
v

-- | Converting to HTML hooks into the ToHtml instance for 'Text' for most tags.
-- Tags that have no obvious textual representation render as empty HTML.
instance ToHtml (GVal m) where
    toHtml :: GVal m -> Html
toHtml = GVal m -> Html
forall (m :: * -> *). GVal m -> Html
asHtml

instance PrintfArg (GVal m) where
    formatArg :: GVal m -> FieldFormatter
formatArg GVal m
x FieldFormat
fmt =
        case FieldFormat -> Char
fmtChar (Char -> FieldFormat -> FieldFormat
vFmt Char
's' FieldFormat
fmt) of
            Char
's' -> String -> FieldFormatter
forall a. IsChar a => [a] -> FieldFormatter
formatString
                    (Text -> String
Text.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText GVal m
x)
                    (FieldFormat
fmt { fmtChar :: Char
fmtChar = Char
's', fmtPrecision :: Maybe Int
fmtPrecision = Maybe Int
forall a. Maybe a
Nothing })
            Char
'c' -> String -> FieldFormatter
forall a. IsChar a => [a] -> FieldFormatter
formatString
                    (Text -> String
Text.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$ GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText GVal m
x)
                    FieldFormat
fmt
            Char
f -> if Char
f Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`Prelude.elem` [Char
'f', Char
'F', Char
'g', Char
'G', Char
'e', Char
'E']
                    then Double -> FieldFormatter
forall a. RealFloat a => a -> FieldFormatter
formatRealFloat (Scientific -> Double
forall a. RealFloat a => Scientific -> a
toRealFloat (Scientific -> Double)
-> (GVal m -> Scientific) -> GVal m -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scientific -> Maybe Scientific -> Scientific
forall a. a -> Maybe a -> a
fromMaybe Scientific
0 (Maybe Scientific -> Scientific)
-> (GVal m -> Maybe Scientific) -> GVal m -> Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GVal m -> Maybe Scientific
forall (m :: * -> *). GVal m -> Maybe Scientific
asNumber (GVal m -> Double) -> GVal m -> Double
forall a b. (a -> b) -> a -> b
$ GVal m
x) FieldFormat
fmt
                    else Integer -> FieldFormatter
formatInteger (Scientific -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
Prelude.round (Scientific -> Integer)
-> (GVal m -> Scientific) -> GVal m -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scientific -> Maybe Scientific -> Scientific
forall a. a -> Maybe a -> a
fromMaybe Scientific
0 (Maybe Scientific -> Scientific)
-> (GVal m -> Maybe Scientific) -> GVal m -> Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GVal m -> Maybe Scientific
forall (m :: * -> *). GVal m -> Maybe Scientific
asNumber (GVal m -> Integer) -> GVal m -> Integer
forall a b. (a -> b) -> a -> b
$ GVal m
x) FieldFormat
fmt

-- * Representing functions as 'GVal's
--
-- | A function that can be called from within a template execution context.
type Function m = [(Maybe Text, GVal m)] -> m (GVal m)

-- | Match arguments passed to a function at runtime against a list of declared
-- argument names.
-- @matchFuncArgs argNames argsPassed@ returns @(matchedArgs, positionalArgs, namedArgs)@,
-- where @matchedArgs@ is a list of arguments matched against declared names
-- (by name or by position), @positionalArgs@ are the unused positional
-- (unnamed) arguments, and @namedArgs@ are the unused named arguments.
matchFuncArgs :: [Text] -> [(Maybe Text, GVal m)] -> (HashMap Text (GVal m), [GVal m], HashMap Text (GVal m))
matchFuncArgs :: [Text]
-> [(Maybe Text, GVal m)]
-> (HashMap Text (GVal m), [GVal m], HashMap Text (GVal m))
matchFuncArgs [Text]
names [(Maybe Text, GVal m)]
args =
    (HashMap Text (GVal m)
matched, [GVal m]
positional, HashMap Text (GVal m)
named)
    where
        positionalRaw :: [GVal m]
positionalRaw = [ GVal m
v | (Maybe Text
Nothing, GVal m
v) <- [(Maybe Text, GVal m)]
args ]
        namedRaw :: HashMap Text (GVal m)
namedRaw = [(Text, GVal m)] -> HashMap Text (GVal m)
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList [ (Text
n, GVal m
v) | (Just Text
n, GVal m
v) <- [(Maybe Text, GVal m)]
args ]
        fromPositional :: [(Text, GVal m)]
fromPositional = [Text] -> [GVal m] -> [(Text, GVal m)]
forall a b. [a] -> [b] -> [(a, b)]
Prelude.zip [Text]
names [GVal m]
positionalRaw
        numPositional :: Int
numPositional = [(Text, GVal m)] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
Prelude.length [(Text, GVal m)]
fromPositional
        namesRemaining :: [Text]
namesRemaining = Int -> [Text] -> [Text]
forall a. Int -> [a] -> [a]
Prelude.drop Int
numPositional [Text]
names
        positional :: [GVal m]
positional = Int -> [GVal m] -> [GVal m]
forall a. Int -> [a] -> [a]
Prelude.drop Int
numPositional [GVal m]
positionalRaw
        fromNamed :: [(Text, GVal m)]
fromNamed = (Text -> Maybe (Text, GVal m)) -> [Text] -> [(Text, GVal m)]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Text -> Maybe (Text, GVal m)
lookupName [Text]
namesRemaining
        lookupName :: Text -> Maybe (Text, GVal m)
lookupName Text
n = do
            GVal m
v <- Text -> HashMap Text (GVal m) -> Maybe (GVal m)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HashMap.lookup Text
n HashMap Text (GVal m)
namedRaw
            (Text, GVal m) -> Maybe (Text, GVal m)
forall (m :: * -> *) a. Monad m => a -> m a
return (Text
n, GVal m
v)
        matched :: HashMap Text (GVal m)
matched = [(Text, GVal m)] -> HashMap Text (GVal m)
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList ([(Text, GVal m)] -> HashMap Text (GVal m))
-> [(Text, GVal m)] -> HashMap Text (GVal m)
forall a b. (a -> b) -> a -> b
$ [(Text, GVal m)]
fromPositional [(Text, GVal m)] -> [(Text, GVal m)] -> [(Text, GVal m)]
forall a. [a] -> [a] -> [a]
++ [(Text, GVal m)]
fromNamed
        named :: HashMap Text (GVal m)
named = HashMap Text (GVal m)
-> HashMap Text (GVal m) -> HashMap Text (GVal m)
forall k v w.
(Eq k, Hashable k) =>
HashMap k v -> HashMap k w -> HashMap k v
HashMap.difference HashMap Text (GVal m)
namedRaw ([(Text, GVal m)] -> HashMap Text (GVal m)
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList [(Text, GVal m)]
fromNamed)

-- * Marshalling from Haskell to 'GVal'
--
-- | Types that implement conversion to 'GVal'.
class ToGVal m a where
    toGVal :: a -> GVal m

-- | Trivial instance for 'GVal' itself.
instance ToGVal m (GVal m) where
    toGVal :: GVal m -> GVal m
toGVal = GVal m -> GVal m
forall a. a -> a
id

instance ToGVal m () where
    toGVal :: () -> GVal m
toGVal = GVal m -> () -> GVal m
forall a b. a -> b -> a
const GVal m
forall a. Default a => a
def

-- | 'Nothing' becomes NULL, 'Just' unwraps.
instance ToGVal m v => ToGVal m (Maybe v) where
    toGVal :: Maybe v -> GVal m
toGVal Maybe v
Nothing = GVal m
forall a. Default a => a
def { asJSON :: Maybe Value
asJSON = Value -> Maybe Value
forall a. a -> Maybe a
Just Value
JSON.Null }
    toGVal (Just v
x) = v -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal v
x

-- | Haskell lists become list-like 'GVal's
instance ToGVal m v => ToGVal m [v] where
    toGVal :: [v] -> GVal m
toGVal [v]
xs = [GVal m] -> GVal m
helper ((v -> GVal m) -> [v] -> [GVal m]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map v -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal [v]
xs)
        where
            helper :: [GVal m] -> GVal m
            helper :: [GVal m] -> GVal m
helper [GVal m]
xs =
                GVal m
forall a. Default a => a
def
                    { asHtml :: Html
asHtml = [Html] -> Html
forall a. Monoid a => [a] -> a
mconcat ([Html] -> Html) -> ([GVal m] -> [Html]) -> [GVal m] -> Html
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GVal m -> Html) -> [GVal m] -> [Html]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map GVal m -> Html
forall (m :: * -> *). GVal m -> Html
asHtml ([GVal m] -> Html) -> [GVal m] -> Html
forall a b. (a -> b) -> a -> b
$ [GVal m]
xs
                    , asText :: Text
asText = [Text] -> Text
forall a. Monoid a => [a] -> a
mconcat ([Text] -> Text) -> ([GVal m] -> [Text]) -> [GVal m] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GVal m -> Text) -> [GVal m] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText ([GVal m] -> Text) -> [GVal m] -> Text
forall a b. (a -> b) -> a -> b
$ [GVal m]
xs
                    , asBytes :: Maybe ByteString
asBytes = [Maybe ByteString] -> Maybe ByteString
forall a. Monoid a => [a] -> a
mconcat ([Maybe ByteString] -> Maybe ByteString)
-> ([GVal m] -> [Maybe ByteString]) -> [GVal m] -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GVal m -> Maybe ByteString) -> [GVal m] -> [Maybe ByteString]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map GVal m -> Maybe ByteString
forall (m :: * -> *). GVal m -> Maybe ByteString
asBytes ([GVal m] -> Maybe ByteString) -> [GVal m] -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ [GVal m]
xs
                    , asBoolean :: Bool
asBoolean = Bool -> Bool
not (Bool -> Bool) -> ([GVal m] -> Bool) -> [GVal m] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [GVal m] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
List.null ([GVal m] -> Bool) -> [GVal m] -> Bool
forall a b. (a -> b) -> a -> b
$ [GVal m]
xs
                    , isNull :: Bool
isNull = Bool
False
                    , asList :: Maybe [GVal m]
asList = [GVal m] -> Maybe [GVal m]
forall a. a -> Maybe a
Just ([GVal m] -> Maybe [GVal m]) -> [GVal m] -> Maybe [GVal m]
forall a b. (a -> b) -> a -> b
$ (GVal m -> GVal m) -> [GVal m] -> [GVal m]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map GVal m -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal [GVal m]
xs
                    , length :: Maybe Int
length = Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$ [GVal m] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
Prelude.length [GVal m]
xs
                    }

-- | 'HashMap' of 'Text' becomes a dictionary-like 'GVal'
instance ToGVal m v => ToGVal m (HashMap Text v) where
    toGVal :: HashMap Text v -> GVal m
toGVal HashMap Text v
xs = HashMap Text (GVal m) -> GVal m
helper ((v -> GVal m) -> HashMap Text v -> HashMap Text (GVal m)
forall v1 v2 k. (v1 -> v2) -> HashMap k v1 -> HashMap k v2
HashMap.map v -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal HashMap Text v
xs)
        where
            helper :: HashMap Text (GVal m) -> GVal m
            helper :: HashMap Text (GVal m) -> GVal m
helper HashMap Text (GVal m)
xs =
                GVal m
forall a. Default a => a
def
                    { asHtml :: Html
asHtml = [Html] -> Html
forall a. Monoid a => [a] -> a
mconcat ([Html] -> Html)
-> (HashMap Text (GVal m) -> [Html])
-> HashMap Text (GVal m)
-> Html
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GVal m -> Html) -> [GVal m] -> [Html]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map GVal m -> Html
forall (m :: * -> *). GVal m -> Html
asHtml ([GVal m] -> [Html])
-> (HashMap Text (GVal m) -> [GVal m])
-> HashMap Text (GVal m)
-> [Html]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap Text (GVal m) -> [GVal m]
forall k v. HashMap k v -> [v]
HashMap.elems (HashMap Text (GVal m) -> Html) -> HashMap Text (GVal m) -> Html
forall a b. (a -> b) -> a -> b
$ HashMap Text (GVal m)
xs
                    , asText :: Text
asText = [Text] -> Text
forall a. Monoid a => [a] -> a
mconcat ([Text] -> Text)
-> (HashMap Text (GVal m) -> [Text])
-> HashMap Text (GVal m)
-> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GVal m -> Text) -> [GVal m] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText ([GVal m] -> [Text])
-> (HashMap Text (GVal m) -> [GVal m])
-> HashMap Text (GVal m)
-> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap Text (GVal m) -> [GVal m]
forall k v. HashMap k v -> [v]
HashMap.elems (HashMap Text (GVal m) -> Text) -> HashMap Text (GVal m) -> Text
forall a b. (a -> b) -> a -> b
$ HashMap Text (GVal m)
xs
                    , asBytes :: Maybe ByteString
asBytes = [Maybe ByteString] -> Maybe ByteString
forall a. Monoid a => [a] -> a
mconcat ([Maybe ByteString] -> Maybe ByteString)
-> (HashMap Text (GVal m) -> [Maybe ByteString])
-> HashMap Text (GVal m)
-> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GVal m -> Maybe ByteString) -> [GVal m] -> [Maybe ByteString]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map GVal m -> Maybe ByteString
forall (m :: * -> *). GVal m -> Maybe ByteString
asBytes ([GVal m] -> [Maybe ByteString])
-> (HashMap Text (GVal m) -> [GVal m])
-> HashMap Text (GVal m)
-> [Maybe ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap Text (GVal m) -> [GVal m]
forall k v. HashMap k v -> [v]
HashMap.elems (HashMap Text (GVal m) -> Maybe ByteString)
-> HashMap Text (GVal m) -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ HashMap Text (GVal m)
xs
                    , asBoolean :: Bool
asBoolean = Bool -> Bool
not (Bool -> Bool)
-> (HashMap Text (GVal m) -> Bool) -> HashMap Text (GVal m) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashMap Text (GVal m) -> Bool
forall k v. HashMap k v -> Bool
HashMap.null (HashMap Text (GVal m) -> Bool) -> HashMap Text (GVal m) -> Bool
forall a b. (a -> b) -> a -> b
$ HashMap Text (GVal m)
xs
                    , isNull :: Bool
isNull = Bool
False
                    , asLookup :: Maybe (Text -> Maybe (GVal m))
asLookup = (Text -> Maybe (GVal m)) -> Maybe (Text -> Maybe (GVal m))
forall a. a -> Maybe a
Just (Text -> HashMap Text (GVal m) -> Maybe (GVal m)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
`HashMap.lookup` HashMap Text (GVal m)
xs)
                    , asDictItems :: Maybe [(Text, GVal m)]
asDictItems = [(Text, GVal m)] -> Maybe [(Text, GVal m)]
forall a. a -> Maybe a
Just ([(Text, GVal m)] -> Maybe [(Text, GVal m)])
-> [(Text, GVal m)] -> Maybe [(Text, GVal m)]
forall a b. (a -> b) -> a -> b
$ HashMap Text (GVal m) -> [(Text, GVal m)]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList HashMap Text (GVal m)
xs
                    }

-- | 'Map' of 'Text' becomes a dictionary-like 'GVal'
instance ToGVal m v => ToGVal m (Map Text v) where
    toGVal :: Map Text v -> GVal m
toGVal Map Text v
xs = Map Text (GVal m) -> GVal m
helper ((v -> GVal m) -> Map Text v -> Map Text (GVal m)
forall a b k. (a -> b) -> Map k a -> Map k b
Map.map v -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal Map Text v
xs)
        where
            helper :: Map Text (GVal m) -> GVal m
            helper :: Map Text (GVal m) -> GVal m
helper Map Text (GVal m)
xs =
                GVal m
forall a. Default a => a
def
                    { asHtml :: Html
asHtml = [Html] -> Html
forall a. Monoid a => [a] -> a
mconcat ([Html] -> Html)
-> (Map Text (GVal m) -> [Html]) -> Map Text (GVal m) -> Html
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GVal m -> Html) -> [GVal m] -> [Html]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map GVal m -> Html
forall (m :: * -> *). GVal m -> Html
asHtml ([GVal m] -> [Html])
-> (Map Text (GVal m) -> [GVal m]) -> Map Text (GVal m) -> [Html]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map Text (GVal m) -> [GVal m]
forall k a. Map k a -> [a]
Map.elems (Map Text (GVal m) -> Html) -> Map Text (GVal m) -> Html
forall a b. (a -> b) -> a -> b
$ Map Text (GVal m)
xs
                    , asText :: Text
asText = [Text] -> Text
forall a. Monoid a => [a] -> a
mconcat ([Text] -> Text)
-> (Map Text (GVal m) -> [Text]) -> Map Text (GVal m) -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GVal m -> Text) -> [GVal m] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText ([GVal m] -> [Text])
-> (Map Text (GVal m) -> [GVal m]) -> Map Text (GVal m) -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map Text (GVal m) -> [GVal m]
forall k a. Map k a -> [a]
Map.elems (Map Text (GVal m) -> Text) -> Map Text (GVal m) -> Text
forall a b. (a -> b) -> a -> b
$ Map Text (GVal m)
xs
                    , asBytes :: Maybe ByteString
asBytes = [Maybe ByteString] -> Maybe ByteString
forall a. Monoid a => [a] -> a
mconcat ([Maybe ByteString] -> Maybe ByteString)
-> (Map Text (GVal m) -> [Maybe ByteString])
-> Map Text (GVal m)
-> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (GVal m -> Maybe ByteString) -> [GVal m] -> [Maybe ByteString]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map GVal m -> Maybe ByteString
forall (m :: * -> *). GVal m -> Maybe ByteString
asBytes ([GVal m] -> [Maybe ByteString])
-> (Map Text (GVal m) -> [GVal m])
-> Map Text (GVal m)
-> [Maybe ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map Text (GVal m) -> [GVal m]
forall k a. Map k a -> [a]
Map.elems (Map Text (GVal m) -> Maybe ByteString)
-> Map Text (GVal m) -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ Map Text (GVal m)
xs
                    , asBoolean :: Bool
asBoolean = Bool -> Bool
not (Bool -> Bool)
-> (Map Text (GVal m) -> Bool) -> Map Text (GVal m) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map Text (GVal m) -> Bool
forall k a. Map k a -> Bool
Map.null (Map Text (GVal m) -> Bool) -> Map Text (GVal m) -> Bool
forall a b. (a -> b) -> a -> b
$ Map Text (GVal m)
xs
                    , isNull :: Bool
isNull = Bool
False
                    , asLookup :: Maybe (Text -> Maybe (GVal m))
asLookup = (Text -> Maybe (GVal m)) -> Maybe (Text -> Maybe (GVal m))
forall a. a -> Maybe a
Just (Text -> Map Text (GVal m) -> Maybe (GVal m)
forall k a. Ord k => k -> Map k a -> Maybe a
`Map.lookup` Map Text (GVal m)
xs)
                    , asDictItems :: Maybe [(Text, GVal m)]
asDictItems = [(Text, GVal m)] -> Maybe [(Text, GVal m)]
forall a. a -> Maybe a
Just ([(Text, GVal m)] -> Maybe [(Text, GVal m)])
-> [(Text, GVal m)] -> Maybe [(Text, GVal m)]
forall a b. (a -> b) -> a -> b
$ Map Text (GVal m) -> [(Text, GVal m)]
forall k a. Map k a -> [(k, a)]
Map.toAscList Map Text (GVal m)
xs
                    }

instance ToGVal m Int where
    toGVal :: Int -> GVal m
toGVal Int
x =
        GVal m
forall a. Default a => a
def
            { asHtml :: Html
asHtml = Text -> Html
html (Text -> Html) -> (Int -> Text) -> Int -> Html
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack (String -> Text) -> (Int -> String) -> Int -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
show (Int -> Html) -> Int -> Html
forall a b. (a -> b) -> a -> b
$ Int
x
            , asText :: Text
asText = String -> Text
Text.pack (String -> Text) -> (Int -> String) -> Int -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String
forall a. Show a => a -> String
show (Int -> Text) -> Int -> Text
forall a b. (a -> b) -> a -> b
$ Int
x
            , asBoolean :: Bool
asBoolean = Int
x Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0
            , asNumber :: Maybe Scientific
asNumber = Scientific -> Maybe Scientific
forall a. a -> Maybe a
Just (Scientific -> Maybe Scientific)
-> (Int -> Scientific) -> Int -> Maybe Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Scientific
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Maybe Scientific) -> Int -> Maybe Scientific
forall a b. (a -> b) -> a -> b
$ Int
x
            , isNull :: Bool
isNull = Bool
False
            }

instance ToGVal m Integer where
    toGVal :: Integer -> GVal m
toGVal Integer
x =
        GVal m
forall a. Default a => a
def
            { asHtml :: Html
asHtml = Text -> Html
html (Text -> Html) -> (Integer -> Text) -> Integer -> Html
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack (String -> Text) -> (Integer -> String) -> Integer -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> String
forall a. Show a => a -> String
show (Integer -> Html) -> Integer -> Html
forall a b. (a -> b) -> a -> b
$ Integer
x
            , asText :: Text
asText = String -> Text
Text.pack (String -> Text) -> (Integer -> String) -> Integer -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> String
forall a. Show a => a -> String
show (Integer -> Text) -> Integer -> Text
forall a b. (a -> b) -> a -> b
$ Integer
x
            , asBytes :: Maybe ByteString
asBytes = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (Integer -> ByteString) -> Integer -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8 (Text -> ByteString) -> (Integer -> Text) -> Integer -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack (String -> Text) -> (Integer -> String) -> Integer -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> String
forall a. Show a => a -> String
show (Integer -> Maybe ByteString) -> Integer -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ Integer
x
            , asBoolean :: Bool
asBoolean = Integer
x Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
/= Integer
0
            , asNumber :: Maybe Scientific
asNumber = Scientific -> Maybe Scientific
forall a. a -> Maybe a
Just (Scientific -> Maybe Scientific)
-> (Integer -> Scientific) -> Integer -> Maybe Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Scientific
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Maybe Scientific) -> Integer -> Maybe Scientific
forall a b. (a -> b) -> a -> b
$ Integer
x
            , isNull :: Bool
isNull = Bool
False
            }

instance ToGVal m Scientific where
    toGVal :: Scientific -> GVal m
toGVal Scientific
x =
        GVal m
forall a. Default a => a
def
            { asHtml :: Html
asHtml = Text -> Html
html (Text -> Html) -> Text -> Html
forall a b. (a -> b) -> a -> b
$ Scientific -> Text
scientificToText Scientific
x
            , asText :: Text
asText = Scientific -> Text
scientificToText Scientific
x
            , asBytes :: Maybe ByteString
asBytes = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (Scientific -> ByteString) -> Scientific -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8 (Text -> ByteString)
-> (Scientific -> Text) -> Scientific -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scientific -> Text
scientificToText (Scientific -> Maybe ByteString) -> Scientific -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ Scientific
x
            , asBoolean :: Bool
asBoolean = Scientific
x Scientific -> Scientific -> Bool
forall a. Eq a => a -> a -> Bool
/= Scientific
0
            , asNumber :: Maybe Scientific
asNumber = Scientific -> Maybe Scientific
forall a. a -> Maybe a
Just Scientific
x
            , isNull :: Bool
isNull = Bool
False
            }

instance ToGVal m Day where
    toGVal :: Day -> GVal m
toGVal Day
x =
        let dayDict :: [(Text, GVal m)]
dayDict = Day -> [(Text, GVal m)]
forall (m :: * -> *). Day -> [(Text, GVal m)]
dayToDict Day
x
            julian :: Integer
julian = Day -> Integer
toModifiedJulianDay Day
x
            formatted :: Text
formatted = String -> Text
Text.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ TimeLocale -> String -> Day -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
"%0Y-%m-%d" Day
x
        in ([Pair m] -> GVal m
forall (m :: * -> *). [Pair m] -> GVal m
orderedDict [Pair m]
forall (m :: * -> *). [(Text, GVal m)]
dayDict)
            { asHtml :: Html
asHtml = Text -> Html
html (Text -> Html) -> Text -> Html
forall a b. (a -> b) -> a -> b
$ Text
formatted
            , asText :: Text
asText = Text
formatted
            , asBytes :: Maybe ByteString
asBytes = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (Text -> ByteString) -> Text -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8 (Text -> Maybe ByteString) -> Text -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ Text
formatted
            , asBoolean :: Bool
asBoolean = Bool
True
            , asNumber :: Maybe Scientific
asNumber = Scientific -> Maybe Scientific
forall a. a -> Maybe a
Just (Scientific -> Maybe Scientific)
-> (Integer -> Scientific) -> Integer -> Maybe Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Scientific
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Maybe Scientific) -> Integer -> Maybe Scientific
forall a b. (a -> b) -> a -> b
$ Integer
julian
            , asList :: Maybe [GVal m]
asList = [GVal m] -> Maybe [GVal m]
forall a. a -> Maybe a
Just ((Pair m -> GVal m) -> [Pair m] -> [GVal m]
forall a b. (a -> b) -> [a] -> [b]
List.map Pair m -> GVal m
forall a b. (a, b) -> b
snd [Pair m]
forall (m :: * -> *). [(Text, GVal m)]
dayDict)
            }

dayToDict :: Day -> [(Text, GVal m)]
dayToDict :: Day -> [(Text, GVal m)]
dayToDict Day
x =
    let (Integer
year, Int
month, Int
day) = Day -> (Integer, Int, Int)
toGregorian Day
x
    in [ Text
"year" Text -> Integer -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> Integer
year
        , Text
"month" Text -> Int -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> Int
month
        , Text
"day" Text -> Int -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> Int
day
        ]

instance ToGVal m TimeOfDay where
    toGVal :: TimeOfDay -> GVal m
toGVal TimeOfDay
x =
        let timeDict :: [(Text, GVal m)]
timeDict = TimeOfDay -> [(Text, GVal m)]
forall (m :: * -> *). TimeOfDay -> [(Text, GVal m)]
timeToDict TimeOfDay
x
            formatted :: Text
formatted = String -> Text
Text.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ TimeLocale -> String -> TimeOfDay -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
"%H:%M:%S" TimeOfDay
x
        in ([Pair m] -> GVal m
forall (m :: * -> *). [Pair m] -> GVal m
orderedDict [Pair m]
forall (m :: * -> *). [(Text, GVal m)]
timeDict)
            { asHtml :: Html
asHtml = Text -> Html
html (Text -> Html) -> Text -> Html
forall a b. (a -> b) -> a -> b
$ Text
formatted
            , asText :: Text
asText = Text
formatted
            , asBytes :: Maybe ByteString
asBytes = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (Text -> ByteString) -> Text -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8 (Text -> Maybe ByteString) -> Text -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ Text
formatted
            , asBoolean :: Bool
asBoolean = Bool
True
            , asNumber :: Maybe Scientific
asNumber = Maybe Scientific
forall a. Maybe a
Nothing
            , asList :: Maybe [GVal m]
asList = [GVal m] -> Maybe [GVal m]
forall a. a -> Maybe a
Just ((Pair m -> GVal m) -> [Pair m] -> [GVal m]
forall a b. (a -> b) -> [a] -> [b]
List.map Pair m -> GVal m
forall a b. (a, b) -> b
snd [Pair m]
forall (m :: * -> *). [(Text, GVal m)]
timeDict)
            }

timeToDict :: TimeOfDay -> [(Text, GVal m)]
timeToDict :: TimeOfDay -> [(Text, GVal m)]
timeToDict (TimeOfDay Int
hours Int
minutes Pico
seconds) =
    [ Text
"hours" Text -> Int -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> Int
hours
    , Text
"minutes" Text -> Int -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> Int
minutes
    , Text
"seconds" Text -> Scientific -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> Pico -> Scientific
picoToScientific Pico
seconds
    ]

instance ToGVal m LocalTime where
    toGVal :: LocalTime -> GVal m
toGVal LocalTime
x =
        let dtDict :: [(Text, GVal m)]
dtDict = LocalTime -> [(Text, GVal m)]
forall (m :: * -> *). LocalTime -> [(Text, GVal m)]
localTimeToDict LocalTime
x
            formatted :: Text
formatted = String -> Text
Text.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ TimeLocale -> String -> LocalTime -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
"%0Y-%m-%d %H:%M:%S" LocalTime
x
        in ([Pair m] -> GVal m
forall (m :: * -> *). [Pair m] -> GVal m
orderedDict ([Pair m] -> GVal m) -> [Pair m] -> GVal m
forall a b. (a -> b) -> a -> b
$
                [Pair m]
forall (m :: * -> *). [(Text, GVal m)]
dtDict [Pair m] -> [Pair m] -> [Pair m]
forall a. [a] -> [a] -> [a]
++
                [ Text
"date" Text -> Day -> Pair m
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> LocalTime -> Day
localDay LocalTime
x
                , Text
"time" Text -> TimeOfDay -> Pair m
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> LocalTime -> TimeOfDay
localTimeOfDay LocalTime
x
                ])
            { asHtml :: Html
asHtml = Text -> Html
html (Text -> Html) -> Text -> Html
forall a b. (a -> b) -> a -> b
$ Text
formatted
            , asText :: Text
asText = Text
formatted
            , asBytes :: Maybe ByteString
asBytes = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (Text -> ByteString) -> Text -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8 (Text -> Maybe ByteString) -> Text -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ Text
formatted
            , asBoolean :: Bool
asBoolean = Bool
True
            , asNumber :: Maybe Scientific
asNumber = Maybe Scientific
forall a. Maybe a
Nothing
            , asList :: Maybe [GVal m]
asList = [GVal m] -> Maybe [GVal m]
forall a. a -> Maybe a
Just ((Pair m -> GVal m) -> [Pair m] -> [GVal m]
forall a b. (a -> b) -> [a] -> [b]
List.map Pair m -> GVal m
forall a b. (a, b) -> b
snd [Pair m]
forall (m :: * -> *). [(Text, GVal m)]
dtDict)
            }

localTimeToDict :: LocalTime -> [(Text, GVal m)]
localTimeToDict :: LocalTime -> [(Text, GVal m)]
localTimeToDict LocalTime
x =
        let dayDict :: [(Text, GVal m)]
dayDict = Day -> [(Text, GVal m)]
forall (m :: * -> *). Day -> [(Text, GVal m)]
dayToDict (Day -> [(Text, GVal m)]) -> Day -> [(Text, GVal m)]
forall a b. (a -> b) -> a -> b
$ LocalTime -> Day
localDay LocalTime
x
            timeDict :: [(Text, GVal m)]
timeDict = TimeOfDay -> [(Text, GVal m)]
forall (m :: * -> *). TimeOfDay -> [(Text, GVal m)]
timeToDict (TimeOfDay -> [(Text, GVal m)]) -> TimeOfDay -> [(Text, GVal m)]
forall a b. (a -> b) -> a -> b
$ LocalTime -> TimeOfDay
localTimeOfDay LocalTime
x
        in [(Text, GVal m)]
forall (m :: * -> *). [(Text, GVal m)]
dayDict [(Text, GVal m)] -> [(Text, GVal m)] -> [(Text, GVal m)]
forall a. [a] -> [a] -> [a]
++ [(Text, GVal m)]
forall (m :: * -> *). [(Text, GVal m)]
timeDict

instance ToGVal m TimeZone where
    toGVal :: TimeZone -> GVal m
toGVal  = [Pair m] -> GVal m
forall (m :: * -> *). [Pair m] -> GVal m
dict ([Pair m] -> GVal m)
-> (TimeZone -> [Pair m]) -> TimeZone -> GVal m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeZone -> [Pair m]
forall (m :: * -> *). TimeZone -> [(Text, GVal m)]
timeZoneToDict

timeZoneToDict :: TimeZone -> [(Text, GVal m)]
timeZoneToDict :: TimeZone -> [(Text, GVal m)]
timeZoneToDict (TimeZone Int
minutes Bool
summerOnly String
name) =
    [ Text
"minutes" Text -> Int -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> Int
minutes
    , Text
"summerOnly" Text -> Bool -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> Bool
summerOnly
    , Text
"name" Text -> String -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> String
name
    ]

instance ToGVal m TimeLocale where
    toGVal :: TimeLocale -> GVal m
toGVal TimeLocale
t =
        let formattedExample :: Text
formattedExample =
                String -> Text
Text.pack (String -> Text) -> (LocalTime -> String) -> LocalTime -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeLocale -> String -> LocalTime -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
t String
"%c" (LocalTime -> Text) -> LocalTime -> Text
forall a b. (a -> b) -> a -> b
$
                    Day -> TimeOfDay -> LocalTime
LocalTime (Integer -> Int -> Int -> Day
fromGregorian Integer
2000 Int
1 Int
1) (Int -> Int -> Pico -> TimeOfDay
TimeOfDay Int
13 Int
15 Pico
00)
            timeLocaleDict :: [(Text, GVal m)]
timeLocaleDict = TimeLocale -> [(Text, GVal m)]
forall (m :: * -> *). TimeLocale -> [(Text, GVal m)]
timeLocaleToDict TimeLocale
t
        in ([Pair m] -> GVal m
forall (m :: * -> *). [Pair m] -> GVal m
dict [Pair m]
forall (m :: * -> *). [(Text, GVal m)]
timeLocaleDict)
            { asHtml :: Html
asHtml = Text -> Html
html (Text -> Html) -> Text -> Html
forall a b. (a -> b) -> a -> b
$ Text
formattedExample
            , asText :: Text
asText = Text
formattedExample
            , asBytes :: Maybe ByteString
asBytes = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (Text -> ByteString) -> Text -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8 (Text -> Maybe ByteString) -> Text -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ Text
formattedExample
            , asBoolean :: Bool
asBoolean = Bool
True
            , asNumber :: Maybe Scientific
asNumber = Maybe Scientific
forall a. Maybe a
Nothing
            }

timeLocaleToDict :: TimeLocale -> [(Text, GVal m)]
timeLocaleToDict :: TimeLocale -> [(Text, GVal m)]
timeLocaleToDict TimeLocale
t =
    [ Text
"wDays" Text -> [(Text, Text)] -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> ((String, String) -> (Text, Text))
-> [(String, String)] -> [(Text, Text)]
forall a b. (a -> b) -> [a] -> [b]
List.map (String, String) -> (Text, Text)
packPair (TimeLocale -> [(String, String)]
wDays TimeLocale
t)
    , Text
"months" Text -> [(Text, Text)] -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> ((String, String) -> (Text, Text))
-> [(String, String)] -> [(Text, Text)]
forall a b. (a -> b) -> [a] -> [b]
List.map (String, String) -> (Text, Text)
packPair (TimeLocale -> [(String, String)]
months TimeLocale
t)
    , Text
"amPm" Text -> (Text, Text) -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> (String, String) -> (Text, Text)
packPair (TimeLocale -> (String, String)
amPm TimeLocale
t)
    , Text
"dateTimeFmt" Text -> Text -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> String -> Text
Text.pack (TimeLocale -> String
dateTimeFmt TimeLocale
t)
    , Text
"dateFmt" Text -> Text -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> String -> Text
Text.pack (TimeLocale -> String
dateFmt TimeLocale
t)
    , Text
"timeFmt" Text -> Text -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> String -> Text
Text.pack (TimeLocale -> String
timeFmt TimeLocale
t)
    , Text
"time12Fmt" Text -> Text -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> String -> Text
Text.pack (TimeLocale -> String
time12Fmt TimeLocale
t)
    -- TODO
    -- , "knownTimeZones" ~> knownTimeZones t
    , Text
"knownTimeZones" Text -> [Text] -> (Text, GVal m)
forall (m :: * -> *) a. ToGVal m a => Text -> a -> Pair m
~> ([] :: [Text])
    ]

-- TODO: ToGVal instance for ZonedTime
instance ToGVal m ZonedTime where
    toGVal :: ZonedTime -> GVal m
toGVal ZonedTime
x =
        let dtDict :: [(Text, GVal m)]
dtDict = ZonedTime -> [(Text, GVal m)]
forall (m :: * -> *). ZonedTime -> [(Text, GVal m)]
zonedTimeToDict ZonedTime
x
            formatted :: Text
formatted = String -> Text
Text.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ TimeLocale -> String -> ZonedTime -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
"%0Y-%m-%d %H:%M:%S%z" ZonedTime
x
        in ([Pair m] -> GVal m
forall (m :: * -> *). [Pair m] -> GVal m
dict [Pair m]
forall (m :: * -> *). [(Text, GVal m)]
dtDict)
            { asHtml :: Html
asHtml = Text -> Html
html (Text -> Html) -> Text -> Html
forall a b. (a -> b) -> a -> b
$ Text
formatted
            , asText :: Text
asText = Text
formatted
            , asBytes :: Maybe ByteString
asBytes = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (Text -> ByteString) -> Text -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8 (Text -> Maybe ByteString) -> Text -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ Text
formatted
            , asBoolean :: Bool
asBoolean = Bool
True
            , asNumber :: Maybe Scientific
asNumber = Maybe Scientific
forall a. Maybe a
Nothing
            }

zonedTimeToDict :: ZonedTime -> [(Text, GVal m)]
zonedTimeToDict :: ZonedTime -> [(Text, GVal m)]
zonedTimeToDict ZonedTime
t =
    (Text
"tz", TimeZone -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal (TimeZone -> GVal m) -> TimeZone -> GVal m
forall a b. (a -> b) -> a -> b
$ ZonedTime -> TimeZone
zonedTimeZone ZonedTime
t)(Text, GVal m) -> [(Text, GVal m)] -> [(Text, GVal m)]
forall a. a -> [a] -> [a]
:LocalTime -> [(Text, GVal m)]
forall (m :: * -> *). LocalTime -> [(Text, GVal m)]
localTimeToDict (ZonedTime -> LocalTime
zonedTimeToLocalTime ZonedTime
t)

instance (ToGVal m a, ToGVal m b) => ToGVal m (a, b) where
    toGVal :: (a, b) -> GVal m
toGVal (a
a, b
b) = [GVal m] -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal ([ a -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal a
a, b -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal b
b ] :: [GVal m])

instance (ToGVal m a, ToGVal m b, ToGVal m c) => ToGVal m (a, b, c) where
    toGVal :: (a, b, c) -> GVal m
toGVal (a
a, b
b, c
c) = [GVal m] -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal ([ a -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal a
a, b -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal b
b, c -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal c
c ] :: [GVal m])

instance (ToGVal m a, ToGVal m b, ToGVal m c, ToGVal m d) => ToGVal m (a, b, c, d) where
    toGVal :: (a, b, c, d) -> GVal m
toGVal (a
a, b
b, c
c, d
d) = [GVal m] -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal ([ a -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal a
a, b -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal b
b, c -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal c
c, d -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal d
d ] :: [GVal m])

-- | Silly helper function, needed to bypass the default 'Show' instance of
-- 'Scientific' in order to make integral 'Scientific's look like integers.
scientificToText :: Scientific -> Text
scientificToText :: Scientific -> Text
scientificToText Scientific
x =
    String -> Text
Text.pack (String -> Text) -> String -> Text
forall a b. (a -> b) -> a -> b
$ case Scientific -> Either Double Integer
forall r i. (RealFloat r, Integral i) => Scientific -> Either r i
floatingOrInteger Scientific
x of
        Left Double
x -> Double -> String
forall a. Show a => a -> String
show Double
x
        Right Integer
x -> Integer -> String
forall a. Show a => a -> String
show Integer
x

-- | Booleans render as 1 or empty string, and otherwise behave as expected.
instance ToGVal m Bool where
    toGVal :: Bool -> GVal m
toGVal Bool
x =
        GVal m
forall a. Default a => a
def
            { asHtml :: Html
asHtml = if Bool
x then Text -> Html
html Text
"1" else Text -> Html
html Text
""
            , asText :: Text
asText = if Bool
x then Text
"1" else Text
""
            , asBoolean :: Bool
asBoolean = Bool
x
            , asBytes :: Maybe ByteString
asBytes = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString) -> ByteString -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ if Bool
x then ByteString
"1" else ByteString
"0"
            , asNumber :: Maybe Scientific
asNumber = Scientific -> Maybe Scientific
forall a. a -> Maybe a
Just (Scientific -> Maybe Scientific) -> Scientific -> Maybe Scientific
forall a b. (a -> b) -> a -> b
$ if Bool
x then Scientific
1 else Scientific
0
            , isNull :: Bool
isNull = Bool
False
            , asJSON :: Maybe Value
asJSON = Value -> Maybe Value
forall a. a -> Maybe a
Just (Bool -> Value
JSON.Bool Bool
x)
            }

-- | 'String' -> 'GVal' conversion uses the 'IsString' class; because 'String'
-- is an alias for '[Char]', there is also a 'ToGVal' instance for 'String',
-- but it marshals strings as lists of characters, i.e., calling 'toGVal' on
-- a string produces a list of characters on the 'GVal' side.
instance IsString (GVal m) where
    fromString :: String -> GVal m
fromString String
x =
        GVal m
forall a. Default a => a
def
            { asHtml :: Html
asHtml = Text -> Html
html (Text -> Html) -> (String -> Text) -> String -> Html
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack (String -> Html) -> String -> Html
forall a b. (a -> b) -> a -> b
$ String
x
            , asText :: Text
asText = String -> Text
Text.pack String
x
            , asBytes :: Maybe ByteString
asBytes = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (String -> ByteString) -> String -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8 (Text -> ByteString) -> (String -> Text) -> String -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
Text.pack (String -> Maybe ByteString) -> String -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ String
x
            , asBoolean :: Bool
asBoolean = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
Prelude.null String
x
            , asNumber :: Maybe Scientific
asNumber = String -> Maybe Scientific
forall a. Read a => String -> Maybe a
readMay String
x
            , isNull :: Bool
isNull = Bool
False
            , length :: Maybe Int
length = Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> (String -> Int) -> String -> Maybe Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
Prelude.length (String -> Maybe Int) -> String -> Maybe Int
forall a b. (a -> b) -> a -> b
$ String
x
            }

-- | Single characters are treated as length-1 'Text's.
instance ToGVal m Char where
    toGVal :: Char -> GVal m
toGVal = Text -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal (Text -> GVal m) -> (Char -> Text) -> Char -> GVal m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Text
Text.singleton

instance ToGVal m Text where
    toGVal :: Text -> GVal m
toGVal Text
x =
        GVal m
forall a. Default a => a
def
            { asHtml :: Html
asHtml = Text -> Html
html Text
x
            , asText :: Text
asText = Text
x
            , asBytes :: Maybe ByteString
asBytes = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (Text -> ByteString) -> Text -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8 (Text -> Maybe ByteString) -> Text -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ Text
x
            , asBoolean :: Bool
asBoolean = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Text -> Bool
Text.null Text
x
            , asNumber :: Maybe Scientific
asNumber = String -> Maybe Scientific
forall a. Read a => String -> Maybe a
readMay (String -> Maybe Scientific)
-> (Text -> String) -> Text -> Maybe Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
Text.unpack (Text -> Maybe Scientific) -> Text -> Maybe Scientific
forall a b. (a -> b) -> a -> b
$ Text
x
            , isNull :: Bool
isNull = Bool
False
            }

instance ToGVal m LText.Text where
    toGVal :: Text -> GVal m
toGVal Text
x =
        GVal m
forall a. Default a => a
def
            { asHtml :: Html
asHtml = Text -> Html
html (Text -> Text
LText.toStrict Text
x)
            , asText :: Text
asText = Text -> Text
LText.toStrict Text
x
            , asBytes :: Maybe ByteString
asBytes = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (Text -> ByteString) -> Text -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
LBS.toStrict (ByteString -> ByteString)
-> (Text -> ByteString) -> Text -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
LText.encodeUtf8 (Text -> Maybe ByteString) -> Text -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ Text
x
            , asBoolean :: Bool
asBoolean = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Text -> Bool
LText.null Text
x
            , asNumber :: Maybe Scientific
asNumber = String -> Maybe Scientific
forall a. Read a => String -> Maybe a
readMay (String -> Maybe Scientific)
-> (Text -> String) -> Text -> Maybe Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
LText.unpack (Text -> Maybe Scientific) -> Text -> Maybe Scientific
forall a b. (a -> b) -> a -> b
$ Text
x
            , isNull :: Bool
isNull = Bool
False
            }

instance ToGVal m ByteString where
    toGVal :: ByteString -> GVal m
toGVal ByteString
x =
        GVal m
forall a. Default a => a
def
            { asHtml :: Html
asHtml = Text -> Html
html (ByteString -> Text
decodeUtf8 ByteString
x)
            , asText :: Text
asText = ByteString -> Text
decodeUtf8 ByteString
x
            , asBytes :: Maybe ByteString
asBytes = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just ByteString
x
            , asBoolean :: Bool
asBoolean = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ByteString -> Bool
BS.null ByteString
x
            , asNumber :: Maybe Scientific
asNumber = String -> Maybe Scientific
forall a. Read a => String -> Maybe a
readMay (String -> Maybe Scientific)
-> (ByteString -> String) -> ByteString -> Maybe Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
Text.unpack (Text -> String) -> (ByteString -> Text) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
decodeUtf8 (ByteString -> Maybe Scientific) -> ByteString -> Maybe Scientific
forall a b. (a -> b) -> a -> b
$ ByteString
x
            , isNull :: Bool
isNull = Bool
False
            }

instance ToGVal m LBS.ByteString where
    toGVal :: ByteString -> GVal m
toGVal ByteString
x =
        GVal m
forall a. Default a => a
def
            { asHtml :: Html
asHtml = Text -> Html
html (Text -> Html) -> (ByteString -> Text) -> ByteString -> Html
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text
LText.toStrict (Text -> Text) -> (ByteString -> Text) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
LText.decodeUtf8 (ByteString -> Html) -> ByteString -> Html
forall a b. (a -> b) -> a -> b
$ ByteString
x
            , asText :: Text
asText = Text -> Text
LText.toStrict (Text -> Text) -> (ByteString -> Text) -> ByteString -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
LText.decodeUtf8 (ByteString -> Text) -> ByteString -> Text
forall a b. (a -> b) -> a -> b
$ ByteString
x
            , asBytes :: Maybe ByteString
asBytes = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (ByteString -> ByteString) -> ByteString -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
LBS.toStrict (ByteString -> Maybe ByteString) -> ByteString -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ ByteString
x
            , asBoolean :: Bool
asBoolean = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ByteString -> Bool
LBS.null ByteString
x
            , asNumber :: Maybe Scientific
asNumber = String -> Maybe Scientific
forall a. Read a => String -> Maybe a
readMay (String -> Maybe Scientific)
-> (ByteString -> String) -> ByteString -> Maybe Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
LText.unpack (Text -> String) -> (ByteString -> Text) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Text
LText.decodeUtf8 (ByteString -> Maybe Scientific) -> ByteString -> Maybe Scientific
forall a b. (a -> b) -> a -> b
$ ByteString
x
            , isNull :: Bool
isNull = Bool
False
            }
--
-- | This instance is slightly wrong; the 'asBoolean', 'asNumber', and 'asText'
-- methods all treat the HTML source as plain text. We do this to avoid parsing
-- the HTML back into a 'Text' (and dealing with possible parser errors); the
-- reason this instance exists at all is that we still want to be able to pass
-- pre-rendered HTML around sometimes, and as long as we don't call any numeric
-- or string functions on it, everything is fine. When such HTML values
-- accidentally do get used as strings, the HTML source will bleed into the
-- visible text, but at least this will not introduce an XSS vulnerability.
--
-- It is therefore recommended to avoid passing 'Html' values into templates,
-- and also to avoid calling any string functions on 'Html' values inside
-- templates (e.g. capturing macro output and then passing it through a textual
-- filter).
instance ToGVal m Html where
    toGVal :: Html -> GVal m
toGVal Html
x =
        GVal m
forall a. Default a => a
def
            { asHtml :: Html
asHtml = Html
x
            , asText :: Text
asText = Html -> Text
htmlSource Html
x
            , asBoolean :: Bool
asBoolean = Bool -> Bool
not (Bool -> Bool) -> (Html -> Bool) -> Html -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Bool
Text.null (Text -> Bool) -> (Html -> Text) -> Html -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Html -> Text
htmlSource (Html -> Bool) -> Html -> Bool
forall a b. (a -> b) -> a -> b
$ Html
x
            , asNumber :: Maybe Scientific
asNumber = String -> Maybe Scientific
forall a. Read a => String -> Maybe a
readMay (String -> Maybe Scientific)
-> (Html -> String) -> Html -> Maybe Scientific
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
Text.unpack (Text -> String) -> (Html -> Text) -> Html -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Html -> Text
htmlSource (Html -> Maybe Scientific) -> Html -> Maybe Scientific
forall a b. (a -> b) -> a -> b
$ Html
x
            , isNull :: Bool
isNull = Bool
False
            }

-- | Convert Aeson 'Value's to 'GVal's over an arbitrary host monad. Because
-- JSON cannot represent functions, this conversion will never produce a
-- 'Function'. Further, the 'ToJSON' instance for such a 'GVal' will always
-- produce the exact 'Value' that was use to construct the it.
instance ToGVal m JSON.Value where
    toGVal :: Value -> GVal m
toGVal Value
j = (Value -> GVal m
forall (m :: * -> *). Value -> GVal m
rawJSONToGVal Value
j) { asJSON :: Maybe Value
asJSON = Value -> Maybe Value
forall a. a -> Maybe a
Just Value
j }

rawJSONToGVal :: JSON.Value -> GVal m
rawJSONToGVal :: Value -> GVal m
rawJSONToGVal (JSON.Number Scientific
n) = Scientific -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal Scientific
n
rawJSONToGVal (JSON.String Text
s) = Text -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal Text
s
rawJSONToGVal (JSON.Bool Bool
b) = Bool -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal Bool
b
rawJSONToGVal Value
JSON.Null = GVal m
forall a. Default a => a
def
rawJSONToGVal (JSON.Array Array
a) = [Value] -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal ([Value] -> GVal m) -> [Value] -> GVal m
forall a b. (a -> b) -> a -> b
$ Array -> [Value]
forall a. Vector a -> [a]
Vector.toList Array
a
rawJSONToGVal (JSON.Object Object
o) = Object -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal Object
o

#if MIN_VERSION_aeson(2,0,0)
-- | 'AKM.KeyMap' of 'JSON.Value' becomes a dictionary-like 'GVal'
instance ToGVal m (AKM.KeyMap JSON.Value) where
    toGVal :: Object -> GVal m
toGVal Object
xs = KeyMap (GVal m) -> GVal m
helper ((Value -> GVal m) -> Object -> KeyMap (GVal m)
forall a b. (a -> b) -> KeyMap a -> KeyMap b
AKM.map Value -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal Object
xs)
        where
            helper :: AKM.KeyMap (GVal m) -> GVal m
            helper :: KeyMap (GVal m) -> GVal m
helper KeyMap (GVal m)
xs =
                GVal m
forall a. Default a => a
def
                    { asHtml :: Html
asHtml = [Html] -> Html
forall a. Monoid a => [a] -> a
mconcat ([Html] -> Html)
-> (KeyMap (GVal m) -> [Html]) -> KeyMap (GVal m) -> Html
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Key, GVal m) -> Html) -> [(Key, GVal m)] -> [Html]
forall a b. (a -> b) -> [a] -> [b]
List.map (GVal m -> Html
forall (m :: * -> *). GVal m -> Html
asHtml (GVal m -> Html)
-> ((Key, GVal m) -> GVal m) -> (Key, GVal m) -> Html
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Key, GVal m) -> GVal m
forall a b. (a, b) -> b
snd) ([(Key, GVal m)] -> [Html])
-> (KeyMap (GVal m) -> [(Key, GVal m)])
-> KeyMap (GVal m)
-> [Html]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KeyMap (GVal m) -> [(Key, GVal m)]
forall v. KeyMap v -> [(Key, v)]
AKM.toList (KeyMap (GVal m) -> Html) -> KeyMap (GVal m) -> Html
forall a b. (a -> b) -> a -> b
$ KeyMap (GVal m)
xs
                    , asText :: Text
asText = [Text] -> Text
forall a. Monoid a => [a] -> a
mconcat ([Text] -> Text)
-> (KeyMap (GVal m) -> [Text]) -> KeyMap (GVal m) -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Key, GVal m) -> Text) -> [(Key, GVal m)] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
List.map (GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText (GVal m -> Text)
-> ((Key, GVal m) -> GVal m) -> (Key, GVal m) -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Key, GVal m) -> GVal m
forall a b. (a, b) -> b
snd) ([(Key, GVal m)] -> [Text])
-> (KeyMap (GVal m) -> [(Key, GVal m)])
-> KeyMap (GVal m)
-> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KeyMap (GVal m) -> [(Key, GVal m)]
forall v. KeyMap v -> [(Key, v)]
AKM.toList (KeyMap (GVal m) -> Text) -> KeyMap (GVal m) -> Text
forall a b. (a -> b) -> a -> b
$ KeyMap (GVal m)
xs
                    , asBytes :: Maybe ByteString
asBytes = [Maybe ByteString] -> Maybe ByteString
forall a. Monoid a => [a] -> a
mconcat ([Maybe ByteString] -> Maybe ByteString)
-> (KeyMap (GVal m) -> [Maybe ByteString])
-> KeyMap (GVal m)
-> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Key, GVal m) -> Maybe ByteString)
-> [(Key, GVal m)] -> [Maybe ByteString]
forall a b. (a -> b) -> [a] -> [b]
List.map (GVal m -> Maybe ByteString
forall (m :: * -> *). GVal m -> Maybe ByteString
asBytes (GVal m -> Maybe ByteString)
-> ((Key, GVal m) -> GVal m) -> (Key, GVal m) -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Key, GVal m) -> GVal m
forall a b. (a, b) -> b
snd) ([(Key, GVal m)] -> [Maybe ByteString])
-> (KeyMap (GVal m) -> [(Key, GVal m)])
-> KeyMap (GVal m)
-> [Maybe ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KeyMap (GVal m) -> [(Key, GVal m)]
forall v. KeyMap v -> [(Key, v)]
AKM.toList (KeyMap (GVal m) -> Maybe ByteString)
-> KeyMap (GVal m) -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ KeyMap (GVal m)
xs
                    , asBoolean :: Bool
asBoolean = Bool -> Bool
not (Bool -> Bool)
-> (KeyMap (GVal m) -> Bool) -> KeyMap (GVal m) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KeyMap (GVal m) -> Bool
forall v. KeyMap v -> Bool
AKM.null (KeyMap (GVal m) -> Bool) -> KeyMap (GVal m) -> Bool
forall a b. (a -> b) -> a -> b
$ KeyMap (GVal m)
xs
                    , isNull :: Bool
isNull = Bool
False
                    , asLookup :: Maybe (Text -> Maybe (GVal m))
asLookup = (Text -> Maybe (GVal m)) -> Maybe (Text -> Maybe (GVal m))
forall a. a -> Maybe a
Just ((Text -> Maybe (GVal m)) -> Maybe (Text -> Maybe (GVal m)))
-> (Text -> Maybe (GVal m)) -> Maybe (Text -> Maybe (GVal m))
forall a b. (a -> b) -> a -> b
$ (Key -> KeyMap (GVal m) -> Maybe (GVal m)
forall v. Key -> KeyMap v -> Maybe v
`AKM.lookup` KeyMap (GVal m)
xs) (Key -> Maybe (GVal m)) -> (Text -> Key) -> Text -> Maybe (GVal m)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Key
AK.fromText
                    , asDictItems :: Maybe [(Text, GVal m)]
asDictItems = [(Text, GVal m)] -> Maybe [(Text, GVal m)]
forall a. a -> Maybe a
Just ([(Text, GVal m)] -> Maybe [(Text, GVal m)])
-> (KeyMap (GVal m) -> [(Text, GVal m)])
-> KeyMap (GVal m)
-> Maybe [(Text, GVal m)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Key, GVal m) -> (Text, GVal m))
-> [(Key, GVal m)] -> [(Text, GVal m)]
forall a b. (a -> b) -> [a] -> [b]
List.map (\(Key
k,GVal m
v) -> (Key -> Text
AK.toText Key
k, GVal m
v)) ([(Key, GVal m)] -> [(Text, GVal m)])
-> (KeyMap (GVal m) -> [(Key, GVal m)])
-> KeyMap (GVal m)
-> [(Text, GVal m)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. KeyMap (GVal m) -> [(Key, GVal m)]
forall v. KeyMap v -> [(Key, v)]
AKM.toList (KeyMap (GVal m) -> Maybe [(Text, GVal m)])
-> KeyMap (GVal m) -> Maybe [(Text, GVal m)]
forall a b. (a -> b) -> a -> b
$ KeyMap (GVal m)
xs
                    }
#endif

-- | Turn a 'Function' into a 'GVal'
fromFunction :: Function m -> GVal m
fromFunction :: Function m -> GVal m
fromFunction Function m
f =
    GVal m
forall a. Default a => a
def
        { asHtml :: Html
asHtml = Text -> Html
html Text
""
        , asText :: Text
asText = Text
""
        , asBoolean :: Bool
asBoolean = Bool
True
        , isNull :: Bool
isNull = Bool
False
        , asFunction :: Maybe (Function m)
asFunction = Function m -> Maybe (Function m)
forall a. a -> Maybe a
Just Function m
f
        , asJSON :: Maybe Value
asJSON = Value -> Maybe Value
forall a. a -> Maybe a
Just Value
"<<function>>"
        }


-- * Convenience API for constructing heterogenous dictionaries.
--
-- Example usage:
--
-- > context :: GVal m
-- > context = dict [ "number" ~> (15 :: Int), "name" ~> ("Joe" :: String) ]

-- | A key/value pair, used for constructing dictionary GVals using a
-- compact syntax.
type Pair m = (Text, GVal m)

-- | Construct a dictionary GVal from a list of pairs. Internally, this uses
-- a hashmap, so element order will not be preserved.
dict :: [Pair m] -> GVal m
dict :: [Pair m] -> GVal m
dict = HashMap Text (GVal m) -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal (HashMap Text (GVal m) -> GVal m)
-> ([Pair m] -> HashMap Text (GVal m)) -> [Pair m] -> GVal m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Pair m] -> HashMap Text (GVal m)
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList

-- | Construct an ordered dictionary GVal from a list of pairs. Internally,
-- this conversion uses both a hashmap (for O(1) lookup) and the original list,
-- so element order is preserved, but there is a bit of a memory overhead.
orderedDict :: [Pair m] -> GVal m
orderedDict :: [Pair m] -> GVal m
orderedDict [Pair m]
xs =
    GVal m
forall a. Default a => a
def
        { asHtml :: Html
asHtml = [Html] -> Html
forall a. Monoid a => [a] -> a
mconcat ([Html] -> Html) -> ([Pair m] -> [Html]) -> [Pair m] -> Html
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Pair m -> Html) -> [Pair m] -> [Html]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map (GVal m -> Html
forall (m :: * -> *). GVal m -> Html
asHtml (GVal m -> Html) -> (Pair m -> GVal m) -> Pair m -> Html
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Pair m -> GVal m
forall a b. (a, b) -> b
snd) ([Pair m] -> Html) -> [Pair m] -> Html
forall a b. (a -> b) -> a -> b
$ [Pair m]
xs
        , asText :: Text
asText = [Text] -> Text
forall a. Monoid a => [a] -> a
mconcat ([Text] -> Text) -> ([Pair m] -> [Text]) -> [Pair m] -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Pair m -> Text) -> [Pair m] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map (GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText (GVal m -> Text) -> (Pair m -> GVal m) -> Pair m -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Pair m -> GVal m
forall a b. (a, b) -> b
snd) ([Pair m] -> Text) -> [Pair m] -> Text
forall a b. (a -> b) -> a -> b
$ [Pair m]
xs
        , asBoolean :: Bool
asBoolean = Bool -> Bool
not (Bool -> Bool) -> ([Pair m] -> Bool) -> [Pair m] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Pair m] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
Prelude.null ([Pair m] -> Bool) -> [Pair m] -> Bool
forall a b. (a -> b) -> a -> b
$ [Pair m]
xs
        , isNull :: Bool
isNull = Bool
False
        , asLookup :: Maybe (Text -> Maybe (GVal m))
asLookup = (Text -> Maybe (GVal m)) -> Maybe (Text -> Maybe (GVal m))
forall a. a -> Maybe a
Just (Text -> HashMap Text (GVal m) -> Maybe (GVal m)
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
`HashMap.lookup` HashMap Text (GVal m)
hm)
        , asDictItems :: Maybe [Pair m]
asDictItems = [Pair m] -> Maybe [Pair m]
forall a. a -> Maybe a
Just [Pair m]
xs
        }
    where
        hm :: HashMap Text (GVal m)
hm = [Pair m] -> HashMap Text (GVal m)
forall k v. (Eq k, Hashable k) => [(k, v)] -> HashMap k v
HashMap.fromList [Pair m]
xs

-- | Construct a pair from a key and a value.
(~>) :: ToGVal m a => Text -> a -> Pair m
Text
k ~> :: Text -> a -> Pair m
~> a
v = (Text
k, a -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal a
v)
infixr 8 ~>

-- * Convenience API for constructing heterogenous lists

type Cons m = [GVal m]

-- | Alias for '(~:)'.
gcons :: ToGVal m a => a -> Cons m -> Cons m
gcons :: a -> Cons m -> Cons m
gcons = (:) (GVal m -> Cons m -> Cons m)
-> (a -> GVal m) -> a -> Cons m -> Cons m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal

-- | This operator allows constructing heterogenous lists using cons-style
-- syntax, e.g.:
--
-- >>> asText $ list ("Found " ~: (6 :: Int) ~: " items" ~: [] :: [GVal IO])
-- "Found 6 items"
(~:) :: ToGVal m a => a -> Cons m -> Cons m
~: :: a -> Cons m -> Cons m
(~:) = a -> Cons m -> Cons m
forall (m :: * -> *) a. ToGVal m a => a -> Cons m -> Cons m
gcons
infixr 5 ~:

-- | Construct a GVal from a list of GVals. This is equivalent to the 'toGVal'
-- implementation of @[GVal m]@, but typed more narrowly for clarity and
-- disambiguation.
list :: Cons m -> GVal m
list :: Cons m -> GVal m
list = Cons m -> GVal m
forall (m :: * -> *) a. ToGVal m a => a -> GVal m
toGVal

-- * Inspecting 'GVal's / Marshalling 'GVal' to Haskell

-- | Check if the given GVal is a list-like object
isList :: GVal m -> Bool
isList :: GVal m -> Bool
isList = Maybe [GVal m] -> Bool
forall a. Maybe a -> Bool
isJust (Maybe [GVal m] -> Bool)
-> (GVal m -> Maybe [GVal m]) -> GVal m -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList

-- | Check if the given GVal is a dictionary-like object
isDict :: GVal m -> Bool
isDict :: GVal m -> Bool
isDict = Maybe [(Text, GVal m)] -> Bool
forall a. Maybe a -> Bool
isJust (Maybe [(Text, GVal m)] -> Bool)
-> (GVal m -> Maybe [(Text, GVal m)]) -> GVal m -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GVal m -> Maybe [(Text, GVal m)]
forall (m :: * -> *). GVal m -> Maybe [(Text, GVal m)]
asDictItems

-- | Treat a 'GVal' as a flat list and look up a value by integer index.
-- If the value is not a List, or if the index exceeds the list length,
-- return 'Nothing'.
lookupIndex :: Int -> GVal m -> Maybe (GVal m)
lookupIndex :: Int -> GVal m -> Maybe (GVal m)
lookupIndex = Maybe Int -> GVal m -> Maybe (GVal m)
forall (m :: * -> *). Maybe Int -> GVal m -> Maybe (GVal m)
lookupIndexMay (Maybe Int -> GVal m -> Maybe (GVal m))
-> (Int -> Maybe Int) -> Int -> GVal m -> Maybe (GVal m)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Maybe Int
forall a. a -> Maybe a
Just

-- | Helper function; look up a value by an integer index when the index may or
-- may not be available. If no index is given, return 'Nothing'.
lookupIndexMay :: Maybe Int -> GVal m -> Maybe (GVal m)
lookupIndexMay :: Maybe Int -> GVal m -> Maybe (GVal m)
lookupIndexMay Maybe Int
i GVal m
v = do
    Int
index <- Maybe Int
i
    [GVal m]
items <- GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList GVal m
v
    [GVal m] -> Int -> Maybe (GVal m)
forall a. [a] -> Int -> Maybe a
atMay [GVal m]
items Int
index

-- | Strictly-typed lookup: treat value as a dictionary-like object and look
-- up the value at a given key.
lookupKey :: Text -> GVal m -> Maybe (GVal m)
lookupKey :: Text -> GVal m -> Maybe (GVal m)
lookupKey Text
k GVal m
v = do
    Text -> Maybe (GVal m)
lf <- GVal m -> Maybe (Text -> Maybe (GVal m))
forall (m :: * -> *). GVal m -> Maybe (Text -> Maybe (GVal m))
asLookup GVal m
v
    Text -> Maybe (GVal m)
lf Text
k

-- | Loosely-typed lookup: try dictionary-style lookup first (treat index as
-- a string, and container as a dictionary), if that doesn't yield anything
-- (either because the index is not string-ish, or because the container
-- doesn't provide dictionary-style access), try index-based lookup.
lookupLoose :: GVal m -> GVal m -> Maybe (GVal m)
lookupLoose :: GVal m -> GVal m -> Maybe (GVal m)
lookupLoose GVal m
k GVal m
v =
    Text -> GVal m -> Maybe (GVal m)
forall (m :: * -> *). Text -> GVal m -> Maybe (GVal m)
lookupKey (GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText GVal m
k) GVal m
v Maybe (GVal m) -> Maybe (GVal m) -> Maybe (GVal m)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Maybe Int -> GVal m -> Maybe (GVal m)
forall (m :: * -> *). Maybe Int -> GVal m -> Maybe (GVal m)
lookupIndexMay (Scientific -> Int
forall a b. (RealFrac a, Integral b) => a -> b
floor (Scientific -> Int) -> Maybe Scientific -> Maybe Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe Scientific
forall (m :: * -> *). GVal m -> Maybe Scientific
asNumber GVal m
k) GVal m
v

-- | Like 'lookupLoose', but fall back to the given default value if
-- the key is not in the dictionary, or if the indexee is not a
-- dictionary-like object.
lookupLooseDef :: GVal m -> GVal m -> GVal m -> GVal m
lookupLooseDef :: GVal m -> GVal m -> GVal m -> GVal m
lookupLooseDef GVal m
d GVal m
k = GVal m -> Maybe (GVal m) -> GVal m
forall a. a -> Maybe a -> a
fromMaybe GVal m
d (Maybe (GVal m) -> GVal m)
-> (GVal m -> Maybe (GVal m)) -> GVal m -> GVal m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GVal m -> GVal m -> Maybe (GVal m)
forall (m :: * -> *). GVal m -> GVal m -> Maybe (GVal m)
lookupLoose GVal m
k

(~!) :: (FromGVal m v) => GVal m -> GVal m -> Maybe v
GVal m
g ~! :: GVal m -> GVal m -> Maybe v
~! GVal m
k = GVal m -> GVal m -> Maybe (GVal m)
forall (m :: * -> *). GVal m -> GVal m -> Maybe (GVal m)
lookupLoose GVal m
k GVal m
g Maybe (GVal m) -> (GVal m -> Maybe v) -> Maybe v
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= GVal m -> Maybe v
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal

-- | Treat a 'GVal' as a dictionary and list all the keys, with no particular
-- ordering.
keys :: GVal m -> Maybe [Text]
keys :: GVal m -> Maybe [Text]
keys GVal m
v = ((Text, GVal m) -> Text) -> [(Text, GVal m)] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
Prelude.map (Text, GVal m) -> Text
forall a b. (a, b) -> a
fst ([(Text, GVal m)] -> [Text])
-> Maybe [(Text, GVal m)] -> Maybe [Text]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe [(Text, GVal m)]
forall (m :: * -> *). GVal m -> Maybe [(Text, GVal m)]
asDictItems GVal m
v

-- | Convert a 'GVal' to a number.
toNumber :: GVal m -> Maybe Scientific
toNumber :: GVal m -> Maybe Scientific
toNumber = GVal m -> Maybe Scientific
forall (m :: * -> *). GVal m -> Maybe Scientific
asNumber

-- | Convert a 'GVal' to an 'Int'.
-- The conversion will fail when the value is not numeric, and also if
-- it is too large to fit in an 'Int'.
toInt :: GVal m -> Maybe Int
toInt :: GVal m -> Maybe Int
toInt = Scientific -> Maybe Int
forall i. (Integral i, Bounded i) => Scientific -> Maybe i
toBoundedInteger (Scientific -> Maybe Int)
-> (GVal m -> Maybe Scientific) -> GVal m -> Maybe Int
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< GVal m -> Maybe Scientific
forall (m :: * -> *). GVal m -> Maybe Scientific
toNumber

-- | Convert a 'GVal' to an 'Integer'
-- The conversion will fail when the value is not an integer
toInteger :: GVal m -> Maybe Integer
toInteger :: GVal m -> Maybe Integer
toInteger = (Double -> Maybe Integer)
-> (Integer -> Maybe Integer)
-> Either Double Integer
-> Maybe Integer
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
Prelude.either (Maybe Integer -> Double -> Maybe Integer
forall a b. a -> b -> a
const Maybe Integer
forall a. Maybe a
Nothing) Integer -> Maybe Integer
forall a. a -> Maybe a
Just (Either Double Integer -> Maybe Integer)
-> (Scientific -> Either Double Integer)
-> Scientific
-> Maybe Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scientific -> Either Double Integer
forall r i. (RealFloat r, Integral i) => Scientific -> Either r i
floatingOrInteger (Scientific -> Maybe Integer)
-> (GVal m -> Maybe Scientific) -> GVal m -> Maybe Integer
forall (m :: * -> *) b c a.
Monad m =>
(b -> m c) -> (a -> m b) -> a -> m c
<=< GVal m -> Maybe Scientific
forall (m :: * -> *). GVal m -> Maybe Scientific
asNumber

-- | Convert a 'GVal' to an 'Int', falling back to the given
-- default if the conversion fails.
toIntDef :: Int -> GVal m -> Int
toIntDef :: Int -> GVal m -> Int
toIntDef Int
d = Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe Int
d (Maybe Int -> Int) -> (GVal m -> Maybe Int) -> GVal m -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GVal m -> Maybe Int
forall (m :: * -> *). GVal m -> Maybe Int
toInt

-- | Convert a 'GVal' to an 'Int', falling back to zero (0)
-- if the conversion fails.
toInt0 :: GVal m -> Int
toInt0 :: GVal m -> Int
toInt0 = Int -> GVal m -> Int
forall (m :: * -> *). Int -> GVal m -> Int
toIntDef Int
0

-- | Loose cast to boolean.
--
-- Numeric zero, empty strings, empty lists, empty objects, 'Null', and boolean
-- 'False' are considered falsy, anything else (including functions) is
-- considered true-ish.
toBoolean :: GVal m -> Bool
toBoolean :: GVal m -> Bool
toBoolean = GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
asBoolean

-- | Dynamically cast to a function.
-- This yields 'Just' a 'Function' if the value is a function, 'Nothing' if
-- it's not.
toFunction :: GVal m -> Maybe (Function m)
toFunction :: GVal m -> Maybe (Function m)
toFunction = GVal m -> Maybe (Function m)
forall (m :: * -> *). GVal m -> Maybe (Function m)
asFunction

picoToScientific :: Pico -> Scientific
picoToScientific :: Pico -> Scientific
picoToScientific (MkFixed Integer
x) = Integer -> Int -> Scientific
scientific Integer
x (-Int
12)

scientificToPico :: Scientific -> Pico
scientificToPico :: Scientific -> Pico
scientificToPico Scientific
s =
    Integer -> Pico
forall k (a :: k). Integer -> Fixed a
MkFixed (Scientific -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
Prelude.floor (Scientific -> Integer) -> Scientific -> Integer
forall a b. (a -> b) -> a -> b
$ Integer -> Int -> Scientific
scientific (Scientific -> Integer
coefficient Scientific
s) (Scientific -> Int
base10Exponent Scientific
s Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
12))

{-#RULES "GVal/round-trip-Maybe" fromGVal . toGVal = Just #-}
{-#RULES "GVal/round-trip-Either" fromGValEither . toGVal = Right #-}
{-#RULES "GVal/text-shortcut" asText . toGVal = id #-}

class FromGVal m a where
    fromGValEither :: GVal m -> Either Prelude.String a
    fromGValEither = Either String a
-> (a -> Either String a) -> Maybe a -> Either String a
forall b a. b -> (a -> b) -> Maybe a -> b
Prelude.maybe (String -> Either String a
forall a b. a -> Either a b
Left String
"Conversion from GVal failed") a -> Either String a
forall a b. b -> Either a b
Right (Maybe a -> Either String a)
-> (GVal m -> Maybe a) -> GVal m -> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GVal m -> Maybe a
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal
    fromGVal :: GVal m -> Maybe a
    fromGVal = (String -> Maybe a) -> (a -> Maybe a) -> Either String a -> Maybe a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
Prelude.either (Maybe a -> String -> Maybe a
forall a b. a -> b -> a
const Maybe a
forall a. Maybe a
Nothing) a -> Maybe a
forall a. a -> Maybe a
Just (Either String a -> Maybe a)
-> (GVal m -> Either String a) -> GVal m -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GVal m -> Either String a
forall (m :: * -> *) a. FromGVal m a => GVal m -> Either String a
fromGValEither

fromGValM :: (MonadFail m, FromGVal m a) => GVal m -> m a
fromGValM :: GVal m -> m a
fromGValM = (String -> m a) -> (a -> m a) -> Either String a -> m a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
Prelude.either String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
Prelude.fail a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Either String a -> m a)
-> (GVal m -> Either String a) -> GVal m -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GVal m -> Either String a
forall (m :: * -> *) a. FromGVal m a => GVal m -> Either String a
fromGValEither

instance FromGVal m Int where
    fromGVal :: GVal m -> Maybe Int
fromGVal = GVal m -> Maybe Int
forall (m :: * -> *). GVal m -> Maybe Int
toInt

instance FromGVal m Scientific where
    fromGVal :: GVal m -> Maybe Scientific
fromGVal = GVal m -> Maybe Scientific
forall (m :: * -> *). GVal m -> Maybe Scientific
asNumber

instance FromGVal m Integer where
    fromGVal :: GVal m -> Maybe Integer
fromGVal = GVal m -> Maybe Integer
forall (m :: * -> *). GVal m -> Maybe Integer
toInteger

instance FromGVal m Text where
    fromGVal :: GVal m -> Maybe Text
fromGVal = Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text) -> (GVal m -> Text) -> GVal m -> Maybe Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GVal m -> Text
forall (m :: * -> *). GVal m -> Text
asText

instance FromGVal m (GVal m) where
    fromGVal :: GVal m -> Maybe (GVal m)
fromGVal = GVal m -> Maybe (GVal m)
forall a. a -> Maybe a
Just

instance FromGVal m ByteString where
    fromGVal :: GVal m -> Maybe ByteString
fromGVal = GVal m -> Maybe ByteString
forall (m :: * -> *). GVal m -> Maybe ByteString
asBytes

instance FromGVal m LBS.ByteString where
    fromGVal :: GVal m -> Maybe ByteString
fromGVal = (ByteString -> ByteString) -> Maybe ByteString -> Maybe ByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> ByteString
LBS.fromStrict (Maybe ByteString -> Maybe ByteString)
-> (GVal m -> Maybe ByteString) -> GVal m -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GVal m -> Maybe ByteString
forall (m :: * -> *). GVal m -> Maybe ByteString
asBytes

instance FromGVal m a => FromGVal m (Maybe a) where
    fromGVal :: GVal m -> Maybe (Maybe a)
fromGVal = \GVal m
g ->
        if GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
isNull GVal m
g
            then
                Maybe a -> Maybe (Maybe a)
forall a. a -> Maybe a
Just Maybe a
forall a. Maybe a
Nothing
            else
                a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> Maybe a -> Maybe (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe a
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal GVal m
g

instance FromGVal m Bool where
    fromGVal :: GVal m -> Maybe Bool
fromGVal = Bool -> Maybe Bool
forall a. a -> Maybe a
Just (Bool -> Maybe Bool) -> (GVal m -> Bool) -> GVal m -> Maybe Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
asBoolean

instance FromGVal m JSON.Value where
    fromGVal :: GVal m -> Maybe Value
fromGVal = GVal m -> Maybe Value
forall (m :: * -> *). GVal m -> Maybe Value
asJSON

instance FromGVal m () where
    fromGVal :: GVal m -> Maybe ()
fromGVal GVal m
g = if GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
isNull GVal m
g then () -> Maybe ()
forall a. a -> Maybe a
Just () else Maybe ()
forall a. Maybe a
Nothing

instance FromGVal m a => FromGVal m [a] where
    fromGVal :: GVal m -> Maybe [a]
fromGVal GVal m
g = GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList GVal m
g Maybe [GVal m] -> ([GVal m] -> Maybe [a]) -> Maybe [a]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (GVal m -> Maybe a) -> [GVal m] -> Maybe [a]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM GVal m -> Maybe a
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal

instance ( FromGVal m a
         , FromGVal m b
         ) => FromGVal m (a, b) where
    fromGVal :: GVal m -> Maybe (a, b)
fromGVal GVal m
g = case GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList GVal m
g of
        Just [GVal m
a, GVal m
b] ->
            (,) (a -> b -> (a, b)) -> Maybe a -> Maybe (b -> (a, b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe a
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal GVal m
a
                Maybe (b -> (a, b)) -> Maybe b -> Maybe (a, b)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> GVal m -> Maybe b
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal GVal m
b
        Maybe [GVal m]
_ -> Maybe (a, b)
forall a. Maybe a
Nothing

instance ( FromGVal m a
         , FromGVal m b
         , FromGVal m c
         ) => FromGVal m (a, b, c) where
    fromGVal :: GVal m -> Maybe (a, b, c)
fromGVal GVal m
g = case GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList GVal m
g of
        Just [GVal m
a, GVal m
b, GVal m
c] ->
            (,,) (a -> b -> c -> (a, b, c))
-> Maybe a -> Maybe (b -> c -> (a, b, c))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe a
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal GVal m
a
                 Maybe (b -> c -> (a, b, c)) -> Maybe b -> Maybe (c -> (a, b, c))
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> GVal m -> Maybe b
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal GVal m
b
                 Maybe (c -> (a, b, c)) -> Maybe c -> Maybe (a, b, c)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> GVal m -> Maybe c
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal GVal m
c
        Maybe [GVal m]
_ -> Maybe (a, b, c)
forall a. Maybe a
Nothing

instance ( FromGVal m a
         , FromGVal m b
         , FromGVal m c
         , FromGVal m d
         ) => FromGVal m (a, b, c, d) where
    fromGVal :: GVal m -> Maybe (a, b, c, d)
fromGVal GVal m
g = case GVal m -> Maybe [GVal m]
forall (m :: * -> *). GVal m -> Maybe [GVal m]
asList GVal m
g of
        Just [GVal m
a, GVal m
b, GVal m
c, GVal m
d] ->
            (,,,) (a -> b -> c -> d -> (a, b, c, d))
-> Maybe a -> Maybe (b -> c -> d -> (a, b, c, d))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m -> Maybe a
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal GVal m
a
                  Maybe (b -> c -> d -> (a, b, c, d))
-> Maybe b -> Maybe (c -> d -> (a, b, c, d))
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> GVal m -> Maybe b
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal GVal m
b
                  Maybe (c -> d -> (a, b, c, d))
-> Maybe c -> Maybe (d -> (a, b, c, d))
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> GVal m -> Maybe c
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal GVal m
c
                  Maybe (d -> (a, b, c, d)) -> Maybe d -> Maybe (a, b, c, d)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> GVal m -> Maybe d
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal GVal m
d
        Maybe [GVal m]
_ -> Maybe (a, b, c, d)
forall a. Maybe a
Nothing

instance FromGVal m Day where
    fromGVal :: GVal m -> Maybe Day
fromGVal GVal m
g = do
        Integer
year <- Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Integer) -> Maybe Int -> Maybe Integer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (GVal m
g GVal m -> GVal m -> Maybe Int
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"year" :: Maybe Int)
        Int
month <- GVal m
g GVal m -> GVal m -> Maybe Int
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"month"
        Int
day <- GVal m
g GVal m -> GVal m -> Maybe Int
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"day"
        Day -> Maybe Day
forall (m :: * -> *) a. Monad m => a -> m a
return (Day -> Maybe Day) -> Day -> Maybe Day
forall a b. (a -> b) -> a -> b
$ Integer -> Int -> Int -> Day
fromGregorian Integer
year Int
month Int
day

instance FromGVal m TimeOfDay where
    fromGVal :: GVal m -> Maybe TimeOfDay
fromGVal GVal m
g = do
        Int
hours <- GVal m
g GVal m -> GVal m -> Maybe Int
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"hours"
        Int
minutes <- GVal m
g GVal m -> GVal m -> Maybe Int
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"minutes"
        Pico
seconds <- Scientific -> Pico
scientificToPico (Scientific -> Pico) -> Maybe Scientific -> Maybe Pico
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m
g GVal m -> GVal m -> Maybe Scientific
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"seconds"
        TimeOfDay -> Maybe TimeOfDay
forall (m :: * -> *) a. Monad m => a -> m a
return (TimeOfDay -> Maybe TimeOfDay) -> TimeOfDay -> Maybe TimeOfDay
forall a b. (a -> b) -> a -> b
$ Int -> Int -> Pico -> TimeOfDay
TimeOfDay Int
hours Int
minutes Pico
seconds

instance FromGVal m LocalTime where
    fromGVal :: GVal m -> Maybe LocalTime
fromGVal GVal m
g = do
        Day
date <- GVal m -> Maybe Day
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal GVal m
g Maybe Day -> Maybe Day -> Maybe Day
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> GVal m
g GVal m -> GVal m -> Maybe Day
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"date"
        TimeOfDay
time <- GVal m -> Maybe TimeOfDay
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal GVal m
g Maybe TimeOfDay -> Maybe TimeOfDay -> Maybe TimeOfDay
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> GVal m
g GVal m -> GVal m -> Maybe TimeOfDay
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"time"
        LocalTime -> Maybe LocalTime
forall (m :: * -> *) a. Monad m => a -> m a
return (LocalTime -> Maybe LocalTime) -> LocalTime -> Maybe LocalTime
forall a b. (a -> b) -> a -> b
$ Day -> TimeOfDay -> LocalTime
LocalTime Day
date TimeOfDay
time

instance FromGVal m ZonedTime where
    fromGVal :: GVal m -> Maybe ZonedTime
fromGVal GVal m
g = do
        LocalTime
localTime <- GVal m -> Maybe LocalTime
forall (m :: * -> *) a. FromGVal m a => GVal m -> Maybe a
fromGVal GVal m
g
        TimeZone
timeZone <- GVal m
g GVal m -> GVal m -> Maybe TimeZone
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"tz"
        ZonedTime -> Maybe ZonedTime
forall (m :: * -> *) a. Monad m => a -> m a
return (ZonedTime -> Maybe ZonedTime) -> ZonedTime -> Maybe ZonedTime
forall a b. (a -> b) -> a -> b
$ LocalTime -> TimeZone -> ZonedTime
ZonedTime LocalTime
localTime TimeZone
timeZone

instance FromGVal m TimeZone where
    fromGVal :: GVal m -> Maybe TimeZone
fromGVal GVal m
g =
        Int -> Bool -> String -> TimeZone
TimeZone
            (Int -> Bool -> String -> TimeZone)
-> Maybe Int -> Maybe (Bool -> String -> TimeZone)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m
g GVal m -> GVal m -> Maybe Int
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"minutes"
            Maybe (Bool -> String -> TimeZone)
-> Maybe Bool -> Maybe (String -> TimeZone)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> GVal m
g GVal m -> GVal m -> Maybe Bool
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"summerOnly"
            Maybe (String -> TimeZone) -> Maybe String -> Maybe TimeZone
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (Text -> String
Text.unpack (Text -> String) -> Maybe Text -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m
g GVal m -> GVal m -> Maybe Text
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"name")

instance FromGVal m TimeLocale where
    fromGVal :: GVal m -> Maybe TimeLocale
fromGVal GVal m
g =
        if GVal m -> Bool
forall (m :: * -> *). GVal m -> Bool
isDict GVal m
g
            then
                TimeLocale -> Maybe TimeLocale
forall a. a -> Maybe a
Just (TimeLocale -> Maybe TimeLocale) -> TimeLocale -> Maybe TimeLocale
forall a b. (a -> b) -> a -> b
$ [(String, String)]
-> [(String, String)]
-> (String, String)
-> String
-> String
-> String
-> String
-> [TimeZone]
-> TimeLocale
TimeLocale
                    ([(String, String)]
-> Maybe [(String, String)] -> [(String, String)]
forall a. a -> Maybe a -> a
fromMaybe (TimeLocale -> [(String, String)]
wDays TimeLocale
defaultTimeLocale) (Maybe [(String, String)] -> [(String, String)])
-> Maybe [(String, String)] -> [(String, String)]
forall a b. (a -> b) -> a -> b
$ ((Text, Text) -> (String, String))
-> [(Text, Text)] -> [(String, String)]
forall a b. (a -> b) -> [a] -> [b]
List.map (Text, Text) -> (String, String)
unpackPair ([(Text, Text)] -> [(String, String)])
-> Maybe [(Text, Text)] -> Maybe [(String, String)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m
g GVal m -> GVal m -> Maybe [(Text, Text)]
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"wDays")
                    ([(String, String)]
-> Maybe [(String, String)] -> [(String, String)]
forall a. a -> Maybe a -> a
fromMaybe (TimeLocale -> [(String, String)]
months TimeLocale
defaultTimeLocale) (Maybe [(String, String)] -> [(String, String)])
-> Maybe [(String, String)] -> [(String, String)]
forall a b. (a -> b) -> a -> b
$ ((Text, Text) -> (String, String))
-> [(Text, Text)] -> [(String, String)]
forall a b. (a -> b) -> [a] -> [b]
List.map (Text, Text) -> (String, String)
unpackPair ([(Text, Text)] -> [(String, String)])
-> Maybe [(Text, Text)] -> Maybe [(String, String)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m
g GVal m -> GVal m -> Maybe [(Text, Text)]
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"months")
                    ((String, String) -> Maybe (String, String) -> (String, String)
forall a. a -> Maybe a -> a
fromMaybe (TimeLocale -> (String, String)
amPm TimeLocale
defaultTimeLocale) (Maybe (String, String) -> (String, String))
-> Maybe (String, String) -> (String, String)
forall a b. (a -> b) -> a -> b
$ (Text, Text) -> (String, String)
unpackPair ((Text, Text) -> (String, String))
-> Maybe (Text, Text) -> Maybe (String, String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m
g GVal m -> GVal m -> Maybe (Text, Text)
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"amPm")
                    (String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe (TimeLocale -> String
dateTimeFmt TimeLocale
defaultTimeLocale) (Maybe String -> String) -> Maybe String -> String
forall a b. (a -> b) -> a -> b
$ Text -> String
Text.unpack (Text -> String) -> Maybe Text -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m
g GVal m -> GVal m -> Maybe Text
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"dateTimeFmt")
                    (String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe (TimeLocale -> String
dateFmt TimeLocale
defaultTimeLocale) (Maybe String -> String) -> Maybe String -> String
forall a b. (a -> b) -> a -> b
$ Text -> String
Text.unpack (Text -> String) -> Maybe Text -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m
g GVal m -> GVal m -> Maybe Text
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"dateFmt")
                    (String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe (TimeLocale -> String
timeFmt TimeLocale
defaultTimeLocale) (Maybe String -> String) -> Maybe String -> String
forall a b. (a -> b) -> a -> b
$ Text -> String
Text.unpack (Text -> String) -> Maybe Text -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m
g GVal m -> GVal m -> Maybe Text
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"timeFmt")
                    (String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe (TimeLocale -> String
time12Fmt TimeLocale
defaultTimeLocale) (Maybe String -> String) -> Maybe String -> String
forall a b. (a -> b) -> a -> b
$ Text -> String
Text.unpack (Text -> String) -> Maybe Text -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> GVal m
g GVal m -> GVal m -> Maybe Text
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"time12Fmt")
                    ([TimeZone] -> Maybe [TimeZone] -> [TimeZone]
forall a. a -> Maybe a -> a
fromMaybe (TimeLocale -> [TimeZone]
knownTimeZones TimeLocale
defaultTimeLocale) (Maybe [TimeZone] -> [TimeZone]) -> Maybe [TimeZone] -> [TimeZone]
forall a b. (a -> b) -> a -> b
$ GVal m
g GVal m -> GVal m -> Maybe [TimeZone]
forall (m :: * -> *) v. FromGVal m v => GVal m -> GVal m -> Maybe v
~! GVal m
"knownTimeZones")
            else
                Maybe TimeLocale
forall a. Maybe a
Nothing

pairwise :: (a -> b) -> (a, a) -> (b, b)
pairwise :: (a -> b) -> (a, a) -> (b, b)
pairwise a -> b
f (a
a, a
b) = (a -> b
f a
a, a -> b
f a
b)

packPair :: ([Char], [Char]) -> (Text, Text)
packPair :: (String, String) -> (Text, Text)
packPair = (String -> Text) -> (String, String) -> (Text, Text)
forall a b. (a -> b) -> (a, a) -> (b, b)
pairwise String -> Text
Text.pack

unpackPair :: (Text, Text) -> ([Char], [Char])
unpackPair :: (Text, Text) -> (String, String)
unpackPair = (Text -> String) -> (Text, Text) -> (String, String)
forall a b. (a -> b) -> (a, a) -> (b, b)
pairwise Text -> String
Text.unpack