packages feed

nestedtext-0.1.2: src/Data/NestedText/From.hs

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

module Data.NestedText.From where

import Control.Monad (forM)
import Data.Bifunctor (Bifunctor(first))
import qualified Data.Binary.Builder as BB
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Short as SBS
import Data.Kind (Type)
import qualified Data.Map as M
import qualified Data.Text as TS
import qualified Data.Text.Encoding as TE
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Short as ST
import qualified Data.Vector as V
import Data.Void (Void)
import Generic.Data

import Data.NestedText.Type

class FromItem a where
  type FromItemError a :: Type
  fromItem :: Item -> Either (FromItemError a) a
class Ord a => FromKey a where
  type FromKeyError a :: Type
  fromKey :: Key -> Either (FromKeyError a) a

instance FromItem Item where
  type FromItemError Item = Void
  fromItem = Right

data FromItemError'Common
  = FromItemError'Common'InvalidValue
  deriving (Generic, Eq, Show)

instance FromItem BS.ByteString where
  type FromItemError BS.ByteString = FromItemError'Common
  fromItem (Item'String t) = Right $ TE.encodeUtf8 t
  fromItem _ = Left FromItemError'Common'InvalidValue
instance FromItem BL.ByteString where
  type FromItemError BL.ByteString = FromItemError'Common
  fromItem (Item'String t) = Right $ BB.toLazyByteString $ TE.encodeUtf8Builder t
  fromItem _ = Left FromItemError'Common'InvalidValue
instance FromItem TS.Text where
  type FromItemError TS.Text = FromItemError'Common
  fromItem (Item'String t) = Right t
  fromItem _ = Left FromItemError'Common'InvalidValue
instance FromItem TL.Text where
  type FromItemError TL.Text = FromItemError'Common
  fromItem (Item'String t) = Right $ TL.fromStrict t
  fromItem _ = Left FromItemError'Common'InvalidValue

data FromItemError'List a
  = FromItemError'List'InvalidValue
  | FromItemError'List'ElementError (FromItemError a)
  deriving (Generic)
instance Eq (FromItemError a) => Eq (FromItemError'List a) where
  (==) = geq
instance Show (FromItemError a) => Show (FromItemError'List a) where
  showsPrec = gshowsPrec

instance FromItem a => FromItem [a] where
  type FromItemError [a] = FromItemError'List a
  fromItem (Item'List xs) = fmap V.toList $ V.forM xs $ \x ->
    first FromItemError'List'ElementError $ fromItem x
  fromItem _ = Left FromItemError'List'InvalidValue
instance FromItem a => FromItem (V.Vector a) where
  type FromItemError (V.Vector a) = FromItemError'List a
  fromItem (Item'List xs) = V.forM xs $ \x ->
    first FromItemError'List'ElementError $ fromItem x
  fromItem _ = Left FromItemError'List'InvalidValue

instance FromKey BS.ByteString where
  type FromKeyError BS.ByteString = Void
  fromKey st = Right $ ST.toByteString st
instance FromKey BL.ByteString where
  type FromKeyError BL.ByteString = Void
  fromKey st = Right $ BB.toLazyByteString $ ST.toBuilder st
instance FromKey SBS.ShortByteString where
  type FromKeyError SBS.ShortByteString = Void
  fromKey st = Right $ ST.toShortByteString st
instance FromKey TS.Text where
  type FromKeyError TS.Text = Void
  fromKey st = Right $ ST.toText st
instance FromKey TL.Text where
  type FromKeyError TL.Text = Void
  fromKey st = Right $ TL.fromStrict $ ST.toText st
instance FromKey ST.ShortText where
  type FromKeyError ST.ShortText = Void
  fromKey = Right

data FromItemError'Map k v
  = FromItemError'Map'InvalidValue
  | FromItemError'Map'KeyError (FromKeyError k)
  | FromItemError'Map'ValueError (FromItemError v)
  deriving (Generic)
instance (Eq (FromKeyError k), Eq (FromItemError v))
  => Eq (FromItemError'Map k v) where
    (==) = geq
instance (Show (FromKeyError k), Show (FromItemError v))
  => Show (FromItemError'Map k v) where
    showsPrec = gshowsPrec

instance (FromKey k, FromItem v) => FromItem (M.Map k v) where
  type FromItemError (M.Map k v) = FromItemError'Map k v
  fromItem (Item'Dictionary dic) =
    fmap M.fromList $ forM (M.toAscList dic) $ \(ks, vs) -> do
      kd <- first FromItemError'Map'KeyError $ fromKey ks
      vd <- first FromItemError'Map'ValueError $ fromItem vs
      return (kd, vd)
  fromItem _ = Left FromItemError'Map'InvalidValue