{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE FlexibleInstances  #-}
{-# LANGUAGE RankNTypes  #-}

-- | Provides base types and utility functions needed for modules in Discord.Internal.Types
module Discord.Internal.Types.Prelude where

import Data.Bits
import Data.Word

import Data.Aeson.Types
import qualified Data.ByteString as B
import Data.Time.Clock
import qualified Data.Text as T
import Data.Time.Clock.POSIX
import Web.Internal.HttpApiData

import Data.Bifunctor (first)
import Text.Read (readMaybe)
import Data.Data (Data (dataTypeOf), dataTypeConstrs, fromConstr)

-- | Authorization token for the Discord API
newtype Auth = Auth T.Text
  deriving (Int -> Auth -> ShowS
[Auth] -> ShowS
Auth -> String
(Int -> Auth -> ShowS)
-> (Auth -> String) -> ([Auth] -> ShowS) -> Show Auth
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Auth] -> ShowS
$cshowList :: [Auth] -> ShowS
show :: Auth -> String
$cshow :: Auth -> String
showsPrec :: Int -> Auth -> ShowS
$cshowsPrec :: Int -> Auth -> ShowS
Show, ReadPrec [Auth]
ReadPrec Auth
Int -> ReadS Auth
ReadS [Auth]
(Int -> ReadS Auth)
-> ReadS [Auth] -> ReadPrec Auth -> ReadPrec [Auth] -> Read Auth
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Auth]
$creadListPrec :: ReadPrec [Auth]
readPrec :: ReadPrec Auth
$creadPrec :: ReadPrec Auth
readList :: ReadS [Auth]
$creadList :: ReadS [Auth]
readsPrec :: Int -> ReadS Auth
$creadsPrec :: Int -> ReadS Auth
Read, Auth -> Auth -> Bool
(Auth -> Auth -> Bool) -> (Auth -> Auth -> Bool) -> Eq Auth
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Auth -> Auth -> Bool
$c/= :: Auth -> Auth -> Bool
== :: Auth -> Auth -> Bool
$c== :: Auth -> Auth -> Bool
Eq, Eq Auth
Eq Auth
-> (Auth -> Auth -> Ordering)
-> (Auth -> Auth -> Bool)
-> (Auth -> Auth -> Bool)
-> (Auth -> Auth -> Bool)
-> (Auth -> Auth -> Bool)
-> (Auth -> Auth -> Auth)
-> (Auth -> Auth -> Auth)
-> Ord Auth
Auth -> Auth -> Bool
Auth -> Auth -> Ordering
Auth -> Auth -> Auth
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Auth -> Auth -> Auth
$cmin :: Auth -> Auth -> Auth
max :: Auth -> Auth -> Auth
$cmax :: Auth -> Auth -> Auth
>= :: Auth -> Auth -> Bool
$c>= :: Auth -> Auth -> Bool
> :: Auth -> Auth -> Bool
$c> :: Auth -> Auth -> Bool
<= :: Auth -> Auth -> Bool
$c<= :: Auth -> Auth -> Bool
< :: Auth -> Auth -> Bool
$c< :: Auth -> Auth -> Bool
compare :: Auth -> Auth -> Ordering
$ccompare :: Auth -> Auth -> Ordering
$cp1Ord :: Eq Auth
Ord)


-- | Get the raw token formatted for use with the websocket gateway
authToken :: Auth -> T.Text
authToken :: Auth -> Text
authToken (Auth Text
tok) = let token :: Text
token = Text -> Text
T.strip Text
tok
                           bot :: Text
bot = if Text
"Bot " Text -> Text -> Bool
`T.isPrefixOf` Text
token then Text
"" else Text
"Bot "
                       in Text
bot Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
token

