{-# LANGUAGE FlexibleInstances #-}

module HaskellWorks.Data.Network.Ip.SafeEnum
  ( SafeEnum(..)
  , boundedPred
  , boundedSucc
  ) where

import Data.Int
import Data.Maybe
import Data.Word
import HaskellWorks.Data.Network.Ip.Word128

class SafeEnum a where
  safePred :: a -> Maybe a
  safeSucc :: a -> Maybe a

instance SafeEnum Word where
  safePred :: Word -> Maybe Word
safePred = Word -> Maybe Word
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: Word -> Maybe Word
safeSucc = Word -> Maybe Word
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum Word8 where
  safePred :: Word8 -> Maybe Word8
safePred = Word8 -> Maybe Word8
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: Word8 -> Maybe Word8
safeSucc = Word8 -> Maybe Word8
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum Word16 where
  safePred :: Word16 -> Maybe Word16
safePred = Word16 -> Maybe Word16
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: Word16 -> Maybe Word16
safeSucc = Word16 -> Maybe Word16
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum Word32 where
  safePred :: Word32 -> Maybe Word32
safePred = Word32 -> Maybe Word32
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: Word32 -> Maybe Word32
safeSucc = Word32 -> Maybe Word32
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum Word64 where
  safePred :: Word64 -> Maybe Word64
safePred = Word64 -> Maybe Word64
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: Word64 -> Maybe Word64
safeSucc = Word64 -> Maybe Word64
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum Word128 where
  safePred :: Word128 -> Maybe Word128
safePred = Word128 -> Maybe Word128
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: Word128 -> Maybe Word128
safeSucc = Word128 -> Maybe Word128
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum Int where
  safePred :: Int -> Maybe Int
safePred = Int -> Maybe Int
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: Int -> Maybe Int
safeSucc = Int -> Maybe Int
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum Int8 where
  safePred :: Int8 -> Maybe Int8
safePred = Int8 -> Maybe Int8
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: Int8 -> Maybe Int8
safeSucc = Int8 -> Maybe Int8
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum Int16 where
  safePred :: Int16 -> Maybe Int16
safePred = Int16 -> Maybe Int16
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: Int16 -> Maybe Int16
safeSucc = Int16 -> Maybe Int16
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum Int32 where
  safePred :: Int32 -> Maybe Int32
safePred = Int32 -> Maybe Int32
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: Int32 -> Maybe Int32
safeSucc = Int32 -> Maybe Int32
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum Int64 where
  safePred :: Int64 -> Maybe Int64
safePred = Int64 -> Maybe Int64
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: Int64 -> Maybe Int64
safeSucc = Int64 -> Maybe Int64
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum Char where
  safePred :: Char -> Maybe Char
safePred = Char -> Maybe Char
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: Char -> Maybe Char
safeSucc = Char -> Maybe Char
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum Bool where
  safePred :: Bool -> Maybe Bool
safePred = Bool -> Maybe Bool
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: Bool -> Maybe Bool
safeSucc = Bool -> Maybe Bool
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum () where
  safePred :: () -> Maybe ()
safePred = () -> Maybe ()
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred
  safeSucc :: () -> Maybe ()
safeSucc = () -> Maybe ()
forall a. (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc

instance SafeEnum Integer where
  safePred :: Integer -> Maybe Integer
safePred = Integer -> Maybe Integer
forall a. a -> Maybe a
Just (Integer -> Maybe Integer)
-> (Integer -> Integer) -> Integer -> Maybe Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Integer
forall a. Enum a => a -> a
pred
  safeSucc :: Integer -> Maybe Integer
safeSucc = Integer -> Maybe Integer
forall a. a -> Maybe a
Just (Integer -> Maybe Integer)
-> (Integer -> Integer) -> Integer -> Maybe Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Integer
forall a. Enum a => a -> a
succ

boundedPred :: SafeEnum a => a -> a
boundedPred :: a -> a
boundedPred a
a = a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe a
a (a -> Maybe a
forall a. SafeEnum a => a -> Maybe a
safePred a
a)

boundedSucc :: SafeEnum a => a -> a
boundedSucc :: a -> a
boundedSucc a
a = a -> Maybe a -> a
forall a. a -> Maybe a -> a
fromMaybe a
a (a -> Maybe a
forall a. SafeEnum a => a -> Maybe a
safeSucc a
a)

defaultSafePred :: (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafePred :: a -> Maybe a
defaultSafePred a
v = if a
v a -> a -> Bool
forall a. Eq a => a -> a -> Bool
/= a
forall a. Bounded a => a
minBound then a -> Maybe a
forall a. a -> Maybe a
Just (a -> a
forall a. Enum a => a -> a
pred a
v) else Maybe a
forall a. Maybe a
Nothing

defaultSafeSucc :: (Bounded a, Enum a, Eq a) => a -> Maybe a
defaultSafeSucc :: a -> Maybe a
defaultSafeSucc a
v = if a
v a -> a -> Bool
forall a. Eq a => a -> a -> Bool
/= a
forall a. Bounded a => a
maxBound then a -> Maybe a
forall a. a -> Maybe a
Just (a -> a
forall a. Enum a => a -> a
succ a
v) else Maybe a
forall a. Maybe a
Nothing