    -- |
    -- 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