{-# LANGUAGE OverloadedStrings #-}
module Foreign.Lua.Peek
( Peeker
, PeekError (..)
, errorMsg
, force
, formatPeekError
, pushMsg
, toPeeker
, peekBool
, peekIntegral
, peekRealFloat
, peekByteString
, peekLazyByteString
, peekString
, peekText
, peekStringy
, peekKeyValuePairs
, peekList
, peekMap
, peekSet
, optional
) where
import Control.Applicative ((<|>))
import Data.Bifunctor (first, second)
import Data.ByteString (ByteString)
import Data.List.NonEmpty (NonEmpty (..), (<|))
import Data.Map (Map)
import Data.Maybe (fromMaybe)
import Data.Set (Set)
import Data.String (IsString (fromString))
import Data.Text (Text)
import Foreign.Lua.Core as Lua
import Text.Read (readMaybe)
import qualified Data.ByteString.Lazy as BL
import qualified Data.List.NonEmpty as NonEmpty
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.Text as T
import qualified Foreign.Lua.Utf8 as Utf8
newtype PeekError = PeekError { PeekError -> NonEmpty Text
fromPeekError :: NonEmpty Text }
deriving (PeekError -> PeekError -> Bool
(PeekError -> PeekError -> Bool)
-> (PeekError -> PeekError -> Bool) -> Eq PeekError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PeekError -> PeekError -> Bool
$c/= :: PeekError -> PeekError -> Bool
== :: PeekError -> PeekError -> Bool
$c== :: PeekError -> PeekError -> Bool
Eq, Int -> PeekError -> ShowS
[PeekError] -> ShowS
PeekError -> String
(Int -> PeekError -> ShowS)
-> (PeekError -> String)
-> ([PeekError] -> ShowS)
-> Show PeekError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PeekError] -> ShowS
$cshowList :: [PeekError] -> ShowS
show :: PeekError -> String
$cshow :: PeekError -> String
showsPrec :: Int -> PeekError -> ShowS
$cshowsPrec :: Int -> PeekError -> ShowS
Show)
formatPeekError :: PeekError -> String
formatPeekError :: PeekError -> String
formatPeekError (PeekError NonEmpty Text
msgs) = Text -> String
T.unpack (Text -> String) -> Text -> String
forall a b. (a -> b) -> a -> b
$
Text -> [Text] -> Text
T.intercalate Text
"\n\t" (NonEmpty Text -> [Text]
forall a. NonEmpty a -> [a]
NonEmpty.toList NonEmpty Text
msgs)
type Peeker a = StackIndex -> Lua (Either PeekError a)
errorMsg :: Text -> PeekError
errorMsg :: Text -> PeekError
errorMsg = NonEmpty Text -> PeekError
PeekError (NonEmpty Text -> PeekError)
-> (Text -> NonEmpty Text) -> Text -> PeekError
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> NonEmpty Text
forall (f :: * -> *) a. Applicative f => a -> f a
pure
pushMsg :: Text -> PeekError -> PeekError
pushMsg :: Text -> PeekError -> PeekError
pushMsg Text
msg (PeekError NonEmpty Text
lst) = NonEmpty Text -> PeekError
PeekError (NonEmpty Text -> PeekError) -> NonEmpty Text -> PeekError
forall a b. (a -> b) -> a -> b
$ Text
msg Text -> NonEmpty Text -> NonEmpty Text
forall a. a -> NonEmpty a -> NonEmpty a
<| NonEmpty Text
lst
retrieving :: Text -> Either PeekError a -> Either PeekError a
retrieving :: Text -> Either PeekError a -> Either PeekError a
retrieving Text
msg = (PeekError -> PeekError)
-> Either PeekError a -> Either PeekError a
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first ((PeekError -> PeekError)
-> Either PeekError a -> Either PeekError a)
-> (PeekError -> PeekError)
-> Either PeekError a
-> Either PeekError a
forall a b. (a -> b) -> a -> b
$ Text -> PeekError -> PeekError
pushMsg (Text
"retrieving " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
msg)
force :: Either PeekError a -> Lua a
force :: Either PeekError a -> Lua a
force = (PeekError -> Lua a) -> (a -> Lua a) -> Either PeekError a -> Lua a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> Lua a
forall a. String -> Lua a
throwMessage (String -> Lua a) -> (PeekError -> String) -> PeekError -> Lua a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PeekError -> String
formatPeekError) a -> Lua a
forall (m :: * -> *) a. Monad m => a -> m a
return
toPeeker :: (StackIndex -> Lua a)
-> Peeker a
toPeeker :: (StackIndex -> Lua a) -> Peeker a
toPeeker StackIndex -> Lua a
op StackIndex
idx =
(a -> Either PeekError a
forall a b. b -> Either a b
Right (a -> Either PeekError a) -> Lua a -> Lua (Either PeekError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StackIndex -> Lua a
op StackIndex
idx) Lua (Either PeekError a)
-> Lua (Either PeekError a) -> Lua (Either PeekError a)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Either PeekError a -> Lua (Either PeekError a)
forall (m :: * -> *) a. Monad m => a -> m a
return (PeekError -> Either PeekError a
forall a b. a -> Either a b
Left (PeekError -> Either PeekError a)
-> PeekError -> Either PeekError a
forall a b. (a -> b) -> a -> b
$ Text -> PeekError
errorMsg Text
"retrieving failed")
typeChecked :: Text
-> (StackIndex -> Lua Bool)
-> Peeker a
-> Peeker a
typeChecked :: Text -> (StackIndex -> Lua Bool) -> Peeker a -> Peeker a
typeChecked Text
expectedType StackIndex -> Lua Bool
test Peeker a
peekfn StackIndex
idx = do
Bool
v <- StackIndex -> Lua Bool
test StackIndex
idx
if Bool
v
then Peeker a
peekfn StackIndex
idx
else PeekError -> Either PeekError a
forall a b. a -> Either a b
Left (PeekError -> Either PeekError a)
-> Lua PeekError -> Lua (Either PeekError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> StackIndex -> Lua PeekError
mismatchError Text
expectedType StackIndex
idx
reportValueOnFailure :: Text
-> (StackIndex -> Lua (Maybe a))
-> Peeker a
reportValueOnFailure :: Text -> (StackIndex -> Lua (Maybe a)) -> Peeker a
reportValueOnFailure Text
expected StackIndex -> Lua (Maybe a)
peekMb StackIndex
idx = do
Maybe a
res <- StackIndex -> Lua (Maybe a)
peekMb StackIndex
idx
case Maybe a
res of
Just a
x -> Either PeekError a -> Lua (Either PeekError a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either PeekError a -> Lua (Either PeekError a))
-> Either PeekError a -> Lua (Either PeekError a)
forall a b. (a -> b) -> a -> b
$ a -> Either PeekError a
forall a b. b -> Either a b
Right a
x
Maybe a
Nothing -> PeekError -> Either PeekError a
forall a b. a -> Either a b
Left (PeekError -> Either PeekError a)
-> Lua PeekError -> Lua (Either PeekError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> StackIndex -> Lua PeekError
mismatchError Text
expected StackIndex
idx
mismatchError :: Text -> StackIndex -> Lua PeekError
mismatchError :: Text -> StackIndex -> Lua PeekError
mismatchError Text
expected StackIndex
idx = do
String
actualType <- StackIndex -> Lua Type
ltype StackIndex
idx Lua Type -> (Type -> Lua String) -> Lua String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Type -> Lua String
typename
Text
actualValue <- ByteString -> Text
Utf8.toText (ByteString -> Text) -> Lua ByteString -> Lua Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StackIndex -> Lua ByteString
tostring' StackIndex
idx Lua Text -> Lua () -> Lua Text
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* StackIndex -> Lua ()
pop StackIndex
1
PeekError -> Lua PeekError
forall (m :: * -> *) a. Monad m => a -> m a
return (PeekError -> Lua PeekError)
-> (Text -> PeekError) -> Text -> Lua PeekError
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> PeekError
errorMsg (Text -> Lua PeekError) -> Text -> Lua PeekError
forall a b. (a -> b) -> a -> b
$
Text
"expected " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
expected Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
", got '" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
Text
actualValue Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"' (" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack String
actualType Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
")"
peekBool :: Peeker Bool
peekBool :: Peeker Bool
peekBool = (Bool -> Either PeekError Bool)
-> Lua Bool -> Lua (Either PeekError Bool)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Bool -> Either PeekError Bool
forall a b. b -> Either a b
Right (Lua Bool -> Lua (Either PeekError Bool))
-> (StackIndex -> Lua Bool) -> Peeker Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. StackIndex -> Lua Bool
toboolean
toByteString :: StackIndex -> Lua (Maybe ByteString)
toByteString :: StackIndex -> Lua (Maybe ByteString)
toByteString StackIndex
idx = do
StackIndex -> Lua ()
pushvalue StackIndex
idx
StackIndex -> Lua (Maybe ByteString)
tostring StackIndex
stackTop Lua (Maybe ByteString) -> Lua () -> Lua (Maybe ByteString)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* StackIndex -> Lua ()
pop StackIndex
1
peekByteString :: Peeker ByteString
peekByteString :: Peeker ByteString
peekByteString = Text -> (StackIndex -> Lua (Maybe ByteString)) -> Peeker ByteString
forall a. Text -> (StackIndex -> Lua (Maybe a)) -> Peeker a
reportValueOnFailure Text
"string" StackIndex -> Lua (Maybe ByteString)
toByteString
peekLazyByteString :: Peeker BL.ByteString
peekLazyByteString :: Peeker ByteString
peekLazyByteString = (Either PeekError ByteString -> Either PeekError ByteString)
-> Lua (Either PeekError ByteString)
-> Lua (Either PeekError ByteString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((ByteString -> ByteString)
-> Either PeekError ByteString -> Either PeekError ByteString
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second ByteString -> ByteString
BL.fromStrict) (Lua (Either PeekError ByteString)
-> Lua (Either PeekError ByteString))
-> Peeker ByteString -> Peeker ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Peeker ByteString
peekByteString
peekString :: Peeker String
peekString :: Peeker String
peekString = Peeker String
forall a. IsString a => Peeker a
peekStringy
peekStringy :: IsString a => Peeker a
peekStringy :: Peeker a
peekStringy = (Either PeekError ByteString -> Either PeekError a)
-> Lua (Either PeekError ByteString) -> Lua (Either PeekError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((ByteString -> a)
-> Either PeekError ByteString -> Either PeekError a
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second ((ByteString -> a)
-> Either PeekError ByteString -> Either PeekError a)
-> (ByteString -> a)
-> Either PeekError ByteString
-> Either PeekError a
forall a b. (a -> b) -> a -> b
$ String -> a
forall a. IsString a => String -> a
fromString (String -> a) -> (ByteString -> String) -> ByteString -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
Utf8.toString) (Lua (Either PeekError ByteString) -> Lua (Either PeekError a))
-> Peeker ByteString -> Peeker a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Peeker ByteString
peekByteString
peekText :: Peeker T.Text
peekText :: Peeker Text
peekText = (Either PeekError ByteString -> Either PeekError Text)
-> Lua (Either PeekError ByteString) -> Lua (Either PeekError Text)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((ByteString -> Text)
-> Either PeekError ByteString -> Either PeekError Text
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second ByteString -> Text
Utf8.toText) (Lua (Either PeekError ByteString) -> Lua (Either PeekError Text))
-> Peeker ByteString -> Peeker Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Peeker ByteString
peekByteString
peekIntegral :: (Integral a, Read a) => Peeker a
peekIntegral :: Peeker a
peekIntegral StackIndex
idx =
StackIndex -> Lua Type
ltype StackIndex
idx Lua Type
-> (Type -> Lua (Either PeekError a)) -> Lua (Either PeekError a)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Type
TypeNumber -> (Integer -> a) -> Either PeekError Integer -> Either PeekError a
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second Integer -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Either PeekError Integer -> Either PeekError a)
-> Lua (Either PeekError Integer) -> Lua (Either PeekError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
Text -> (StackIndex -> Lua (Maybe Integer)) -> Peeker Integer
forall a. Text -> (StackIndex -> Lua (Maybe a)) -> Peeker a
reportValueOnFailure Text
"Integral" StackIndex -> Lua (Maybe Integer)
tointeger StackIndex
idx
Type
TypeString -> do
String
str <- ByteString -> String
Utf8.toString (ByteString -> String)
-> (Maybe ByteString -> ByteString) -> Maybe ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
ByteString -> Maybe ByteString -> ByteString
forall a. a -> Maybe a -> a
fromMaybe (String -> ByteString
forall a. HasCallStack => String -> a
Prelude.error String
"programming error in peekIntegral")
(Maybe ByteString -> String)
-> Lua (Maybe ByteString) -> Lua String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StackIndex -> Lua (Maybe ByteString)
tostring StackIndex
idx
let msg :: Text
msg = Text
"expected Integral, got '" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack String
str Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"' (string)"
Either PeekError a -> Lua (Either PeekError a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either PeekError a -> Lua (Either PeekError a))
-> Either PeekError a -> Lua (Either PeekError a)
forall a b. (a -> b) -> a -> b
$ Either PeekError a
-> (a -> Either PeekError a) -> Maybe a -> Either PeekError a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (PeekError -> Either PeekError a
forall a b. a -> Either a b
Left (PeekError -> Either PeekError a)
-> PeekError -> Either PeekError a
forall a b. (a -> b) -> a -> b
$ Text -> PeekError
errorMsg Text
msg) a -> Either PeekError a
forall a b. b -> Either a b
Right (Maybe a -> Either PeekError a) -> Maybe a -> Either PeekError a
forall a b. (a -> b) -> a -> b
$ String -> Maybe a
forall a. Read a => String -> Maybe a
readMaybe String
str
Type
_ -> PeekError -> Either PeekError a
forall a b. a -> Either a b
Left (PeekError -> Either PeekError a)
-> Lua PeekError -> Lua (Either PeekError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> StackIndex -> Lua PeekError
mismatchError Text
"Integral" StackIndex
idx
peekRealFloat :: (RealFloat a, Read a) => Peeker a
peekRealFloat :: Peeker a
peekRealFloat StackIndex
idx =
StackIndex -> Lua Type
ltype StackIndex
idx Lua Type
-> (Type -> Lua (Either PeekError a)) -> Lua (Either PeekError a)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Type
TypeString -> do
String
str <- ByteString -> String
Utf8.toString (ByteString -> String)
-> (Maybe ByteString -> ByteString) -> Maybe ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
ByteString -> Maybe ByteString -> ByteString
forall a. a -> Maybe a -> a
fromMaybe (String -> ByteString
forall a. HasCallStack => String -> a
Prelude.error String
"programming error in peekRealFloat")
(Maybe ByteString -> String)
-> Lua (Maybe ByteString) -> Lua String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StackIndex -> Lua (Maybe ByteString)
tostring StackIndex
idx
let msg :: Text
msg = Text
"expected RealFloat, got '" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack String
str Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"' (string)"
Either PeekError a -> Lua (Either PeekError a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either PeekError a -> Lua (Either PeekError a))
-> Either PeekError a -> Lua (Either PeekError a)
forall a b. (a -> b) -> a -> b
$ Either PeekError a
-> (a -> Either PeekError a) -> Maybe a -> Either PeekError a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (PeekError -> Either PeekError a
forall a b. a -> Either a b
Left (PeekError -> Either PeekError a)
-> PeekError -> Either PeekError a
forall a b. (a -> b) -> a -> b
$ Text -> PeekError
errorMsg Text
msg) a -> Either PeekError a
forall a b. b -> Either a b
Right (Maybe a -> Either PeekError a) -> Maybe a -> Either PeekError a
forall a b. (a -> b) -> a -> b
$ String -> Maybe a
forall a. Read a => String -> Maybe a
readMaybe String
str
Type
_ -> (Number -> a) -> Either PeekError Number -> Either PeekError a
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second Number -> a
forall a b. (Real a, Fractional b) => a -> b
realToFrac (Either PeekError Number -> Either PeekError a)
-> Lua (Either PeekError Number) -> Lua (Either PeekError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
Text -> (StackIndex -> Lua (Maybe Number)) -> Peeker Number
forall a. Text -> (StackIndex -> Lua (Maybe a)) -> Peeker a
reportValueOnFailure Text
"RealFloat" StackIndex -> Lua (Maybe Number)
tonumber StackIndex
idx
peekList :: Peeker a -> Peeker [a]
peekList :: Peeker a -> Peeker [a]
peekList Peeker a
peekElement = Text -> (StackIndex -> Lua Bool) -> Peeker [a] -> Peeker [a]
forall a. Text -> (StackIndex -> Lua Bool) -> Peeker a -> Peeker a
typeChecked Text
"table" StackIndex -> Lua Bool
istable (Peeker [a] -> Peeker [a]) -> Peeker [a] -> Peeker [a]
forall a b. (a -> b) -> a -> b
$ \StackIndex
idx -> do
let elementsAt :: [Integer] -> Lua (Either PeekError [a])
elementsAt [] = Either PeekError [a] -> Lua (Either PeekError [a])
forall (m :: * -> *) a. Monad m => a -> m a
return ([a] -> Either PeekError [a]
forall a b. b -> Either a b
Right [])
elementsAt (Integer
i : [Integer]
is) = do
Either PeekError a
eitherX <- StackIndex -> Integer -> Lua ()
rawgeti StackIndex
idx Integer
i Lua () -> Lua (Either PeekError a) -> Lua (Either PeekError a)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Peeker a
peekElement (CInt -> StackIndex
nthFromTop CInt
1) Lua (Either PeekError a) -> Lua () -> Lua (Either PeekError a)
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* StackIndex -> Lua ()
pop StackIndex
1
case Either PeekError a
eitherX of
Right a
x -> ([a] -> [a]) -> Either PeekError [a] -> Either PeekError [a]
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second (a
xa -> [a] -> [a]
forall a. a -> [a] -> [a]
:) (Either PeekError [a] -> Either PeekError [a])
-> Lua (Either PeekError [a]) -> Lua (Either PeekError [a])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Integer] -> Lua (Either PeekError [a])
elementsAt [Integer]
is
Left PeekError
err -> Either PeekError [a] -> Lua (Either PeekError [a])
forall (m :: * -> *) a. Monad m => a -> m a
return (Either PeekError [a] -> Lua (Either PeekError [a]))
-> (PeekError -> Either PeekError [a])
-> PeekError
-> Lua (Either PeekError [a])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PeekError -> Either PeekError [a]
forall a b. a -> Either a b
Left (PeekError -> Lua (Either PeekError [a]))
-> PeekError -> Lua (Either PeekError [a])
forall a b. (a -> b) -> a -> b
$
Text -> PeekError -> PeekError
pushMsg (Text
"in field " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
T.pack (Integer -> String
forall a. Show a => a -> String
show Integer
i)) PeekError
err
Integer
listLength <- Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Integer) -> Lua Int -> Lua Integer
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StackIndex -> Lua Int
rawlen StackIndex
idx
[Integer] -> Lua (Either PeekError [a])
elementsAt [Integer
1..Integer
listLength]
peekMap :: Ord a => Peeker a -> Peeker b -> Peeker (Map a b)
peekMap :: Peeker a -> Peeker b -> Peeker (Map a b)
peekMap Peeker a
keyPeeker Peeker b
valuePeeker =
(Either PeekError [(a, b)] -> Either PeekError (Map a b))
-> Lua (Either PeekError [(a, b)])
-> Lua (Either PeekError (Map a b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Text -> Either PeekError (Map a b) -> Either PeekError (Map a b)
forall a. Text -> Either PeekError a -> Either PeekError a
retrieving Text
"Map" (Either PeekError (Map a b) -> Either PeekError (Map a b))
-> (Either PeekError [(a, b)] -> Either PeekError (Map a b))
-> Either PeekError [(a, b)]
-> Either PeekError (Map a b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([(a, b)] -> Map a b)
-> Either PeekError [(a, b)] -> Either PeekError (Map a b)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second [(a, b)] -> Map a b
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList)
(Lua (Either PeekError [(a, b)])
-> Lua (Either PeekError (Map a b)))
-> (StackIndex -> Lua (Either PeekError [(a, b)]))
-> Peeker (Map a b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Peeker a
-> Peeker b -> StackIndex -> Lua (Either PeekError [(a, b)])
forall a b. Peeker a -> Peeker b -> Peeker [(a, b)]
peekKeyValuePairs Peeker a
keyPeeker Peeker b
valuePeeker
peekKeyValuePairs :: Peeker a -> Peeker b -> Peeker [(a, b)]
peekKeyValuePairs :: Peeker a -> Peeker b -> Peeker [(a, b)]
peekKeyValuePairs Peeker a
keyPeeker Peeker b
valuePeeker =
Text
-> (StackIndex -> Lua Bool) -> Peeker [(a, b)] -> Peeker [(a, b)]
forall a. Text -> (StackIndex -> Lua Bool) -> Peeker a -> Peeker a
typeChecked Text
"table" StackIndex -> Lua Bool
istable (Peeker [(a, b)] -> Peeker [(a, b)])
-> Peeker [(a, b)] -> Peeker [(a, b)]
forall a b. (a -> b) -> a -> b
$ \StackIndex
idx -> do
StackIndex
idx' <- StackIndex -> Lua StackIndex
absindex StackIndex
idx
let remainingPairs :: Lua (Either PeekError [(a, b)])
remainingPairs = do
Either PeekError (Maybe (a, b))
res <- Peeker a -> Peeker b -> Peeker (Maybe (a, b))
forall a b. Peeker a -> Peeker b -> Peeker (Maybe (a, b))
nextPair Peeker a
keyPeeker Peeker b
valuePeeker StackIndex
idx'
case Either PeekError (Maybe (a, b))
res of
Left PeekError
err -> Either PeekError [(a, b)] -> Lua (Either PeekError [(a, b)])
forall (m :: * -> *) a. Monad m => a -> m a
return (Either PeekError [(a, b)] -> Lua (Either PeekError [(a, b)]))
-> Either PeekError [(a, b)] -> Lua (Either PeekError [(a, b)])
forall a b. (a -> b) -> a -> b
$ PeekError -> Either PeekError [(a, b)]
forall a b. a -> Either a b
Left PeekError
err
Right Maybe (a, b)
Nothing -> Either PeekError [(a, b)] -> Lua (Either PeekError [(a, b)])
forall (m :: * -> *) a. Monad m => a -> m a
return (Either PeekError [(a, b)] -> Lua (Either PeekError [(a, b)]))
-> Either PeekError [(a, b)] -> Lua (Either PeekError [(a, b)])
forall a b. (a -> b) -> a -> b
$ [(a, b)] -> Either PeekError [(a, b)]
forall a b. b -> Either a b
Right []
Right (Just (a, b)
a) -> ([(a, b)] -> [(a, b)])
-> Either PeekError [(a, b)] -> Either PeekError [(a, b)]
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second ((a, b)
a(a, b) -> [(a, b)] -> [(a, b)]
forall a. a -> [a] -> [a]
:) (Either PeekError [(a, b)] -> Either PeekError [(a, b)])
-> Lua (Either PeekError [(a, b)])
-> Lua (Either PeekError [(a, b)])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Lua (Either PeekError [(a, b)])
remainingPairs
Lua ()
pushnil
Lua (Either PeekError [(a, b)])
remainingPairs
nextPair :: Peeker a -> Peeker b -> Peeker (Maybe (a, b))
nextPair :: Peeker a -> Peeker b -> Peeker (Maybe (a, b))
nextPair Peeker a
keyPeeker Peeker b
valuePeeker StackIndex
idx = Text
-> Either PeekError (Maybe (a, b))
-> Either PeekError (Maybe (a, b))
forall a. Text -> Either PeekError a -> Either PeekError a
retrieving Text
"key-value pair" (Either PeekError (Maybe (a, b))
-> Either PeekError (Maybe (a, b)))
-> Lua (Either PeekError (Maybe (a, b)))
-> Lua (Either PeekError (Maybe (a, b)))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> do
Bool
hasNext <- StackIndex -> Lua Bool
next StackIndex
idx
if Bool -> Bool
not Bool
hasNext
then Either PeekError (Maybe (a, b))
-> Lua (Either PeekError (Maybe (a, b)))
forall (m :: * -> *) a. Monad m => a -> m a
return (Either PeekError (Maybe (a, b))
-> Lua (Either PeekError (Maybe (a, b))))
-> Either PeekError (Maybe (a, b))
-> Lua (Either PeekError (Maybe (a, b)))
forall a b. (a -> b) -> a -> b
$ Maybe (a, b) -> Either PeekError (Maybe (a, b))
forall a b. b -> Either a b
Right Maybe (a, b)
forall a. Maybe a
Nothing
else do
Either PeekError a
key <- Text -> Either PeekError a -> Either PeekError a
forall a. Text -> Either PeekError a -> Either PeekError a
retrieving Text
"key" (Either PeekError a -> Either PeekError a)
-> Lua (Either PeekError a) -> Lua (Either PeekError a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Peeker a
keyPeeker (CInt -> StackIndex
nthFromTop CInt
2)
Either PeekError b
value <- Text -> Either PeekError b -> Either PeekError b
forall a. Text -> Either PeekError a -> Either PeekError a
retrieving Text
"value" (Either PeekError b -> Either PeekError b)
-> Lua (Either PeekError b) -> Lua (Either PeekError b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Peeker b
valuePeeker (CInt -> StackIndex
nthFromTop CInt
1)
StackIndex -> Lua ()
pop StackIndex
1
Either PeekError (Maybe (a, b))
-> Lua (Either PeekError (Maybe (a, b)))
forall (m :: * -> *) a. Monad m => a -> m a
return (Either PeekError (Maybe (a, b))
-> Lua (Either PeekError (Maybe (a, b))))
-> Either PeekError (Maybe (a, b))
-> Lua (Either PeekError (Maybe (a, b)))
forall a b. (a -> b) -> a -> b
$ ((a, b) -> Maybe (a, b)) -> a -> b -> Maybe (a, b)
forall a b c. ((a, b) -> c) -> a -> b -> c
curry (a, b) -> Maybe (a, b)
forall a. a -> Maybe a
Just (a -> b -> Maybe (a, b))
-> Either PeekError a -> Either PeekError (b -> Maybe (a, b))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Either PeekError a
key Either PeekError (b -> Maybe (a, b))
-> Either PeekError b -> Either PeekError (Maybe (a, b))
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Either PeekError b
value
peekSet :: Ord a => Peeker a -> Peeker (Set a)
peekSet :: Peeker a -> Peeker (Set a)
peekSet Peeker a
elementPeeker =
(Either PeekError [(a, Bool)] -> Either PeekError (Set a))
-> Lua (Either PeekError [(a, Bool)])
-> Lua (Either PeekError (Set a))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Text -> Either PeekError (Set a) -> Either PeekError (Set a)
forall a. Text -> Either PeekError a -> Either PeekError a
retrieving Text
"Set" (Either PeekError (Set a) -> Either PeekError (Set a))
-> (Either PeekError [(a, Bool)] -> Either PeekError (Set a))
-> Either PeekError [(a, Bool)]
-> Either PeekError (Set a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
([(a, Bool)] -> Set a)
-> Either PeekError [(a, Bool)] -> Either PeekError (Set a)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second ([a] -> Set a
forall a. Ord a => [a] -> Set a
Set.fromList ([a] -> Set a) -> ([(a, Bool)] -> [a]) -> [(a, Bool)] -> Set a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((a, Bool) -> a) -> [(a, Bool)] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map (a, Bool) -> a
forall a b. (a, b) -> a
fst ([(a, Bool)] -> [a])
-> ([(a, Bool)] -> [(a, Bool)]) -> [(a, Bool)] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((a, Bool) -> Bool) -> [(a, Bool)] -> [(a, Bool)]
forall a. (a -> Bool) -> [a] -> [a]
filter (a, Bool) -> Bool
forall a b. (a, b) -> b
snd))
(Lua (Either PeekError [(a, Bool)])
-> Lua (Either PeekError (Set a)))
-> (StackIndex -> Lua (Either PeekError [(a, Bool)]))
-> Peeker (Set a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Peeker a
-> Peeker Bool -> StackIndex -> Lua (Either PeekError [(a, Bool)])
forall a b. Peeker a -> Peeker b -> Peeker [(a, b)]
peekKeyValuePairs Peeker a
elementPeeker Peeker Bool
peekBool
optional :: Peeker a
-> Peeker (Maybe a)
optional :: Peeker a -> Peeker (Maybe a)
optional Peeker a
peeker StackIndex
idx = do
Bool
noValue <- StackIndex -> Lua Bool
Lua.isnoneornil StackIndex
idx
if Bool
noValue
then Either PeekError (Maybe a) -> Lua (Either PeekError (Maybe a))
forall (m :: * -> *) a. Monad m => a -> m a
return (Either PeekError (Maybe a) -> Lua (Either PeekError (Maybe a)))
-> Either PeekError (Maybe a) -> Lua (Either PeekError (Maybe a))
forall a b. (a -> b) -> a -> b
$ Maybe a -> Either PeekError (Maybe a)
forall a b. b -> Either a b
Right Maybe a
forall a. Maybe a
Nothing
else (a -> Maybe a) -> Either PeekError a -> Either PeekError (Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Maybe a
forall a. a -> Maybe a
Just (Either PeekError a -> Either PeekError (Maybe a))
-> Lua (Either PeekError a) -> Lua (Either PeekError (Maybe a))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Peeker a
peeker StackIndex
idx