-- |
-- Module      : Crypto.Store.CMS.Info
-- License     : BSD-style
-- Maintainer  : Olivier Chéron <olivier.cheron@gmail.com>
-- Stability   : experimental
-- Portability : unknown
--
-- CMS content information.
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Crypto.Store.CMS.Info
    ( ContentInfo(..)
    , getContentType
    , Encapsulates
    , isAttached
    , fromAttached
    , toAttachedCI
    , isDetached
    , fromDetached
    , toDetachedCI
    ) where

import Control.Monad.Fail (MonadFail)

import Data.ASN1.Types
import Data.ByteString (ByteString)
import Data.Functor.Identity
import Data.Maybe (isJust, isNothing)

import Crypto.Store.ASN1.Generate
import Crypto.Store.ASN1.Parse
import Crypto.Store.CMS.Authenticated
import Crypto.Store.CMS.AuthEnveloped
import Crypto.Store.CMS.Digested
import Crypto.Store.CMS.Encrypted
import Crypto.Store.CMS.Enveloped
import Crypto.Store.CMS.Signed
import Crypto.Store.CMS.Type
import Crypto.Store.CMS.Util

-- | Get the type of a content info.
getContentType :: ContentInfo -> ContentType
getContentType :: ContentInfo -> ContentType
getContentType (DataCI ByteString
_)              = ContentType
DataType
getContentType (SignedDataCI SignedData (Encap ByteString)
_)        = ContentType
SignedDataType
getContentType (EnvelopedDataCI EnvelopedData (Encap ByteString)
_)     = ContentType
EnvelopedDataType
getContentType (DigestedDataCI DigestedData (Encap ByteString)
_)      = ContentType
DigestedDataType
getContentType (EncryptedDataCI EncryptedData (Encap ByteString)
_)     = ContentType
EncryptedDataType
getContentType (AuthenticatedDataCI AuthenticatedData (Encap ByteString)
_) = ContentType
AuthenticatedDataType
getContentType (AuthEnvelopedDataCI AuthEnvelopedData (Encap ByteString)
_) = ContentType
AuthEnvelopedDataType


-- ContentInfo

-- | CMS content information.
data ContentInfo = DataCI ByteString
                   -- ^ Arbitrary octet string
                 | SignedDataCI (SignedData (Encap EncapsulatedContent))
                   -- ^ Signed content info
                 | EnvelopedDataCI (EnvelopedData (Encap EncryptedContent))
                   -- ^ Enveloped content info
                 | DigestedDataCI (DigestedData (Encap EncapsulatedContent))
                   -- ^ Content info with associated digest
                 | EncryptedDataCI (EncryptedData (Encap EncryptedContent))
                   -- ^ Encrypted content info
                 | AuthenticatedDataCI (AuthenticatedData (Encap EncapsulatedContent))
                   -- ^ Authenticatedcontent info
                 | AuthEnvelopedDataCI (AuthEnvelopedData (Encap EncryptedContent))
                   -- ^ Authenticated-enveloped content info
                 deriving (Int -> ContentInfo -> ShowS
[ContentInfo] -> ShowS
ContentInfo -> String
(Int -> ContentInfo -> ShowS)
-> (ContentInfo -> String)
-> ([ContentInfo] -> ShowS)
-> Show ContentInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ContentInfo -> ShowS
showsPrec :: Int -> ContentInfo -> ShowS
$cshow :: ContentInfo -> String
show :: ContentInfo -> String
$cshowList :: [ContentInfo] -> ShowS
showList :: [ContentInfo] -> ShowS
Show,ContentInfo -> ContentInfo -> Bool
(ContentInfo -> ContentInfo -> Bool)
-> (ContentInfo -> ContentInfo -> Bool) -> Eq ContentInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ContentInfo -> ContentInfo -> Bool
== :: ContentInfo -> ContentInfo -> Bool
$c/= :: ContentInfo -> ContentInfo -> Bool
/= :: ContentInfo -> ContentInfo -> Bool
Eq)

