<commit_before>{-# LANGUAGE CPP, DeriveDataTypeable #-}

-- |
-- Module      : Data.Binary.Serialise.CBOR
-- Copyright   : (c) <NAME> 2015
-- License     : BSD3-style (see LICENSE.txt)
--
-- Maintainer  : <EMAIL>
-- Stability   : experimental
-- Portability : non-portable (GHC extensions)
--
-- This module provides functions to serialise and deserialise Haskell
-- values for storage or transmission, to and from lazy
-- @'Data.ByteString.Lazy.ByteString'@s. It also provides a type class
-- and utilities to help you make your types serialisable.
--
-- For a full tutorial on using this module, see
-- "Data.Binary.Serialise.CBOR.Tutorial".
--
module Data.Binary.Serialise.CBOR
  ( -- * High level API
    -- $highlevel
    serialise,
    deserialise,
    deserialiseOrFail,

    -- * Deserialisation exceptions
    DeserialiseFailure(..),

    -- * Primitive, incremental interface
    -- $primitives
    serialiseIncremental,
    deserialiseIncremental,

    -- * The @'Serialise'@ class
    Serialise(..),
  ) where

import           Control.Exception                (Exception(..), throw)
import           Data.Typeable                    (Typeable)

import qualified Data.Binary.Get                  as Bin
import qualified Data.ByteString.Builder          as BS
import qualified Data.ByteString.Lazy             as BS
import qualified Data.ByteString.Lazy.Internal    as BS

import           Data.Binary.Serialise.CBOR.Class
import qualified Data.Binary.Serialise.CBOR.Read  as CBOR.Read
import qualified Data.Binary.Serialise.CBOR.Write as CBOR.Write

--------------------------------------------------------------------------------

-- $primitives
-- The following API...
--

-- | Serialise a Haskell value to an external binary representation.
--
-- The output is represented as a 'BS.Builder' and is constructed incrementally.
-- The representation as a 'BS.Builder' allows efficient concatenation with
-- other data.
serialiseIncremental :: Serialise a => a -> BS.Builder
serialiseIncremental = CBOR.Write.toBuilder . encode

-- | Deserialise a Haskell value from the external binary representation.
--
-- This allows /input/ data to be provided incrementally, rather than all in one
-- go. It also gives an explicit representation of deserialisation errors.
--
-- Note that the incremental behaviour is only for the input data, not the
-- output value: the final deserialised value is constructed and returned as a
-- whole, not incrementally.
deserialiseIncremental :: Serialise a => Bin.Decoder a
deserialiseIncremental = CBOR.Read.deserialiseIncremental decode

-- $highlevel
-- The following API exposes a high level interface allowing you to quickly
-- convert between arbitrary Haskell values (which are an instance of
-- @'Serialise'@) and lazy @'BS.ByteString'@s.
--

-- | Serialise a Haskell value to an external binary representation.
--
-- The output is represented as a lazy 'BS.ByteString' and is constructed
-- incrementally.
serialise :: Serialise a => a -> BS.ByteString
serialise = BS.toLazyByteString . serialiseIncremental

-- | Deserialise a Haskell value from the external binary representation
-- (which must have been made using 'serialise' or related function).
--
-- /Throws/: @'DeserialiseFailure'@ if the given external representation is
-- invalid or does not correspond to a value of the expected type.
deserialise :: Serialise a => BS.ByteString -> a
deserialise =
    supplyAllInput deserialiseIncremental
  where
    supplyAllInput (Bin.Done _ _ x) _bs = x
    supplyAllInput (Bin.Partial k)   bs =
      case bs of
        BS.Chunk chunk bs' ->  supplyAllInput (k (Just chunk)) bs'
        BS.Empty           ->  supplyAllInput (k Nothing)      BS.Empty
    supplyAllInput (Bin.Fail _ off msg) _ =
      throw (DeserialiseFailure off msg)

-- | An exception type that may be returned (by pure functions) or
-- thrown (by IO actions) that fail to deserialise a given input.
data DeserialiseFailure =
       DeserialiseFailure Bin.ByteOffset String
  deriving (Show, Typeable)

instance Exception DeserialiseFailure where
#if MIN_VERSION_base(4,8,0)
    displayException (DeserialiseFailure off msg) =
      "Data.Binary.Serialise.CBOR: deserialising failed at offset "
           ++ show off ++ " : " ++ msg
#endif

-- | Deserialise a Haskell value from the external binary representation,
-- or get back a @'DeserialiseFailure'@.
deserialiseOrFail :: Serialise a => BS.ByteString -> Either DeserialiseFailure a
deserialiseOrFail = supplyAllInput deserialiseIncremental
  where
    supplyAllInput (Bin.Done _ _ x) _bs = Right x
    supplyAllInput (Bin.Partial k)   bs =
      case bs of
        BS.Chunk chunk bs' ->  supplyAllInput (k (Just chunk)) bs'
        BS.Empty           ->  supplyAllInput (k Nothing)      BS.Empty
    supplyAllInput (Bin.Fail _ offset msg) _ =
        Left (DeserialiseFailure offset msg)
<commit_msg>Fix up the main docs a little more<commit_after>{-# LANGUAGE CPP, DeriveDataTypeable #-}

-- |
-- Module      : Data.Binary.Serialise.CBOR
-- Copyright   : (c) <NAME> 2015
-- License     : BSD3-style (see LICENSE.txt)
--
-- Maintainer  : <EMAIL>
-- Stability   : experimental
-- Portability : non-portable (GHC extensions)
--
-- This module provides functions to serialise and deserialise Haskell
-- values for storage or transmission, to and from lazy
-- @'Data.ByteString.Lazy.ByteString'@s. It also provides a type class
-- and utilities to help you make your types serialisable.
--
-- For a full tutorial on using this module, see
-- "Data.Binary.Serialise.CBOR.Tutorial".
--
module Data.Binary.Serialise.CBOR
  ( -- * High level, one-shot API
    -- $highlevel
    serialise,
    deserialise,
    deserialiseOrFail,

    -- * Deserialisation exceptions
    DeserialiseFailure(..),

    -- * Incremental encoding interface
    -- $primitives
    serialiseIncremental,
    deserialiseIncremental,

    -- * The @'Serialise'@ class
    Serialise(..),
  ) where

import           Control.Exception                (Exception(..), throw)
import           Data.Typeable                    (Typeable)

import qualified Data.Binary.Get                  as Bin
import qualified Data.ByteString.Builder          as BS
import qualified Data.ByteString.Lazy             as BS
import qualified Data.ByteString.Lazy.Internal    as BS

import           Data.Binary.Serialise.CBOR.Class
import qualified Data.Binary.Serialise.CBOR.Read  as CBOR.Read
import qualified Data.Binary.Serialise.CBOR.Write as CBOR.Write

--------------------------------------------------------------------------------

-- $primitives
-- The following API allows you to encode or decode CBOR values incrementally,
-- which is useful for large structures that require you to stream values in
-- over time.
--

-- | Serialise a Haskell value to an external binary representation.
--
-- The output is represented as a 'BS.Builder' and is constructed incrementally.
-- The representation as a 'BS.Builder' allows efficient concatenation with
-- other data.
serialiseIncremental :: Serialise a => a -> BS.Builder
serialiseIncremental = CBOR.Write.toBuilder . encode

-- | Deserialise a Haskell value from the external binary representation.
--
-- This allows /input/ data to be provided incrementally, rather than all in one
-- go. It also gives an explicit representation of deserialisation errors.
--
-- Note that the incremental behaviour is only for the input data, not the
-- output value: the final deserialised value is constructed and returned as a
-- whole, not incrementally.
deserialiseIncremental :: Serialise a => Bin.Decoder a
deserialiseIncremental = CBOR.Read.deserialiseIncremental decode

-- $highlevel
-- The following API exposes a high level interface allowing you to quickly
-- convert between arbitrary Haskell values (which are an instance of
-- @'Serialise'@) and lazy @'BS.ByteString'@s.
--

-- | Serialise a Haskell value to an external binary representation.
--
-- The output is represented as a lazy 'BS.ByteString' and is constructed
-- incrementally.
serialise :: Serialise a => a -> BS.ByteString
serialise = BS.toLazyByteString . serialiseIncremental

-- | Deserialise a Haskell value from the external binary representation
-- (which must have been made using 'serialise' or related function).
--
-- /Throws/: @'DeserialiseFailure'@ if the given external representation is
-- invalid or does not correspond to a value of the expected type.
deserialise :: Serialise a => BS.ByteString -> a
deserialise =
    supplyAllInput deserialiseIncremental
  where
    supplyAllInput (Bin.Done _ _ x) _bs = x
    supplyAllInput (Bin.Partial k)   bs =
      case bs of
        BS.Chunk chunk bs' ->  supplyAllInput (k (Just chunk)) bs'
        BS.Empty           ->  supplyAllInput (k Nothing)      BS.Empty
    supplyAllInput (Bin.Fail _ off msg) _ =
      throw (DeserialiseFailure off msg)

-- | An exception type that may be returned (by pure functions) or
-- thrown (by IO actions) that fail to deserialise a given input.
data DeserialiseFailure =
       DeserialiseFailure Bin.ByteOffset String
  deriving (Show, Typeable)

instance Exception DeserialiseFailure where
#if MIN_VERSION_base(4,8,0)
    displayException (DeserialiseFailure off msg) =
      "Data.Binary.Serialise.CBOR: deserialising failed at offset "
           ++ show off ++ " : " ++ msg
#endif

-- | Deserialise a Haskell value from the external binary representation,
-- or get back a @'DeserialiseFailure'@.
deserialiseOrFail :: Serialise a => BS.ByteString -> Either DeserialiseFailure a
deserialiseOrFail = supplyAllInput deserialiseIncremental
  where
    supplyAllInput (Bin.Done _ _ x) _bs = Right x
    supplyAllInput (Bin.Partial k)   bs =
      case bs of
        BS.Chunk chunk bs' ->  supplyAllInput (k (Just chunk)) bs'
        BS.Empty           ->  supplyAllInput (k Nothing)      BS.Empty
    supplyAllInput (Bin.Fail _ offset msg) _ =
        Left (DeserialiseFailure offset msg)

{'fraction_non_alphanumeric': 0.10373652935844496, 'fraction_numerical': 0.001611441232752543, 'mean_word_length': 2.8698363211223694, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5082332', 'n_tokens_mistral': 2783, 'n_tokens_neox': 2707, 'n_words': 1000}