-- | A unique integer identifier. Can be used to calculate the creation date of an entity.
newtype Snowflake = Snowflake { Snowflake -> Word64
unSnowflake :: Word64 }
  deriving (Eq Snowflake
Eq Snowflake
-> (Snowflake -> Snowflake -> Ordering)
-> (Snowflake -> Snowflake -> Bool)
-> (Snowflake -> Snowflake -> Bool)
-> (Snowflake -> Snowflake -> Bool)
-> (Snowflake -> Snowflake -> Bool)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> Ord Snowflake
Snowflake -> Snowflake -> Bool
Snowflake -> Snowflake -> Ordering
Snowflake -> Snowflake -> Snowflake
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Snowflake -> Snowflake -> Snowflake
$cmin :: Snowflake -> Snowflake -> Snowflake
max :: Snowflake -> Snowflake -> Snowflake
$cmax :: Snowflake -> Snowflake -> Snowflake
>= :: Snowflake -> Snowflake -> Bool
$c>= :: Snowflake -> Snowflake -> Bool
> :: Snowflake -> Snowflake -> Bool
$c> :: Snowflake -> Snowflake -> Bool
<= :: Snowflake -> Snowflake -> Bool
$c<= :: Snowflake -> Snowflake -> Bool
< :: Snowflake -> Snowflake -> Bool
$c< :: Snowflake -> Snowflake -> Bool
compare :: Snowflake -> Snowflake -> Ordering
$ccompare :: Snowflake -> Snowflake -> Ordering
$cp1Ord :: Eq Snowflake
Ord, Snowflake -> Snowflake -> Bool
(Snowflake -> Snowflake -> Bool)
-> (Snowflake -> Snowflake -> Bool) -> Eq Snowflake
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Snowflake -> Snowflake -> Bool
$c/= :: Snowflake -> Snowflake -> Bool
== :: Snowflake -> Snowflake -> Bool
$c== :: Snowflake -> Snowflake -> Bool
Eq, Integer -> Snowflake
Snowflake -> Snowflake
Snowflake -> Snowflake -> Snowflake
(Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake)
-> (Snowflake -> Snowflake)
-> (Snowflake -> Snowflake)
-> (Integer -> Snowflake)
-> Num Snowflake
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
fromInteger :: Integer -> Snowflake
$cfromInteger :: Integer -> Snowflake
signum :: Snowflake -> Snowflake
$csignum :: Snowflake -> Snowflake
abs :: Snowflake -> Snowflake
$cabs :: Snowflake -> Snowflake
negate :: Snowflake -> Snowflake
$cnegate :: Snowflake -> Snowflake
* :: Snowflake -> Snowflake -> Snowflake
$c* :: Snowflake -> Snowflake -> Snowflake
- :: Snowflake -> Snowflake -> Snowflake
$c- :: Snowflake -> Snowflake -> Snowflake
+ :: Snowflake -> Snowflake -> Snowflake
$c+ :: Snowflake -> Snowflake -> Snowflake
Num, Enum Snowflake
Real Snowflake
Real Snowflake
-> Enum Snowflake
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> (Snowflake, Snowflake))
-> (Snowflake -> Snowflake -> (Snowflake, Snowflake))
-> (Snowflake -> Integer)
-> Integral Snowflake
Snowflake -> Integer
Snowflake -> Snowflake -> (Snowflake, Snowflake)
Snowflake -> Snowflake -> Snowflake
forall a.
Real a
-> Enum a
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> (a, a))
-> (a -> a -> (a, a))
-> (a -> Integer)
-> Integral a
toInteger :: Snowflake -> Integer
$ctoInteger :: Snowflake -> Integer
divMod :: Snowflake -> Snowflake -> (Snowflake, Snowflake)
$cdivMod :: Snowflake -> Snowflake -> (Snowflake, Snowflake)
quotRem :: Snowflake -> Snowflake -> (Snowflake, Snowflake)
$cquotRem :: Snowflake -> Snowflake -> (Snowflake, Snowflake)
mod :: Snowflake -> Snowflake -> Snowflake
$cmod :: Snowflake -> Snowflake -> Snowflake
div :: Snowflake -> Snowflake -> Snowflake
$cdiv :: Snowflake -> Snowflake -> Snowflake
rem :: Snowflake -> Snowflake -> Snowflake
$crem :: Snowflake -> Snowflake -> Snowflake
quot :: Snowflake -> Snowflake -> Snowflake
$cquot :: Snowflake -> Snowflake -> Snowflake
$cp2Integral :: Enum Snowflake
$cp1Integral :: Real Snowflake
Integral, Int -> Snowflake
Snowflake -> Int
Snowflake -> [Snowflake]
Snowflake -> Snowflake
Snowflake -> Snowflake -> [Snowflake]
Snowflake -> Snowflake -> Snowflake -> [Snowflake]
(Snowflake -> Snowflake)
-> (Snowflake -> Snowflake)
-> (Int -> Snowflake)
-> (Snowflake -> Int)
-> (Snowflake -> [Snowflake])
-> (Snowflake -> Snowflake -> [Snowflake])
-> (Snowflake -> Snowflake -> [Snowflake])
-> (Snowflake -> Snowflake -> Snowflake -> [Snowflake])
-> Enum Snowflake
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Snowflake -> Snowflake -> Snowflake -> [Snowflake]
$cenumFromThenTo :: Snowflake -> Snowflake -> Snowflake -> [Snowflake]
enumFromTo :: Snowflake -> Snowflake -> [Snowflake]
$cenumFromTo :: Snowflake -> Snowflake -> [Snowflake]
enumFromThen :: Snowflake -> Snowflake -> [Snowflake]
$cenumFromThen :: Snowflake -> Snowflake -> [Snowflake]
enumFrom :: Snowflake -> [Snowflake]
$cenumFrom :: Snowflake -> [Snowflake]
fromEnum :: Snowflake -> Int
$cfromEnum :: Snowflake -> Int
toEnum :: Int -> Snowflake
$ctoEnum :: Int -> Snowflake
pred :: Snowflake -> Snowflake
$cpred :: Snowflake -> Snowflake
succ :: Snowflake -> Snowflake
$csucc :: Snowflake -> Snowflake
Enum, Num Snowflake
Ord Snowflake
Num Snowflake
-> Ord Snowflake -> (Snowflake -> Rational) -> Real Snowflake
Snowflake -> Rational
forall a. Num a -> Ord a -> (a -> Rational) -> Real a
toRational :: Snowflake -> Rational
$ctoRational :: Snowflake -> Rational
$cp2Real :: Ord Snowflake
$cp1Real :: Num Snowflake
Real, Eq Snowflake
Snowflake
Eq Snowflake
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake -> Snowflake)
-> (Snowflake -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> Snowflake
-> (Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Bool)
-> (Snowflake -> Maybe Int)
-> (Snowflake -> Int)
-> (Snowflake -> Bool)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int -> Snowflake)
-> (Snowflake -> Int)
-> Bits Snowflake
Int -> Snowflake
Snowflake -> Bool
Snowflake -> Int
Snowflake -> Maybe Int
Snowflake -> Snowflake
Snowflake -> Int -> Bool
Snowflake -> Int -> Snowflake
Snowflake -> Snowflake -> Snowflake
forall a.
Eq a
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> a
-> (Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> Bool)
-> (a -> Maybe Int)
-> (a -> Int)
-> (a -> Bool)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int)
-> Bits a
popCount :: Snowflake -> Int
$cpopCount :: Snowflake -> Int
rotateR :: Snowflake -> Int -> Snowflake
$crotateR :: Snowflake -> Int -> Snowflake
rotateL :: Snowflake -> Int -> Snowflake
$crotateL :: Snowflake -> Int -> Snowflake
unsafeShiftR :: Snowflake -> Int -> Snowflake
$cunsafeShiftR :: Snowflake -> Int -> Snowflake
shiftR :: Snowflake -> Int -> Snowflake
$cshiftR :: Snowflake -> Int -> Snowflake
unsafeShiftL :: Snowflake -> Int -> Snowflake
$cunsafeShiftL :: Snowflake -> Int -> Snowflake
shiftL :: Snowflake -> Int -> Snowflake
$cshiftL :: Snowflake -> Int -> Snowflake
isSigned :: Snowflake -> Bool
$cisSigned :: Snowflake -> Bool
bitSize :: Snowflake -> Int
$cbitSize :: Snowflake -> Int
bitSizeMaybe :: Snowflake -> Maybe Int
$cbitSizeMaybe :: Snowflake -> Maybe Int
testBit :: Snowflake -> Int -> Bool
$ctestBit :: Snowflake -> Int -> Bool
complementBit :: Snowflake -> Int -> Snowflake
$ccomplementBit :: Snowflake -> Int -> Snowflake
clearBit :: Snowflake -> Int -> Snowflake
$cclearBit :: Snowflake -> Int -> Snowflake
setBit :: Snowflake -> Int -> Snowflake
$csetBit :: Snowflake -> Int -> Snowflake
bit :: Int -> Snowflake
$cbit :: Int -> Snowflake
zeroBits :: Snowflake
$czeroBits :: Snowflake
rotate :: Snowflake -> Int -> Snowflake
$crotate :: Snowflake -> Int -> Snowflake
shift :: Snowflake -> Int -> Snowflake
$cshift :: Snowflake -> Int -> Snowflake
complement :: Snowflake -> Snowflake
$ccomplement :: Snowflake -> Snowflake
xor :: Snowflake -> Snowflake -> Snowflake
$cxor :: Snowflake -> Snowflake -> Snowflake
.|. :: Snowflake -> Snowflake -> Snowflake
$c.|. :: Snowflake -> Snowflake -> Snowflake
.&. :: Snowflake -> Snowflake -> Snowflake
$c.&. :: Snowflake -> Snowflake -> Snowflake
$cp1Bits :: Eq Snowflake
Bits)