instance ProduceASN1Object ASN1P ContentInfo where
    asn1s :: ContentInfo -> ASN1Stream ASN1P
asn1s ContentInfo
ci = ASN1ConstructionType -> ASN1Stream ASN1P -> ASN1Stream ASN1P
forall e.
ASN1Elem e =>
ASN1ConstructionType -> ASN1Stream e -> ASN1Stream e
asn1Container ASN1ConstructionType
Sequence (ASN1Stream ASN1P
oid ASN1Stream ASN1P -> ASN1Stream ASN1P -> ASN1Stream ASN1P
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ASN1Stream ASN1P
cont)
      where oid :: ASN1Stream ASN1P
oid = OID -> ASN1Stream ASN1P
forall e. ASN1Elem e => OID -> ASN1Stream e
gOID (OID -> ASN1Stream ASN1P) -> OID -> ASN1Stream ASN1P
forall a b. (a -> b) -> a -> b
$ ContentType -> OID
forall a. OIDable a => a -> OID
getObjectID (ContentType -> OID) -> ContentType -> OID
forall a b. (a -> b) -> a -> b
$ ContentInfo -> ContentType
getContentType ContentInfo
ci
            cont :: ASN1Stream ASN1P
cont = ASN1ConstructionType -> ASN1Stream ASN1P -> ASN1Stream ASN1P
forall e.
ASN1Elem e =>
ASN1ConstructionType -> ASN1Stream e -> ASN1Stream e
asn1Container (ASN1Class -> Int -> ASN1ConstructionType
Container ASN1Class
Context Int
0) ASN1Stream ASN1P
inner
            inner :: ASN1Stream ASN1P
inner =
                case ContentInfo
ci of
                    DataCI ByteString
bs              -> ByteString -> ASN1Stream ASN1P
forall e. ASN1Elem e => ByteString -> ASN1Stream e
dataASN1S ByteString
bs
                    SignedDataCI SignedData (Encap ByteString)
ed        -> SignedData (Encap ByteString) -> ASN1Stream ASN1P
forall e obj. ProduceASN1Object e obj => obj -> ASN1Stream e
asn1s SignedData (Encap ByteString)
ed
                    EnvelopedDataCI EnvelopedData (Encap ByteString)
ed     -> EnvelopedData (Encap ByteString) -> ASN1Stream ASN1P
forall e obj. ProduceASN1Object e obj => obj -> ASN1Stream e
asn1s EnvelopedData (Encap ByteString)
ed
                    DigestedDataCI DigestedData (Encap ByteString)
dd      -> DigestedData (Encap ByteString) -> ASN1Stream ASN1P
forall e obj. ProduceASN1Object e obj => obj -> ASN1Stream e
asn1s DigestedData (Encap ByteString)
dd
                    EncryptedDataCI EncryptedData (Encap ByteString)
ed     -> EncryptedData (Encap ByteString) -> ASN1Stream ASN1P
forall e obj. ProduceASN1Object e obj => obj -> ASN1Stream e
asn1s EncryptedData (Encap ByteString)
ed
                    AuthenticatedDataCI AuthenticatedData (Encap ByteString)
ad -> AuthenticatedData (Encap ByteString) -> ASN1Stream ASN1P
forall e obj. ProduceASN1Object e obj => obj -> ASN1Stream e
asn1s AuthenticatedData (Encap ByteString)
ad
                    AuthEnvelopedDataCI AuthEnvelopedData (Encap ByteString)
ae -> AuthEnvelopedData (Encap ByteString) -> ASN1Stream ASN1P
forall e obj. ProduceASN1Object e obj => obj -> ASN1Stream e
asn1s AuthEnvelopedData (Encap ByteString)
ae

instance ParseASN1Object [ASN1Event] ContentInfo where
    parse :: ParseASN1 [ASN1Event] ContentInfo
parse =
        ASN1ConstructionType
