1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use std::rc::Rc;
use bc_components::{Compressed, DigestProvider};
use dcbor::{CBOREncodable, CBORTaggedEncodable, CBORTaggedDecodable};

use crate::{Envelope, Error};

/// Support for compressing and uncompressing envelopes.
impl Envelope {
    /// Returns the compressed variant of this envelope.
    ///
    /// Returns the same envelope if it is already compressed.
    pub fn compress(self: Rc<Self>) -> Result<Rc<Self>, Error> {
        match &*self {
            Envelope::Compressed(_) => Ok(self),
            Envelope::Encrypted(_) => Err(Error::AlreadyEncrypted),
            Envelope::Elided(_) => Err(Error::AlreadyElided),
            _ => {
                let compressed = Compressed::from_uncompressed_data(self.tagged_cbor().cbor_data(), Some(self.digest().into_owned()));
                Ok(Envelope::new(compressed))
            },
        }
    }

    /// Returns the uncompressed variant of this envelope.
    ///
    /// Returns the same envelope if it is already uncompressed.
    pub fn uncompress(self: Rc<Self>) -> Result<Rc<Self>, Error> {
        if let Envelope::Compressed(compressed) = &*self {
            if let Some(digest) = compressed.digest_ref_opt() {
                if digest != self.digest().as_ref() {
                    return Err(Error::InvalidDigest);
                }
                let a = compressed.uncompress()?;
                let envelope = Rc::new(Envelope::from_tagged_cbor_data(&a)?);
                if envelope.digest().as_ref() != digest {
                    return Err(Error::InvalidDigest);
                }
                Ok(envelope)
            } else {
                Err(Error::MissingDigest)
            }
        } else {
            Err(Error::NotCompressed)
        }
    }

    /// Returns this envelope with its subject compressed.
    ///
    /// Returns the same envelope if its subject is already compressed.
    pub fn compress_subject(self: Rc<Self>) -> Result<Rc<Self>, Error> {
        if self.clone().subject().is_compressed() {
            Ok(self)
        } else {
            let subject = self.clone().subject().compress()?;
            Ok(self.replace_subject(subject))
        }
    }

    /// Returns this envelope with its subject uncompressed.
    ///
    /// Returns the same envelope if its subject is already uncompressed.
    pub fn uncompress_subject(self: Rc<Self>) -> Result<Rc<Self>, Error> {
        if self.clone().subject().is_compressed() {
            let subject = self.clone().subject().uncompress()?;
            Ok(self.replace_subject(subject))
        } else {
            Ok(self)
        }
    }
}