{-# LANGUAGE TypeFamilies #-}

-- |
-- Module      :  Codec.Scale.Class
-- Copyright   :  Aleksandr Krupenkin 2016-2021
-- License     :  Apache-2.0
--
-- Maintainer  :  mail@akru.me
-- Stability   :  experimental
-- Portability :  unportable
--
-- The SCALE (Simple Concatenated Aggregate Little-Endian) Codec is
-- a lightweight, efficient, binary serialization and deserialization codec.
--
-- It is designed for high-performance, copy-free encoding and decoding of data in
-- resource-constrained execution contexts, like the Substrate runtime. It is not
-- self-describing in any way and assumes the decoding context has all type
-- knowledge about the encoded data.
--

module Codec.Scale
    ( encode
    , decode
    , encode'
    , decode'
    , Encode
    , Decode
    , Generic
    , module Core
    ) where

import           Data.ByteArray    (ByteArray, ByteArrayAccess, convert)
import           Data.Serialize    (runGet, runPut)
import           Generics.SOP      (Generic, Rep, from, to)

import           Codec.Scale.Class (Decode (..), Encode (..), GDecode (..),
                                    GEncode (..))
import           Codec.Scale.Core  as Core

-- | Encode datatype to SCALE format.
encode :: (Encode a, ByteArray ba)
       => a
       -> ba
{-# INLINE encode #-}
encode :: a -> ba
encode = ByteString -> ba
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert (ByteString -> ba) -> (a -> ByteString) -> a -> ba
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPut (Put -> ByteString) -> (a -> Put) -> a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Put
forall a. Encode a => Putter a
put

-- | Generic driven version of 'encode'
encode' :: (Generic a,
            Rep a ~ rep,
            GEncode rep,
            ByteArray ba)
        => a
        -> ba
{-# INLINE encode' #-}
encode' :: a -> ba
encode' = ByteString -> ba
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert (ByteString -> ba) -> (a -> ByteString) -> a -> ba
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Put -> ByteString
runPut (Put -> ByteString) -> (a -> Put) -> a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Putter (SOP I (Code a))
forall a. GEncode a => Putter a
gPut Putter (SOP I (Code a)) -> (a -> SOP I (Code a)) -> a -> Put
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> SOP I (Code a)
forall a. Generic a => a -> Rep a
from

-- | Decode datatype from SCALE format.
decode :: (ByteArrayAccess ba, Decode a)
       => ba
       -> Either String a
{-# INLINE decode #-}
decode :: ba -> Either String a
decode = Get a -> ByteString -> Either String a
forall a. Get a -> ByteString -> Either String a
runGet Get a
forall a. Decode a => Get a
get (ByteString -> Either String a)
-> (ba -> ByteString) -> ba -> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ba -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert

-- | Generic driven version of 'decode'
decode' :: (Generic a,
            Rep a ~ rep,
            GDecode rep,
            ByteArrayAccess ba)
        => ba
        -> Either String a
{-# INLINE decode' #-}
decode' :: ba -> Either String a
decode' = Get a -> ByteString -> Either String a
forall a. Get a -> ByteString -> Either String a
runGet (SOP I (Code a) -> a
forall a. Generic a => Rep a -> a
to (SOP I (Code a) -> a) -> Get (SOP I (Code a)) -> Get a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get (SOP I (Code a))
forall a. GDecode a => Get a
gGet) (ByteString -> Either String a)
-> (ba -> ByteString) -> ba -> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ba -> ByteString
forall bin bout.
(ByteArrayAccess bin, ByteArray bout) =>
bin -> bout
convert