-> ParseASN1 [ASN1Event] ContentInfo
-> ParseASN1 [ASN1Event] ContentInfo
forall e a.
Monoid e =>
ASN1ConstructionType -> ParseASN1 e a -> ParseASN1 e a
onNextContainer ASN1ConstructionType
Sequence (ParseASN1 [ASN1Event] ContentInfo
 -> ParseASN1 [ASN1Event] ContentInfo)
-> ParseASN1 [ASN1Event] ContentInfo
-> ParseASN1 [ASN1Event] ContentInfo
forall a b. (a -> b) -> a -> b
$ do
            OID OID
oid <- ParseASN1 [ASN1Event] ASN1
forall e. Monoid e => ParseASN1 e ASN1
getNext
            String
-> OID
-> (ContentType -> ParseASN1 [ASN1Event] ContentInfo)
-> ParseASN1 [ASN1Event] ContentInfo
forall a e b.
OIDNameable a =>
String -> OID -> (a -> ParseASN1 e b) -> ParseASN1 e b
withObjectID String
"content type" OID
oid ((ContentType -> ParseASN1 [ASN1Event] ContentInfo)
 -> ParseASN1 [ASN1Event] ContentInfo)
-> (ContentType -> ParseASN1 [ASN1Event] ContentInfo)
-> ParseASN1 [ASN1Event] ContentInfo
forall a b. (a -> b) -> a -> b
$ \ContentType
ct ->
                ASN1ConstructionType
-> ParseASN1 [ASN1Event] ContentInfo
-> ParseASN1 [ASN1Event] ContentInfo
forall e a.
Monoid e =>
ASN1ConstructionType -> ParseASN1 e a -> ParseASN1 e a
onNextContainer (ASN1Class -> Int -> ASN1ConstructionType
Container ASN1Class
Context Int
0) (ContentType -> ParseASN1 [ASN1Event] ContentInfo
forall {e}.
(ParseASN1Object e (SignedData (Encap ByteString)),
 ParseASN1Object e (EnvelopedData (Encap ByteString)),
 ParseASN1Object e (AuthenticatedData (Encap ByteString)),
 ParseASN1Object e (AuthEnvelopedData (Encap ByteString))) =>
ContentType -> ParseASN1 e ContentInfo
parseInner ContentType
ct)
      where
        parseInner :: ContentType -> ParseASN1 e ContentInfo
parseInner ContentType
DataType              = ByteString -> ContentInfo
DataCI (ByteString -> ContentInfo)
-> ParseASN1 e ByteString -> ParseASN1 e ContentInfo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParseASN1 e ByteString
forall e. Monoid e => ParseASN1 e ByteString
parseData
        parseInner ContentType
SignedDataType        = SignedData (Encap ByteString) -> ContentInfo
SignedDataCI (SignedData (Encap ByteString) -> ContentInfo)
-> ParseASN1 e (SignedData (Encap ByteString))
-> ParseASN1 e ContentInfo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParseASN1 e (SignedData (Encap ByteString))
forall e obj. ParseASN1Object e obj => ParseASN1 e obj
parse
        parseInner ContentType
EnvelopedDataType     = EnvelopedData (Encap ByteString) -> ContentInfo
EnvelopedDataCI (EnvelopedData (Encap ByteString) -> ContentInfo)
-> ParseASN1 e (EnvelopedData (Encap ByteString))
-> ParseASN1 e ContentInfo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParseASN1 e (EnvelopedData (Encap ByteString))
forall e obj. ParseASN1Object e obj => ParseASN1 e obj
parse
        parseInner ContentType
DigestedDataType      = DigestedData (Encap ByteString) -> ContentInfo
DigestedDataCI (DigestedData (Encap ByteString) -> ContentInfo)
-> ParseASN1 e (DigestedData (Encap ByteString))
-> ParseASN1 e ContentInfo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParseASN1 e (DigestedData (Encap ByteString))
forall e obj. ParseASN1Object e obj => ParseASN1 e obj
parse
        parseInner ContentType
