1use bc_components::XID;
2use bc_envelope::prelude::*;
3use anyhow::{Error, Result};
4
5#[derive(Clone, PartialEq, Eq, Hash)]
6pub struct Receipt(Digest);
7
8pub const RECEIPT_TYPE: &str = "Receipt";
9
10impl Receipt {
11 pub fn new(user_id: XID, data: impl AsRef<[u8]>) -> Self {
12 Self(Digest::from_image_parts(&[user_id.data(), data.as_ref()]))
13 }
14}
15
16impl std::ops::Deref for Receipt {
17 type Target = Digest;
18
19 fn deref(&self) -> &Self::Target {
20 &self.0
21 }
22}
23
24impl std::fmt::Debug for Receipt {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 write!(f, "Receipt({})", hex::encode(&self.0))
27 }
28}
29
30impl From<Receipt> for Envelope {
31 fn from(receipt: Receipt) -> Self {
32 Envelope::new(CBOR::to_byte_string(receipt.0.clone()))
33 .add_type(RECEIPT_TYPE)
34 }
35}
36
37impl TryFrom<Envelope> for Receipt {
38 type Error = Error;
39
40 fn try_from(envelope: Envelope) -> Result<Self> {
41 envelope.check_type_envelope(RECEIPT_TYPE)?;
42 let bytes: ByteString = envelope.extract_subject()?;
43 let digest = Digest::from_data_ref(bytes.data())?;
44 Ok(Self(digest))
45 }
46}
47
48impl From<&Receipt> for Receipt {
49 fn from(receipt: &Receipt) -> Self {
50 receipt.clone()
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57 use hex_literal::hex;
58 use indoc::indoc;
59
60 #[test]
61 fn test_receipt() {
62 let user_id = XID::from_data_ref(hex!("3eadf5bf7a4da69f824be029d2d0ece06fcb3aca7dd85d402b661f7b48f18294")).unwrap();
63 let receipt = Receipt::new(user_id, b"data");
64 assert_eq!(format!("{:?}", receipt), "Receipt(12bd077763220d3223f6cd74f4d51103f29c7ba70b68765cd8ee13c84ee50152)");
65
66 let envelope = receipt.clone().to_envelope();
67 assert_eq!(format!("{}", envelope.ur_string()), "ur:envelope/lftpsohdcxbgryatktiacpbteycnynsnjywktlbyaxwznskgosbdiskohhtpwybwspglvwadgmoyadtpsoiogmihiaihinjojyamdwplrf");
68 #[rustfmt::skip]
69 assert_eq!(envelope.format(), indoc!{r#"
70 Bytes(32) [
71 'isA': "Receipt"
72 ]
73 "#}.trim());
74
75 let receipt_2 = Receipt::try_from(envelope).unwrap();
76 assert_eq!(receipt, receipt_2);
77 }
78}