-- | 'WOE' is an acronym for "Write-Once Enum". This package provides the 'IsoEnum' class to allow for more convenient declaration of arbitrary-index enums. This removes the need for writing boilerplate 'toEnum'/'fromEnum' definitions if you were to implement 'Enum' directly. To expose an 'Enum' interface for your custom enum type, simply do @deriving Enum via WOE@. This requires the @DerivingVia@ extension provided by GHC 8.6.1+.
module Data.WOE(
  IsoEnum, mapping,
  WOE(..),
  toEnumSafely,
  fromEnumSafely
) where

import Data.Tuple
import Data.Maybe

class Eq a => IsoEnum a where
  mapping :: [(Int, a)]

newtype WOE a = WOE { unwrapWOE :: a }

toEnumSafely :: IsoEnum a => Int -> Maybe a
toEnumSafely n = lookup n mapping

fromEnumSafely :: IsoEnum a => a -> Maybe Int
fromEnumSafely x = lookup x $ swap <$> mapping

instance IsoEnum a => Enum (WOE a) where
  toEnum = maybe (error "Invalid enum index.") WOE . toEnumSafely
  fromEnum = maybe (error "Undefined enum index") id . fromEnumSafely . unwrapWOE