EncryptedDataType     = EncryptedData (Encap ByteString) -> ContentInfo
EncryptedDataCI (EncryptedData (Encap ByteString) -> ContentInfo)
-> ParseASN1 e (EncryptedData (Encap ByteString))
-> ParseASN1 e ContentInfo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParseASN1 e (EncryptedData (Encap ByteString))
forall e obj. ParseASN1Object e obj => ParseASN1 e obj
parse
        parseInner ContentType
AuthenticatedDataType = AuthenticatedData (Encap ByteString) -> ContentInfo
AuthenticatedDataCI (AuthenticatedData (Encap ByteString) -> ContentInfo)
-> ParseASN1 e (AuthenticatedData (Encap ByteString))
-> ParseASN1 e ContentInfo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParseASN1 e (AuthenticatedData (Encap ByteString))
forall e obj. ParseASN1Object e obj => ParseASN1 e obj
parse
        parseInner ContentType
AuthEnvelopedDataType = AuthEnvelopedData (Encap ByteString) -> ContentInfo
AuthEnvelopedDataCI (AuthEnvelopedData (Encap ByteString) -> ContentInfo)
-> ParseASN1 e (AuthEnvelopedData (Encap ByteString))
-> ParseASN1 e ContentInfo
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ParseASN1 e (AuthEnvelopedData (Encap ByteString))
forall e obj. ParseASN1Object e obj => ParseASN1 e obj
parse


-- Data

dataASN1S :: ASN1Elem e => ByteString -> ASN1Stream e
dataASN1S :: forall e. ASN1Elem e => ByteString -> ASN1Stream e
dataASN1S = ByteString -> ASN1Stream e
forall e. ASN1Elem e => ByteString -> ASN1Stream e
gOctetString

parseData :: Monoid e => ParseASN1 e ByteString
parseData :: forall e. Monoid e => ParseASN1 e ByteString
parseData = ParseASN1 e ByteString
forall e. Monoid e => ParseASN1 e ByteString
parseOctetString

-- Encapsulation

-- | Class of data structures with inner content that may be stored externally.
-- This class has instances for each CMS content type containing other
-- encapsulated or encrypted content info.
--
-- Functions 'fromAttached' and 'fromDetached' are used to introspect
-- encapsulation state (attached or detached), and recover a data structure with
-- actionable content.
--
-- Functions 'toAttachedCI' and 'toDetachedCI' are needed to decide about the
-- outer encapsulation state and build a 'ContentInfo'.
class Encapsulates struct where
    lens :: Functor f => (a -> f b) -> struct a -> f (struct b)
    toCI :: struct (Encap ByteString) -> ContentInfo

instance Encapsulates SignedData where
    lens :: forall (f :: * -> *) a b.
Functor f =>
(a -> f b) -> SignedData a -> f (SignedData b)
lens a -> f b
f SignedData a
s = let g :: content -> SignedData content
g content
a = SignedData a
s { sdEncapsulatedContent = a }
                in (b -> SignedData b) -> f b -> f (SignedData b)
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap b -> SignedData b
forall {content}. content -> SignedData content
g (a -> f b
f (a -> f b) -> a -> f b
forall a b. (a -> b) -> a -> b
$ SignedData a -> a
forall content. SignedData content -> content
sdEncapsulatedContent SignedData a
s)
    toCI :: SignedData (Encap ByteString) -> ContentInfo
toCI = SignedData (Encap ByteString) -> ContentInfo
SignedDataCI

instance Encapsulates EnvelopedData where
    lens :: forall (f :: * -> *) a b.
Functor f =>
(a -> f b) -> EnvelopedData a -> f (EnvelopedData b)
lens a -> f b
f EnvelopedData a
s = let g :: content -> EnvelopedData content
g content
a = EnvelopedData a
s { evEncryptedContent = a }
                in (b -> EnvelopedData b) -> f b -> f (EnvelopedData b)
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap b -> EnvelopedData b
forall {content}. content -> EnvelopedData content
g (a -> f b
f (a -> f b) -> a -> f b
forall a b. (a -> b) -> a -> b
$ EnvelopedData a -> a
forall content. EnvelopedData content -> content
evEncryptedContent EnvelopedData a
s)
    toCI :: EnvelopedData (Encap ByteString) -> ContentInfo
