{-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE TypeSynonymInstances #-} module Servant.Kotlin.Type ( KotlinClass (..) , KotlinPrimitiveClass (..) , KotlinExClass (..) , KotlinDataClass (..) , KotlinFields (..) , KotlinField (..) , KotlinType (..) , GenericKotlinType (..) , GenericKotlinFields (..) , toKotlinType' ) where import Data.Int (Int16, Int32, Int64, Int8) import Data.IntMap (IntMap) import Data.Map (Map) import Data.Maybe (fromMaybe) import Data.Proxy (Proxy (..)) import Data.Text (Text, pack) import Data.Time (UTCTime) import GHC.Generics import Servant.API (NoContent (..)) data KotlinClass = PrimitiveClass KotlinPrimitiveClass | DataClass KotlinDataClass | ExClass KotlinExClass deriving (Show, Eq) data KotlinPrimitiveClass = KDouble | KFloat | KLong | KInt | KShort | KByte | KChar | KBoolean | KArray KotlinClass | KString | KUnit | KNullable KotlinClass | KAny deriving (Show, Eq) data KotlinExClass = KList KotlinClass | KHashMap KotlinClass KotlinClass | KPair KotlinClass KotlinClass | KTime deriving (Show, Eq) data KotlinDataClass = KotlinDataClass Text KotlinFields deriving (Show, Eq) data KotlinFields = Node KotlinField | Brunch KotlinFields KotlinFields deriving (Show, Eq) data KotlinField = KotlinField Text KotlinClass deriving (Show, Eq) class KotlinType a where toKotlinType :: a -> Maybe KotlinClass toKotlinType = genericToKotlinType . from default toKotlinType :: (Generic a, GenericKotlinType (Rep a)) => a -> Maybe KotlinClass class GenericKotlinType f where genericToKotlinType :: f a -> Maybe KotlinClass instance (Datatype d, GenericKotlinFields f) => GenericKotlinType (D1 d f) where genericToKotlinType datatype = fmap DataClass $ KotlinDataClass (pack $ datatypeName datatype) <$> genericToKotlinFields (unM1 datatype) class GenericKotlinFields f where genericToKotlinFields :: f a -> Maybe KotlinFields instance (Constructor c, GenericKotlinFields f) => GenericKotlinFields (C1 c f) where genericToKotlinFields constructor = if conIsRecord constructor then genericToKotlinFields (unM1 constructor) else Nothing instance GenericKotlinFields (f :+: g) where genericToKotlinFields _ = Nothing instance (Selector s, GenericKotlinType a) => GenericKotlinFields (S1 s a) where genericToKotlinFields selector = case selName selector of "" -> Nothing name -> Node . KotlinField (pack name) <$> genericToKotlinType (undefined :: a p) instance (GenericKotlinFields f, GenericKotlinFields g) => GenericKotlinFields (f :*: g) where genericToKotlinFields _ = Brunch <$> genericToKotlinFields (undefined :: f p) <*> genericToKotlinFields (undefined :: g p) instance GenericKotlinFields U1 where genericToKotlinFields _ = Nothing instance KotlinType a => GenericKotlinType (Rec0 a) where genericToKotlinType _ = toKotlinType (Proxy :: Proxy a) instance KotlinType a => KotlinType [a] where toKotlinType _ = ExClass . KList <$> toKotlinType (Proxy :: Proxy a) instance KotlinType a => KotlinType (Maybe a) where toKotlinType _ = PrimitiveClass . KNullable <$> toKotlinType (Proxy :: Proxy a) instance KotlinType () where toKotlinType _ = Just $ PrimitiveClass KUnit instance KotlinType Text where toKotlinType _ = Just $ PrimitiveClass KString instance KotlinType UTCTime where toKotlinType _ = Just $ ExClass KTime instance KotlinType Float where toKotlinType _ = Just $ PrimitiveClass KFloat instance KotlinType Double where toKotlinType _ = Just $ PrimitiveClass KDouble instance KotlinType Int where toKotlinType _ = Just $ PrimitiveClass KInt instance KotlinType Int8 where toKotlinType _ = Just $ PrimitiveClass KByte instance KotlinType Int16 where toKotlinType _ = Just $ PrimitiveClass KShort instance KotlinType Int32 where toKotlinType _ = Just $ PrimitiveClass KInt instance KotlinType Int64 where toKotlinType _ = Just $ PrimitiveClass KLong instance KotlinType Char where toKotlinType _ = Just $ PrimitiveClass KChar instance KotlinType Bool where toKotlinType _ = Just $ PrimitiveClass KBoolean instance (KotlinType a, KotlinType b) => KotlinType (a, b) where toKotlinType _ = fmap ExClass $ KPair <$> toKotlinType (Proxy :: Proxy a) <*> toKotlinType (Proxy :: Proxy b) instance (KotlinType a) => KotlinType (Proxy a) where toKotlinType _ = toKotlinType (undefined :: a) instance (KotlinType k, KotlinType v) => KotlinType (Map k v) where toKotlinType _ = fmap ExClass $ KHashMap <$> toKotlinType (Proxy :: Proxy k) <*> toKotlinType (Proxy :: Proxy v) instance (KotlinType v) => KotlinType (IntMap v) where toKotlinType _ = PrimitiveClass . KArray <$> toKotlinType (Proxy :: Proxy v) instance KotlinType NoContent where toKotlinType _ = Just $ PrimitiveClass KUnit toKotlinType' :: (KotlinType a) => a -> KotlinClass toKotlinType' = fromMaybe (PrimitiveClass KAny) . toKotlinType