{-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE DerivingVia #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE UndecidableInstances #-} module Encode where import Data.List (intercalate) import Data.Override (Override) import GHC.Generics class Encode a where encode :: a -> String default encode :: (Generic a, GEncode (Rep a)) => a -> String encode = gencode . from instance ( Generic (Override a xs) , GEncode (Rep (Override a xs)) ) => Encode (Override a xs) class GEncode f where gencode :: f a -> String instance (GEncode f) => GEncode (M1 D x f) where gencode (M1 f) = gencode f instance (GEncode f, Constructor c) => GEncode (M1 C c f) where gencode m@(M1 f) = conName m <> ":" <> gencode f instance (GEncode f, GEncode g) => GEncode (f :*: g) where gencode (f :*: g) = gencode f <> "," <> gencode g instance (GEncode f, GEncode g) => GEncode (f :+: g) where gencode = \case L1 f -> gencode f R1 g -> gencode g instance (GEncode f, Selector s) => GEncode (M1 S s f) where gencode m@(M1 f) = if null (selName m) then gencode f else selName m <> "=" <> gencode f instance (Encode a) => GEncode (K1 R a) where gencode (K1 a) = encode a instance GEncode U1 where gencode _ = "" instance Encode Int where encode = show instance Encode Char where encode = pure -- | Create an overlapping instance to verify that overriding with -- 'ListOf' avoids this instance. instance {-# OVERLAPPING #-} Encode String where encode = id deriving via (ListOf a) instance (Encode a) => Encode [a] newtype ListOf a = ListOf { unListOf :: [a] } instance (Encode a) => Encode (ListOf a) where encode = intercalate "," . map encode . unListOf