toCI = EnvelopedData (Encap ByteString) -> ContentInfo
EnvelopedDataCI

instance Encapsulates DigestedData where
    lens :: forall (f :: * -> *) a b.
Functor f =>
(a -> f b) -> DigestedData a -> f (DigestedData b)
lens a -> f b
f DigestedData a
s = let g :: content -> DigestedData content
g content
a = DigestedData a
s { ddEncapsulatedContent = a }
                in (b -> DigestedData b) -> f b -> f (DigestedData b)
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap b -> DigestedData b
forall {content}. content -> DigestedData content
g (a -> f b
f (a -> f b) -> a -> f b
forall a b. (a -> b) -> a -> b
$ DigestedData a -> a
forall content. DigestedData content -> content
ddEncapsulatedContent DigestedData a
s)
    toCI :: DigestedData (Encap ByteString) -> ContentInfo
toCI = DigestedData (Encap ByteString) -> ContentInfo
DigestedDataCI

instance Encapsulates EncryptedData where
    lens :: forall (f :: * -> *) a b.
Functor f =>
(a -> f b) -> EncryptedData a -> f (EncryptedData b)
lens a -> f b
f EncryptedData a
s = let g :: content -> EncryptedData content
g content
a = EncryptedData a
s { edEncryptedContent = a }
                in (b -> EncryptedData b) -> f b -> f (EncryptedData b)
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap b -> EncryptedData b
forall {content}. content -> EncryptedData content
g (a -> f b
f (a -> f b) -> a -> f b
forall a b. (a -> b) -> a -> b
$ EncryptedData a -> a
forall content. EncryptedData content -> content
edEncryptedContent EncryptedData a
s)
    toCI :: EncryptedData (Encap ByteString) -> ContentInfo
toCI = EncryptedData (Encap ByteString) -> ContentInfo
EncryptedDataCI

instance Encapsulates AuthenticatedData where
    lens :: forall (f :: * -> *) a b.
Functor f =>
(a -> f b) -> AuthenticatedData a -> f (AuthenticatedData b)
lens a -> f b
f AuthenticatedData a
s = let g :: content -> AuthenticatedData content
g content
a = AuthenticatedData a
s { adEncapsulatedContent = a }
                in (b -> AuthenticatedData b) -> f b -> f (AuthenticatedData b)
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap b -> AuthenticatedData b
forall {content}. content -> AuthenticatedData content
g (a -> f b
f (a -> f b) -> a -> f b
forall a b. (a -> b) -> a -> b
$ AuthenticatedData a -> a
forall content. AuthenticatedData content -> content
adEncapsulatedContent AuthenticatedData a
s)
    toCI :: AuthenticatedData (Encap ByteString) -> ContentInfo
toCI = AuthenticatedData (Encap ByteString) -> ContentInfo
AuthenticatedDataCI

instance Encapsulates AuthEnvelopedData where
    lens :: forall (f :: * -> *) a b.
Functor f =>
(a -> f b) -> AuthEnvelopedData a -> f (AuthEnvelopedData b)
lens a -> f b
f AuthEnvelopedData a
s = let g :: content -> AuthEnvelopedData content
g content
a = AuthEnvelopedData a
s { aeEncryptedContent = a }
                in (b -> AuthEnvelopedData b) -> f b -> f (AuthEnvelopedData b)