instance Show Snowflake where
  show :: Snowflake -> String
show (Snowflake Word64
a) = Word64 -> String
forall a. Show a => a -> String
show Word64
a

instance Read Snowflake where
  readsPrec :: Int -> ReadS Snowflake
readsPrec Int
p = ((Word64, String) -> (Snowflake, String))
-> [(Word64, String)] -> [(Snowflake, String)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Word64 -> Snowflake) -> (Word64, String) -> (Snowflake, String)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Word64 -> Snowflake
Snowflake) ([(Word64, String)] -> [(Snowflake, String)])
-> (String -> [(Word64, String)]) -> ReadS Snowflake
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String -> [(Word64, String)]
forall a. Read a => Int -> ReadS a
readsPrec Int
p

instance ToJSON Snowflake where
  toJSON :: Snowflake -> Value
toJSON (Snowflake Word64
snowflake) = Text -> Value
String (Text -> Value) -> (String -> Text) -> String -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack (String -> Value) -> String -> Value
forall a b. (a -> b) -> a -> b
$ Word64 -> String
forall a. Show a => a -> String
show Word64
snowflake

instance FromJSON Snowflake where
  parseJSON :: Value -> Parser Snowflake
parseJSON =
    String -> (Text -> Parser Snowflake) -> Value -> Parser Snowflake
forall a. String -> (Text -> Parser a) -> Value -> Parser a
withText
      String
"Snowflake"
      ( \Text
snowflake ->
          case String -> Maybe Snowflake
forall a. Read a => String -> Maybe a
readMaybe (Text -> String
T.unpack Text
snowflake) of
            Maybe Snowflake
Nothing -> String -> Parser Snowflake
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"null snowflake"
            (Just Snowflake
i) -> Snowflake -> Parser Snowflake
forall (f :: * -> *) a. Applicative f => a -> f a
pure Snowflake
i
      )

instance ToHttpApiData Snowflake where
  toUrlPiece :: Snowflake -> Text
toUrlPiece = String -> Text
T.pack (String -> Text) -> (Snowflake -> String) -> Snowflake -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Snowflake -> String
forall a. Show a => a -> String
show

