-- |
-- Module      :  Codec.Scale.SingletonEnum
-- Copyright   :  Aleksandr Krupenkin 2016-2021
-- License     :  Apache-2.0
--
-- Maintainer  :  mail@akru.me
-- Stability   :  experimental
-- Portability :  noportable
--
-- This type helps to encode/decode singleton Rust enums like:
-- `enum Enum { Data { some_data: u32 } }`
--

module Codec.Scale.SingletonEnum (SingletonEnum(..)) where

import           Data.Serialize.Get (getWord8)
import           Data.Serialize.Put (putWord8)

import           Codec.Scale.Class  (Decode (..), Encode (..))

-- | Haskell don't permit to make Rust-like enum type with only one element.
-- For this reason it is impossible to make generic parser for singleton enum type.
-- This type helps to parse Rust encoded singleton enums.
newtype SingletonEnum a = SingletonEnum { SingletonEnum a -> a
unSingletonEnum :: a }

instance Encode a => Encode (SingletonEnum a) where
    put :: Putter (SingletonEnum a)
put (SingletonEnum a
x) = Putter Word8
putWord8 Word8
0 PutM () -> PutM () -> PutM ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Putter a
forall a. Encode a => Putter a
put a
x

instance Decode a => Decode (SingletonEnum a) where
    get :: Get (SingletonEnum a)
get = Get Word8
getWord8 Get Word8 -> Get (SingletonEnum a) -> Get (SingletonEnum a)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> (a -> SingletonEnum a
forall a. a -> SingletonEnum a
SingletonEnum (a -> SingletonEnum a) -> Get a -> Get (SingletonEnum a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get a
forall a. Decode a => Get a
get)