module Data.JSON.ToGo ( ValueM(..) , applyV, applyV_ , applyP, applyP_ ) where import Data.JSON.ToGo.Parser import Data.Aeson (Value(..)) import Data.Monoid (Monoid) import Data.Scientific (Scientific) import Data.Text (Text) import qualified Data.Vector as V import qualified Data.HashMap.Strict as H import Control.Monad (MonadPlus, mzero, msum) import Control.Monad.Trans.Class (lift) data ValueM m a = NullM (m a) | BoolM (Bool -> m a) | NumberM (Scientific -> m a) | StringM (Text -> m a) | ArrayM (Int -> ValueM m a) | ObjectM (Text -> ValueM m a) | AnyM (Value -> m a) instance Monad m => Functor (ValueM m) where fmap g (NullM ma) = NullM $ ma >>= return.g fmap g (BoolM f) = BoolM $ fmap (>>= return.g) f fmap g (NumberM f) = NumberM $ fmap (>>= return.g) f fmap g (StringM f) = StringM $ fmap (>>= return.g) f fmap g (ArrayM f) = ArrayM $ fmap (fmap g) f fmap g (ObjectM f) = ObjectM $ fmap (fmap g) f fmap g (AnyM f) = AnyM $ fmap (>>= return.g) f applyV :: MonadPlus m => ValueM m a -> Value -> m a applyV (NullM ma) Null = ma applyV (BoolM f) (Bool b) = f b applyV (NumberM f) (Number n) = f n applyV (StringM f) (String s) = f s applyV (ArrayM f) (Array v) = msum $ map (uncurry (applyV . f)) (V.toList $ V.indexed v) applyV (ObjectM f) (Object h) = msum $ map (uncurry (applyV . f)) (H.toList h) applyV (AnyM f) v = f v applyV _ _ = mzero applyV_ :: Monad m => ValueM m a -> Value -> m () applyV_ (NullM ma) Null = ma >> return () applyV_ (BoolM f) (Bool b) = f b >> return () applyV_ (NumberM f) (Number n) = f n >> return () applyV_ (StringM f) (String s) = f s >> return () applyV_ (ArrayM f) (Array v) = mapM_ (uncurry (applyV_ . f)) (V.toList $ V.indexed v) applyV_ (ObjectM f) (Object ias) = mapM_ (uncurry (applyV_ . f)) (H.toList ias) applyV_ (AnyM f) v = f v >> return () applyV_ _ _ = return () applyP :: (Monad m, Monoid r) => ValueM m r -> ParserM m r applyP (ArrayM f) = parray (applyP.f) applyP (ObjectM f) = pobject (applyP.f) applyP (NullM m) = pbool >> lift m applyP (BoolM f) = pbool >>= lift.f applyP (NumberM f) = pnumber >>= lift.f applyP (StringM f) = pstring >>= lift.f applyP (AnyM f) = pvalue >>= lift.f applyP_ :: Monad m => ValueM m a -> ParserM m () applyP_ = applyP . fmap (const ())