newtype DiscordId a = DiscordId { DiscordId a -> Snowflake
unId :: Snowflake }
  deriving (Eq (DiscordId a)
Eq (DiscordId a)
-> (DiscordId a -> DiscordId a -> Ordering)
-> (DiscordId a -> DiscordId a -> Bool)
-> (DiscordId a -> DiscordId a -> Bool)
-> (DiscordId a -> DiscordId a -> Bool)
-> (DiscordId a -> DiscordId a -> Bool)
-> (DiscordId a -> DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a -> DiscordId a)
-> Ord (DiscordId a)
DiscordId a -> DiscordId a -> Bool
DiscordId a -> DiscordId a -> Ordering
DiscordId a -> DiscordId a -> DiscordId a
forall a. Eq (DiscordId a)
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. DiscordId a -> DiscordId a -> Bool
forall a. DiscordId a -> DiscordId a -> Ordering
forall a. DiscordId a -> DiscordId a -> DiscordId a
min :: DiscordId a -> DiscordId a -> DiscordId a
$cmin :: forall a. DiscordId a -> DiscordId a -> DiscordId a
max :: DiscordId a -> DiscordId a -> DiscordId a
$cmax :: forall a. DiscordId a -> DiscordId a -> DiscordId a
>= :: DiscordId a -> DiscordId a -> Bool
$c>= :: forall a. DiscordId a -> DiscordId a -> Bool
> :: DiscordId a -> DiscordId a -> Bool
$c> :: forall a. DiscordId a -> DiscordId a -> Bool
<= :: DiscordId a -> DiscordId a -> Bool
$c<= :: forall a. DiscordId a -> DiscordId a -> Bool
< :: DiscordId a -> DiscordId a -> Bool
$c< :: forall a. DiscordId a -> DiscordId a -> Bool
compare :: DiscordId a -> DiscordId a -> Ordering
$ccompare :: forall a. DiscordId a -> DiscordId a -> Ordering
$cp1Ord :: forall a. Eq (DiscordId a)
Ord, DiscordId a -> DiscordId a -> Bool
(DiscordId a -> DiscordId a -> Bool)
-> (DiscordId a -> DiscordId a -> Bool) -> Eq (DiscordId a)
forall a. DiscordId a -> DiscordId a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DiscordId a -> DiscordId a -> Bool
$c/= :: forall a. DiscordId a -> DiscordId a -> Bool
== :: DiscordId a -> DiscordId a -> Bool
$c== :: forall a. DiscordId a -> DiscordId a -> Bool
Eq, Integer -> DiscordId a
DiscordId a -> DiscordId a
DiscordId a -> DiscordId a -> DiscordId a
(DiscordId a -> DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a)
-> (Integer -> DiscordId a)
-> Num (DiscordId a)
forall a. Integer -> DiscordId a
forall a. DiscordId a -> DiscordId a
forall a. DiscordId a -> DiscordId a -> DiscordId a
forall a.
(a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> a)
-> (a -> a)
-> (Integer -> a)
-> Num a
fromInteger :: Integer -> DiscordId a
$cfromInteger :: forall a. Integer -> DiscordId a
signum :: DiscordId a -> DiscordId a
$csignum :: forall a. DiscordId a -> DiscordId a
abs :: DiscordId a -> DiscordId a
$cabs :: forall a. DiscordId a -> DiscordId a
negate :: DiscordId a -> DiscordId a
$cnegate :: forall a. DiscordId a -> DiscordId a
* :: DiscordId a -> DiscordId a -> DiscordId a
$c* :: forall a. DiscordId a -> DiscordId a -> DiscordId a
- :: DiscordId a -> DiscordId a -> DiscordId a
$c- :: forall a. DiscordId a -> DiscordId a -> DiscordId a
+ :: DiscordId a -> DiscordId a -> DiscordId a
$c+ :: forall a. DiscordId a -> DiscordId a -> DiscordId a
Num, Enum (DiscordId a)
Real (DiscordId a)
Real (DiscordId a)
-> Enum (DiscordId a)
-> (DiscordId a -> DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a -> (DiscordId a, DiscordId a))
-> (DiscordId a -> DiscordId a -> (DiscordId a, DiscordId a))
-> (DiscordId a -> Integer)
-> Integral (DiscordId a)
DiscordId a -> Integer
DiscordId a -> DiscordId a -> (DiscordId a, DiscordId a)
DiscordId a -> DiscordId a -> DiscordId a
forall a. Enum (DiscordId a)
forall a. Real (DiscordId a)
forall a.
Real a
-> Enum a
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> (a, a))
-> (a -> a -> (a, a))
-> (a -> Integer)
-> Integral a
forall a. DiscordId a -> Integer
forall a. DiscordId a -> DiscordId a -> (DiscordId a, DiscordId a)
forall a. DiscordId a -> DiscordId a -> DiscordId a
toInteger :: DiscordId a -> Integer
$ctoInteger :: forall a. DiscordId a -> Integer
divMod :: DiscordId a -> DiscordId a -> (DiscordId a, DiscordId a)
$cdivMod :: forall a. DiscordId a -> DiscordId a -> (DiscordId a, DiscordId a)
quotRem :: DiscordId a -> DiscordId a -> (DiscordId a, DiscordId a)
$cquotRem :: forall a. DiscordId a -> DiscordId a -> (DiscordId a, DiscordId a)
mod :: DiscordId a -> DiscordId a -> DiscordId a
$cmod :: forall a. DiscordId a -> DiscordId a -> DiscordId a
div :: DiscordId a -> DiscordId a -> DiscordId a
$cdiv :: forall a. DiscordId a -> DiscordId a -> DiscordId a
rem :: DiscordId a -> DiscordId a -> DiscordId a
$crem :: forall a. DiscordId a -> DiscordId a -> DiscordId a
quot :: DiscordId a -> DiscordId a -> DiscordId a
$cquot :: forall a. DiscordId a -> DiscordId a -> DiscordId a
$cp2Integral :: forall a. Enum (DiscordId a)
$cp1Integral :: forall a. Real (DiscordId a)
Integral, Int -> DiscordId a
DiscordId a -> Int
DiscordId a -> [DiscordId a]
DiscordId a -> DiscordId a
DiscordId a -> DiscordId a -> [DiscordId a]
DiscordId a -> DiscordId a -> DiscordId a -> [DiscordId a]
(DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a)
-> (Int -> DiscordId a)
-> (DiscordId a -> Int)
-> (DiscordId a -> [DiscordId a])
-> (DiscordId a -> DiscordId a -> [DiscordId a])
-> (DiscordId a -> DiscordId a -> [DiscordId a])
-> (DiscordId a -> DiscordId a -> DiscordId a -> [DiscordId a])
-> Enum (DiscordId a)
forall a. Int -> DiscordId a
forall a. DiscordId a -> Int
forall a. DiscordId a -> [DiscordId a]
forall a. DiscordId a -> DiscordId a
forall a. DiscordId a -> DiscordId a -> [DiscordId a]
forall a.
DiscordId a -> DiscordId a -> DiscordId a -> [DiscordId a]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: DiscordId a -> DiscordId a -> DiscordId a -> [DiscordId a]
$cenumFromThenTo :: forall a.
DiscordId a -> DiscordId a -> DiscordId a -> [DiscordId a]
enumFromTo :: DiscordId a -> DiscordId a -> [DiscordId a]
$cenumFromTo :: forall a. DiscordId a -> DiscordId a -> [DiscordId a]
enumFromThen :: DiscordId a -> DiscordId a -> [DiscordId a]
$cenumFromThen :: forall a. DiscordId a -> DiscordId a -> [DiscordId a]
enumFrom :: DiscordId a -> [DiscordId a]
$cenumFrom :: forall a. DiscordId a -> [DiscordId a]
fromEnum :: DiscordId a -> Int
$cfromEnum :: forall a. DiscordId a -> Int
toEnum :: Int -> DiscordId a
$ctoEnum :: forall a. Int -> DiscordId a
pred :: DiscordId a -> DiscordId a
$cpred :: forall a. DiscordId a -> DiscordId a
succ :: DiscordId a -> DiscordId a
$csucc :: forall a. DiscordId a -> DiscordId a
Enum, Num (DiscordId a)
Ord (DiscordId a)
Num (DiscordId a)
-> Ord (DiscordId a)
-> (DiscordId a -> Rational)
-> Real (DiscordId a)
DiscordId a -> Rational
forall a. Num (DiscordId a)
forall a. Ord (DiscordId a)
forall a. Num a -> Ord a -> (a -> Rational) -> Real a
forall a. DiscordId a -> Rational
toRational :: DiscordId a -> Rational
$ctoRational :: forall a. DiscordId a -> Rational
$cp2Real :: forall a. Ord (DiscordId a)
$cp1Real :: forall a. Num (DiscordId a)
Real, Eq (DiscordId a)
DiscordId a
Eq (DiscordId a)
-> (DiscordId a -> DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a -> DiscordId a)
-> (DiscordId a -> DiscordId a)
-> (DiscordId a -> Int -> DiscordId a)
-> (DiscordId a -> Int -> DiscordId a)
-> DiscordId a
-> (Int -> DiscordId a)
-> (DiscordId a -> Int -> DiscordId a)
-> (DiscordId a -> Int -> DiscordId a)
-> (DiscordId a -> Int -> DiscordId a)
-> (DiscordId a -> Int -> Bool)
-> (DiscordId a -> Maybe Int)
-> (DiscordId a -> Int)
-> (DiscordId a -> Bool)
-> (DiscordId a -> Int -> DiscordId a)
-> (DiscordId a -> Int -> DiscordId a)
-> (DiscordId a -> Int -> DiscordId a)
-> (DiscordId a -> Int -> DiscordId a)
-> (DiscordId a -> Int -> DiscordId a)
-> (DiscordId a -> Int -> DiscordId a)
-> (DiscordId a -> Int)
-> Bits (DiscordId a)
Int -> DiscordId a
DiscordId a -> Bool
DiscordId a -> Int
DiscordId a -> Maybe Int
DiscordId a -> DiscordId a
DiscordId a -> Int -> Bool
DiscordId a -> Int -> DiscordId a
DiscordId a -> DiscordId a -> DiscordId a
forall a. Eq (DiscordId a)
forall a. DiscordId a
forall a.
Eq a
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> a
-> (Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> Bool)
-> (a -> Maybe Int)
-> (a -> Int)
-> (a -> Bool)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int -> a)
-> (a -> Int)
-> Bits a
forall a. Int -> DiscordId a
forall a. DiscordId a -> Bool
forall a. DiscordId a -> Int
forall a. DiscordId a -> Maybe Int
forall a. DiscordId a -> DiscordId a
forall a. DiscordId a -> Int -> Bool
forall a. DiscordId a -> Int -> DiscordId a
forall a. DiscordId a -> DiscordId a -> DiscordId a
popCount :: DiscordId a -> Int
$cpopCount :: forall a. DiscordId a -> Int
rotateR :: DiscordId a -> Int -> DiscordId a
$crotateR :: forall a. DiscordId a -> Int -> DiscordId a
rotateL :: DiscordId a -> Int -> DiscordId a
$crotateL :: forall a. DiscordId a -> Int -> DiscordId a
unsafeShiftR :: DiscordId a -> Int -> DiscordId a
$cunsafeShiftR :: forall a. DiscordId a -> Int -> DiscordId a
shiftR :: DiscordId a -> Int -> DiscordId a
$cshiftR :: forall a. DiscordId a -> Int -> DiscordId a
unsafeShiftL :: DiscordId a -> Int -> DiscordId a
$cunsafeShiftL :: forall a. DiscordId a -> Int -> DiscordId a
shiftL :: DiscordId a -> Int -> DiscordId a
$cshiftL :: forall a. DiscordId a -> Int -> DiscordId a
isSigned :: DiscordId a -> Bool
$cisSigned :: forall a. DiscordId a -> Bool
bitSize :: DiscordId a -> Int
$cbitSize :: forall a. DiscordId a -> Int
bitSizeMaybe :: DiscordId a -> Maybe Int
$cbitSizeMaybe :: forall a. DiscordId a -> Maybe Int
testBit :: DiscordId a -> Int -> Bool
$ctestBit :: forall a. DiscordId a -> Int -> Bool
complementBit :: DiscordId a -> Int -> DiscordId a
$ccomplementBit :: forall a. DiscordId a -> Int -> DiscordId a
clearBit :: DiscordId a -> Int -> DiscordId a
$cclearBit :: forall a. DiscordId a -> Int -> DiscordId a
setBit :: DiscordId a -> Int -> DiscordId a
$csetBit :: forall a. DiscordId a -> Int -> DiscordId a
bit :: Int -> DiscordId a
$cbit :: forall a. Int -> DiscordId a
zeroBits :: DiscordId a
$czeroBits :: forall a. DiscordId a
rotate :: DiscordId a -> Int -> DiscordId a
$crotate :: forall a. DiscordId a -> Int -> DiscordId a
shift :: DiscordId a -> Int -> DiscordId a
$cshift :: forall a. DiscordId a -> Int -> DiscordId a
complement :: DiscordId a -> DiscordId a
$ccomplement :: forall a. DiscordId a -> DiscordId a
xor :: DiscordId a -> DiscordId a -> DiscordId a
$cxor :: forall a. DiscordId a -> DiscordId a -> DiscordId a
.|. :: DiscordId a -> DiscordId a -> DiscordId a
$c.|. :: forall a. DiscordId a -> DiscordId a -> DiscordId a
.&. :: DiscordId a -> DiscordId a -> DiscordId a
$c.&. :: forall a. DiscordId a -> DiscordId a -> DiscordId a
$cp1Bits :: forall a. Eq (DiscordId a)
Bits)