forall a b. (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap b -> AuthEnvelopedData b
forall {content}. content -> AuthEnvelopedData content
g (a -> f b
f (a -> f b) -> a -> f b
forall a b. (a -> b) -> a -> b
$ AuthEnvelopedData a -> a
forall content. AuthEnvelopedData content -> content
aeEncryptedContent AuthEnvelopedData a
s)
    toCI :: AuthEnvelopedData (Encap ByteString) -> ContentInfo
toCI = AuthEnvelopedData (Encap ByteString) -> ContentInfo
AuthEnvelopedDataCI

-- | Return 'True' when the encapsulated content is attached.
isAttached :: Encapsulates struct => struct (Encap a) -> Bool
isAttached :: forall (struct :: * -> *) a.
Encapsulates struct =>
struct (Encap a) -> Bool
isAttached = Maybe (struct a) -> Bool
forall a. Maybe a -> Bool
isJust (Maybe (struct a) -> Bool)
-> (struct (Encap a) -> Maybe (struct a))
-> struct (Encap a)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. struct (Encap a) -> Maybe (struct a)
forall (m :: * -> *) (struct :: * -> *) a.
(MonadFail m, Encapsulates struct) =>
struct (Encap a) -> m (struct a)
fromAttached

-- | Unwrap the encapsulation, assuming the inner content is inside the data
-- structure.  The monadic computation fails if the content was detached.
fromAttached :: (MonadFail m, Encapsulates struct) => struct (Encap a) -> m (struct a)
fromAttached :: forall (m :: * -> *) (struct :: * -> *) a.
(MonadFail m, Encapsulates struct) =>
struct (Encap a) -> m (struct a)
fromAttached = (Encap a -> m a) -> struct (Encap a) -> m (struct a)
forall (struct :: * -> *) (f :: * -> *) a b.
(Encapsulates struct, Functor f) =>
(a -> f b) -> struct a -> f (struct b)
forall (f :: * -> *) a b.
Functor f =>
(a -> f b) -> struct a -> f (struct b)
lens (m a -> (a -> m a) -> Encap a -> m a
forall b a. b -> (a -> b) -> Encap a -> b
fromEncap m a
forall {a}. m a
err a -> m a
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return)
  where err :: m a
err = String -> m a
forall a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"fromAttached: detached"

-- | Keep the content inside the data structure.
toAttached :: Encapsulates struct => struct a -> struct (Encap a)
toAttached :: forall (struct :: * -> *) a.
Encapsulates struct =>
struct a -> struct (Encap a)
toAttached = Identity (struct (Encap a)) -> struct (Encap a)
forall a. Identity a -> a
runIdentity (Identity (struct (Encap a)) -> struct (Encap a))
-> (struct a -> Identity (struct (Encap a)))
-> struct a
-> struct (Encap a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Identity (Encap a))
-> struct a -> Identity (struct (Encap a))
forall (struct :: * -> *) (f :: * -> *) a b.
(Encapsulates struct, Functor f) =>
(a -> f b) -> struct a -> f (struct b)
forall (f :: * -> *) a b.
Functor f =>
(a -> f b) -> struct a -> f (struct b)
lens (Encap a -> Identity (Encap a)
forall a. a -> Identity a
Identity (Encap a -> Identity (Encap a))
-> (a -> Encap a) -> a -> Identity (Encap a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Encap a
forall a. a -> Encap a
Attached)

-- | Transform the data structure into a content info, keeping the encapsulated
-- content attached.  May be applied to structures with 'EncapsulatedContent' or
-- 'EncryptedContent'.
toAttachedCI :: Encapsulates struct => struct ByteString -> ContentInfo
toAttachedCI :: forall (struct :: * -> *).
Encapsulates struct =>
struct ByteString -> ContentInfo
toAttachedCI = struct (Encap ByteString) -> ContentInfo
forall (struct :: * -> *).
Encapsulates struct =>
struct (Encap ByteString) -> ContentInfo
toCI (struct (Encap ByteString) -> ContentInfo)
-> (struct ByteString -> struct (Encap ByteString))
-> struct ByteString
-> ContentInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. struct ByteString -> struct (Encap ByteString)
forall (struct :: * -> *) a.
Encapsulates struct =>
struct a -> struct (Encap a)
toAttached

-- | Return 'True' when the encapsulated content is detached.
isDetached :: Encapsulates struct => struct (Encap a) -> Bool
isDetached :: forall (struct :: * -> *) a.
Encapsulates struct =>
struct (Encap a) -> Bool
isDetached = Maybe (struct a) -> Bool
forall a. Maybe a -> Bool
isNothing (Maybe (struct a) -> Bool)
-> (struct (Encap a) -> Maybe (struct a))
-> struct (Encap a)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. struct (Encap a) -> Maybe (struct a)
forall (m :: * -> *) (struct :: * -> *) a.
(MonadFail m, Encapsulates struct) =>
struct (Encap a) -> m (struct a)
fromAttached

-- | Recover the original data structure from a detached encapsulation and the
-- external content.  The monadic computation fails if the content was attached.
fromDetached :: (MonadFail m, Encapsulates struct) => b -> struct (Encap a) -> m (struct b)
fromDetached :: forall (m :: * -> *) (struct :: * -> *) b a.
(MonadFail m, Encapsulates struct) =>
b -> struct (Encap a) -> m (struct b)
fromDetached b
c = (Encap a -> m b) -> struct (Encap a) -> m (struct b)
forall (struct :: * -> *) (f :: * -> *) a b.
(Encapsulates struct, Functor f) =>
(a -> f b) -> struct a -> f (struct b)
forall (f :: * -> *) a b.
Functor f =>
(a -> f b) -> struct a -> f (struct b)
lens (m b -> (a -> m b) -> Encap a -> m b
forall b a. b -> (a -> b) -> Encap a -> b
fromEncap (b -> m b
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return b
c) a -> m b
forall {m :: * -> *} {p} {a}. MonadFail m => p -> m a
err)
  where err :: p -> m a
err p
_ = String -> m a
forall a. String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"fromDetached: attached"

-- | Remove the content from the data structure to store it externally.
toDetached :: Encapsulates struct => struct a -> (a, struct (Encap a))
toDetached :: forall (struct :: * -> *) a.
Encapsulates struct =>
struct a -> (a, struct (Encap a))
toDetached = let f :: a -> (a, Encap a)
f a
a = (a
a, Encap a
forall a. Encap a
Detached) in (a -> (a, Encap a)) -> struct a -> (a, struct (Encap a))
forall (struct :: * -> *) (f :: * -> *) a b.
(Encapsulates struct, Functor f) =>
(a -> f b) -> struct a -> f (struct b)
forall (f :: * -> *) a b.
Functor f =>
(a -> f b) -> struct a -> f (struct b)
lens a -> (a, Encap a)
forall {a} {a}. a -> (a, Encap a)
f

-- | Transform the data structure into a content info, detaching the
-- encapsulated content.  May be applied to structures with
-- 'EncapsulatedContent' or 'EncryptedContent'.
toDetachedCI :: Encapsulates struct => struct ByteString -> (ByteString, ContentInfo)
toDetachedCI :: forall (struct :: * -> *).
Encapsulates struct =>
struct ByteString -> (ByteString, ContentInfo)
toDetachedCI = (struct (Encap ByteString) -> ContentInfo)
-> (ByteString, struct (Encap ByteString))
-> (ByteString, ContentInfo)
forall a b. (a -> b) -> (ByteString, a) -> (ByteString, b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap struct (Encap ByteString) -> ContentInfo
forall (struct :: * -> *).
Encapsulates struct =>
struct (Encap ByteString) -> ContentInfo
toCI ((ByteString, struct (Encap ByteString))
 -> (ByteString, ContentInfo))
-> (struct ByteString -> (ByteString, struct (Encap ByteString)))
-> struct ByteString
-> (ByteString, ContentInfo)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. struct ByteString -> (ByteString, struct (Encap ByteString))
forall (struct :: * -> *) a.
Encapsulates struct =>
struct a -> (a, struct (Encap a))
toDetached