instance Show (DiscordId a) where
  show :: DiscordId a -> String
show = Snowflake -> String
forall a. Show a => a -> String
show (Snowflake -> String)
-> (DiscordId a -> Snowflake) -> DiscordId a -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DiscordId a -> Snowflake
forall a. DiscordId a -> Snowflake
unId

instance Read (DiscordId a) where
  readsPrec :: Int -> ReadS (DiscordId a)
readsPrec Int
p = ((Snowflake, String) -> (DiscordId a, String))
-> [(Snowflake, String)] -> [(DiscordId a, String)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Snowflake -> DiscordId a)
-> (Snowflake, String) -> (DiscordId a, String)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Snowflake -> DiscordId a
forall a. Snowflake -> DiscordId a
DiscordId) ([(Snowflake, String)] -> [(DiscordId a, String)])
-> ReadS Snowflake -> ReadS (DiscordId a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ReadS Snowflake
forall a. Read a => Int -> ReadS a
readsPrec Int
p

instance ToJSON (DiscordId a) where
  toJSON :: DiscordId a -> Value
toJSON = Snowflake -> Value
forall a. ToJSON a => a -> Value
toJSON (Snowflake -> Value)
-> (DiscordId a -> Snowflake) -> DiscordId a -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DiscordId a -> Snowflake
forall a. DiscordId a -> Snowflake
unId

instance FromJSON (DiscordId a) where
  parseJSON :: Value -> Parser (DiscordId a)
parseJSON = (Snowflake -> DiscordId a)
-> Parser Snowflake -> Parser (DiscordId a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Snowflake -> DiscordId a
forall a. Snowflake -> DiscordId a
DiscordId (Parser Snowflake -> Parser (DiscordId a))
-> (Value -> Parser Snowflake) -> Value -> Parser (DiscordId a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> Parser Snowflake
forall a. FromJSON a => Value -> Parser a
parseJSON

instance ToHttpApiData (DiscordId a) where
  toUrlPiece :: DiscordId a -> Text
toUrlPiece = String -> Text
T.pack (String -> Text) -> (DiscordId a -> String) -> DiscordId a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DiscordId a -> String
forall a. Show a => a -> String
show

data ChannelIdType
type ChannelId = DiscordId ChannelIdType

data StageIdType
type StageId = DiscordId StageIdType

data GuildIdType
type GuildId = DiscordId GuildIdType

data MessageIdType
type MessageId = DiscordId MessageIdType

data AttachmentIdType
type AttachmentId = DiscordId AttachmentIdType

data EmojiIdType
type EmojiId = DiscordId EmojiIdType

data StickerIdType
type StickerId = DiscordId StickerIdType

data UserIdType
type UserId = DiscordId UserIdType

data RoleIdType
type RoleId = DiscordId RoleIdType

data IntegrationIdType
type IntegrationId = DiscordId IntegrationIdType

data WebhookIdType
type WebhookId = DiscordId WebhookIdType

data ParentIdType
type ParentId = DiscordId ParentIdType

data ApplicationIdType
type ApplicationId = DiscordId ApplicationIdType

data ApplicationCommandIdType
type ApplicationCommandId = DiscordId ApplicationCommandIdType

data InteractionIdType
type InteractionId = DiscordId InteractionIdType

data ScheduledEventIdType
type ScheduledEventId = DiscordId ScheduledEventIdType

data ScheduledEventEntityIdType
type ScheduledEventEntityId = DiscordId ScheduledEventEntityIdType

newtype DiscordToken a = DiscordToken { DiscordToken a -> Text
unToken :: T.Text }
  deriving (Eq (DiscordToken a)
Eq (DiscordToken a)
-> (DiscordToken a -> DiscordToken a -> Ordering)
-> (DiscordToken a -> DiscordToken a -> Bool)
-> (DiscordToken a -> DiscordToken a -> Bool)
-> (DiscordToken a -> DiscordToken a -> Bool)
-> (DiscordToken a -> DiscordToken a -> Bool)
-> (DiscordToken a -> DiscordToken a -> DiscordToken a)
-> (DiscordToken a -> DiscordToken a -> DiscordToken a)
-> Ord (DiscordToken a)
DiscordToken a -> DiscordToken a -> Bool
DiscordToken a -> DiscordToken a -> Ordering
DiscordToken a -> DiscordToken a -> DiscordToken a
forall a. Eq (DiscordToken a)
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. DiscordToken a -> DiscordToken a -> Bool
forall a. DiscordToken a -> DiscordToken a -> Ordering
forall a. DiscordToken a -> DiscordToken a -> DiscordToken a
min :: DiscordToken a -> DiscordToken a -> DiscordToken a
$cmin :: forall a. DiscordToken a -> DiscordToken a -> DiscordToken a
max :: DiscordToken a -> DiscordToken a -> DiscordToken a
$cmax :: forall a. DiscordToken a -> DiscordToken a -> DiscordToken a
>= :: DiscordToken a -> DiscordToken a -> Bool
$c>= :: forall a. DiscordToken a -> DiscordToken a -> Bool
> :: DiscordToken a -> DiscordToken a -> Bool
$c> :: forall a. DiscordToken a -> DiscordToken a -> Bool
<= :: DiscordToken a -> DiscordToken a -> Bool
$c<= :: forall a. DiscordToken a -> DiscordToken a -> Bool
< :: DiscordToken a -> DiscordToken a -> Bool
$c< :: forall a. DiscordToken a -> DiscordToken a -> Bool
compare :: DiscordToken a -> DiscordToken a -> Ordering
$ccompare :: forall a. DiscordToken a -> DiscordToken a -> Ordering
$cp1Ord :: forall a. Eq (DiscordToken a)
Ord, DiscordToken a -> DiscordToken a -> Bool
(DiscordToken a -> DiscordToken a -> Bool)
-> (DiscordToken a -> DiscordToken a -> Bool)
-> Eq (DiscordToken a)
forall a. DiscordToken a -> DiscordToken a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DiscordToken a -> DiscordToken a -> Bool
$c/= :: forall a. DiscordToken a -> DiscordToken a -> Bool
== :: DiscordToken a -> DiscordToken a -> Bool
$c== :: forall a. DiscordToken a -> DiscordToken a -> Bool
Eq)

instance Show (DiscordToken a) where
  show :: DiscordToken a -> String
show = Text -> String
forall a. Show a => a -> String
show (Text -> String)
-> (DiscordToken a -> Text) -> DiscordToken a -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DiscordToken a -> Text
forall a. DiscordToken a -> Text
unToken

instance Read (DiscordToken a) where
  readsPrec :: Int -> ReadS (DiscordToken a)
readsPrec Int
p = ((Text, String) -> (DiscordToken a, String))
-> [(Text, String)] -> [(DiscordToken a, String)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Text -> DiscordToken a)
-> (Text, String) -> (DiscordToken a, String)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Text -> DiscordToken a
forall a. Text -> DiscordToken a
DiscordToken) ([(Text, String)] -> [(DiscordToken a, String)])
-> (String -> [(Text, String)]) -> ReadS (DiscordToken a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> String -> [(Text, String)]
forall a. Read a => Int -> ReadS a
readsPrec Int
p

instance ToJSON (DiscordToken a) where
  toJSON :: DiscordToken a -> Value
toJSON = Text -> Value
forall a. ToJSON a => a -> Value
toJSON (Text -> Value)
-> (DiscordToken a -> Text) -> DiscordToken a -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DiscordToken a -> Text
forall a. DiscordToken a -> Text
unToken

instance FromJSON (DiscordToken a) where
  parseJSON :: Value -> Parser (DiscordToken a)
parseJSON = (Text -> DiscordToken a) -> Parser Text -> Parser (DiscordToken a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> DiscordToken a
forall a. Text -> DiscordToken a
DiscordToken (Parser Text -> Parser (DiscordToken a))
-> (Value -> Parser Text) -> Value -> Parser (DiscordToken a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> Parser Text
forall a. FromJSON a => Value -> Parser a
parseJSON

instance ToHttpApiData (DiscordToken a) where
  toUrlPiece :: DiscordToken a -> Text
toUrlPiece = DiscordToken a -> Text
forall a. DiscordToken a -> Text
unToken

type InteractionToken = DiscordToken InteractionIdType

type WebhookToken = DiscordToken WebhookIdType

type Shard = (Int, Int)

-- | Gets a creation date from a snowflake.
snowflakeCreationDate :: Snowflake -> UTCTime
snowflakeCreationDate :: Snowflake -> UTCTime
snowflakeCreationDate Snowflake
x = POSIXTime -> UTCTime
posixSecondsToUTCTime (POSIXTime -> UTCTime)
-> (Snowflake -> POSIXTime) -> Snowflake -> UTCTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Snowflake -> POSIXTime
forall a b. (Real a, Fractional b) => a -> b
realToFrac
  (Snowflake -> UTCTime) -> Snowflake -> UTCTime
forall a b. (a -> b) -> a -> b
$ Snowflake
1420070400 Snowflake -> Snowflake -> Snowflake
forall a. Num a => a -> a -> a
+ Snowflake -> Snowflake -> Snowflake
forall a. Integral a => a -> a -> a
quot (Snowflake -> Int -> Snowflake
forall a. Bits a => a -> Int -> a
shiftR Snowflake
x Int
22) Snowflake
1000

-- | Default timestamp
epochTime :: UTCTime
epochTime :: UTCTime
epochTime = POSIXTime -> UTCTime
posixSecondsToUTCTime POSIXTime
0

{-

InternalDiscordEnum is a hack-y typeclass, but it's the best solution overall.
The best we can do is prevent the end-user from seeing this.

typeclass Bounded (minBound + maxBound) could replace discordTypeStartValue, but
it can't derive instances for types like DiscordColor, which have simple sum types involved.

typeclass Enum (toEnum + fromEnum) requires defining both A->Int and Int->A.
If we handle both at once (with an inline map), it's no longer typesafe.

External packages exist, but bloat our dependencies

-}
class Data a => InternalDiscordEnum a where
  discordTypeStartValue :: a
  fromDiscordType :: a -> Int
  discordTypeTable :: [(Int, a)]
  discordTypeTable =  (a -> (Int, a)) -> [a] -> [(Int, a)]
forall a b. (a -> b) -> [a] -> [b]
map (\a
d -> (a -> Int
forall a. InternalDiscordEnum a => a -> Int
fromDiscordType a
d, a
d)) (a -> [a]
forall b. Data b => b -> [b]
makeTable a
forall a. InternalDiscordEnum a => a
discordTypeStartValue)
    where
      makeTable :: Data b => b -> [b]
      makeTable :: b -> [b]
makeTable b
t = (Constr -> b) -> [Constr] -> [b]
forall a b. (a -> b) -> [a] -> [b]
map Constr -> b
forall a. Data a => Constr -> a
fromConstr (DataType -> [Constr]
dataTypeConstrs (DataType -> [Constr]) -> DataType -> [Constr]
forall a b. (a -> b) -> a -> b
$ b -> DataType
forall a. Data a => a -> DataType
dataTypeOf b
t)

  discordTypeParseJSON :: String -> Value -> Parser a
  discordTypeParseJSON String
name =
    String -> (Scientific -> Parser a) -> Value -> Parser a
forall a. String -> (Scientific -> Parser a) -> Value -> Parser a
withScientific
      String
name
      ( \Scientific
i -> do
          case Scientific -> Maybe Int
forall a a. (RealFrac a, Integral a) => a -> Maybe a
maybeInt Scientific
i Maybe Int -> (Int -> Maybe a) -> Maybe a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Int -> [(Int, a)] -> Maybe a
forall a b. Eq a => a -> [(a, b)] -> Maybe b
`lookup` [(Int, a)]
forall a. InternalDiscordEnum a => [(Int, a)]
discordTypeTable) of
            Maybe a
Nothing -> String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser a) -> String -> Parser a
forall a b. (a -> b) -> a -> b
$ String
"could not parse type: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Scientific -> String
forall a. Show a => a -> String
show Scientific
i
            Just a
d -> a -> Parser a
forall (m :: * -> *) a. Monad m => a -> m a
return a
d
      )
    where
      maybeInt :: a -> Maybe a
maybeInt a
i
        | Integer -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
round a
i) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
i = a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$ a -> a
forall a b. (RealFrac a, Integral b) => a -> b
round a
i
        | Bool
otherwise = Maybe a
forall a. Maybe a
Nothing

toMaybeJSON :: (ToJSON a) => a -> Maybe Value
toMaybeJSON :: a -> Maybe Value
toMaybeJSON = Value -> Maybe Value
forall (m :: * -> *) a. Monad m => a -> m a
return (Value -> Maybe Value) -> (a -> Value) -> a -> Maybe Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Value
forall a. ToJSON a => a -> Value
toJSON


-- | @Base64Image mime data@ represents the base64 encoding of an image (as
-- @data@), together with a tag of its mime type (@mime@).  The constructor is
-- only for Internal use, and its public export is hidden in Discord.Types.
--
-- Public creation of this datatype should be done using the relevant smart
-- constructors for Emoji, Sticker, or Avatar.
data Base64Image a = Base64Image T.Text T.Text
  deriving (Int -> Base64Image a -> ShowS
[Base64Image a] -> ShowS
Base64Image a -> String
(Int -> Base64Image a -> ShowS)
-> (Base64Image a -> String)
-> ([Base64Image a] -> ShowS)
-> Show (Base64Image a)
forall a. Int -> Base64Image a -> ShowS
forall a. [Base64Image a] -> ShowS
forall a. Base64Image a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Base64Image a] -> ShowS
$cshowList :: forall a. [Base64Image a] -> ShowS
show :: Base64Image a -> String
$cshow :: forall a. Base64Image a -> String
showsPrec :: Int -> Base64Image a -> ShowS
$cshowsPrec :: forall a. Int -> Base64Image a -> ShowS
Show, ReadPrec [Base64Image a]
ReadPrec (Base64Image a)
Int -> ReadS (Base64Image a)
ReadS [Base64Image a]
(Int -> ReadS (Base64Image a))
-> ReadS [Base64Image a]
-> ReadPrec (Base64Image a)
-> ReadPrec [Base64Image a]
-> Read (Base64Image a)
forall a. ReadPrec [Base64Image a]
forall a. ReadPrec (Base64Image a)
forall a. Int -> ReadS (Base64Image a)
forall a. ReadS [Base64Image a]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Base64Image a]
$creadListPrec :: forall a. ReadPrec [Base64Image a]
readPrec :: ReadPrec (Base64Image a)
$creadPrec :: forall a. ReadPrec (Base64Image a)
readList :: ReadS [Base64Image a]
$creadList :: forall a. ReadS [Base64Image a]
readsPrec :: Int -> ReadS (Base64Image a)
$creadsPrec :: forall a. Int -> ReadS (Base64Image a)
Read, Base64Image a -> Base64Image a -> Bool
(Base64Image a -> Base64Image a -> Bool)
-> (Base64Image a -> Base64Image a -> Bool) -> Eq (Base64Image a)
forall a. Base64Image a -> Base64Image a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Base64Image a -> Base64Image a -> Bool
$c/= :: forall a. Base64Image a -> Base64Image a -> Bool
== :: Base64Image a -> Base64Image a -> Bool
$c== :: forall a. Base64Image a -> Base64Image a -> Bool
Eq, Eq (Base64Image a)
Eq (Base64Image a)
-> (Base64Image a -> Base64Image a -> Ordering)
-> (Base64Image a -> Base64Image a -> Bool)
-> (Base64Image a -> Base64Image a -> Bool)
-> (Base64Image a -> Base64Image a -> Bool)
-> (Base64Image a -> Base64Image a -> Bool)
-> (Base64Image a -> Base64Image a -> Base64Image a)
-> (Base64Image a -> Base64Image a -> Base64Image a)
-> Ord (Base64Image a)
Base64Image a -> Base64Image a -> Bool
Base64Image a -> Base64Image a -> Ordering
Base64Image a -> Base64Image a -> Base64Image a
forall a. Eq (Base64Image a)
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Base64Image a -> Base64Image a -> Bool
forall a. Base64Image a -> Base64Image a -> Ordering
forall a. Base64Image a -> Base64Image a -> Base64Image a
min :: Base64Image a -> Base64Image a -> Base64Image a
$cmin :: forall a. Base64Image a -> Base64Image a -> Base64Image a
max :: Base64Image a -> Base64Image a -> Base64Image a
$cmax :: forall a. Base64Image a -> Base64Image a -> Base64Image a
>= :: Base64Image a -> Base64Image a -> Bool
$c>= :: forall a. Base64Image a -> Base64Image a -> Bool
> :: Base64Image a -> Base64Image a -> Bool
$c> :: forall a. Base64Image a -> Base64Image a -> Bool
<= :: Base64Image a -> Base64Image a -> Bool
$c<= :: forall a. Base64Image a -> Base64Image a -> Bool
< :: Base64Image a -> Base64Image a -> Bool
$c< :: forall a. Base64Image a -> Base64Image a -> Bool
compare :: Base64Image a -> Base64Image a -> Ordering
$ccompare :: forall a. Base64Image a -> Base64Image a -> Ordering
$cp1Ord :: forall a. Eq (Base64Image a)
Ord)

-- | The ToJSON instance for Base64Image creates a string representation of the
-- image's base-64 data, suited for using as JSON values.
--
-- The format is: @data:%MIME%;base64,%DATA%@.
instance ToJSON (Base64Image a) where
  toJSON :: Base64Image a -> Value
toJSON (Base64Image Text
mime Text
im) = Text -> Value
String (Text -> Value) -> Text -> Value
forall a b. (a -> b) -> a -> b
$ Text
"data:" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
mime Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
";base64," Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
im

-- | @getMimeType bs@ returns a possible mimetype for the given bytestring,
-- based on the first few magic bytes. It may return any of PNG/JPEG/GIF or WEBP
-- mimetypes, or Nothing if none are matched.
--
-- Reference: https://en.wikipedia.org/wiki/List_of_file_signatures
--
-- Although Discord's official documentation does not state WEBP as a supported
-- format, it has been accepted for both emojis and user avatars no problem
-- when tested manually.
--
-- /Inspired by discord.py's implementation./
getMimeType :: B.ByteString -> Maybe T.Text
getMimeType :: ByteString -> Maybe Text
getMimeType ByteString
bs
  | Int -> ByteString -> ByteString
B.take Int
8 ByteString
bs ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
"\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"
  = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"image/png"
  | Int -> ByteString -> ByteString
B.take Int
3 ByteString
bs ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
"\xff\xd8\xff" Bool -> Bool -> Bool
|| Int -> ByteString -> ByteString
B.take Int
4 (Int -> ByteString -> ByteString
B.drop Int
6 ByteString
bs) ByteString -> [ByteString] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [ByteString
"JFIF", ByteString
"Exif"]
  = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"image/jpeg"
  | Int -> ByteString -> ByteString
B.take Int
6 ByteString
bs ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
"\x47\x49\x46\x38\x37\x61" Bool -> Bool -> Bool
|| Int -> ByteString -> ByteString
B.take Int
6 ByteString
bs ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
"\x47\x49\x46\x38\x39\x61"
  = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"image/gif"
  | Int -> ByteString -> ByteString
B.take Int
4 ByteString
bs ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
"RIFF" Bool -> Bool -> Bool
&& Int -> ByteString -> ByteString
B.take Int
4 (Int -> ByteString -> ByteString
B.drop Int
8 ByteString
bs) ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
"WEBP"
  = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"image/webp"
  | Bool
otherwise = Maybe Text
forall a. Maybe a
Nothing