depo_api/request/
get_shares.rs

1use std::collections::{ HashMap, HashSet };
2
3use bc_envelope::prelude::*;
4use anyhow::{ Error, Result };
5use gstp::prelude::*;
6
7use crate::{
8    receipt::Receipt,
9    GET_SHARES_FUNCTION,
10    RECEIPT_PARAM,
11    util::{ Abbrev, FlankedFunction },
12};
13
14//
15// Request
16//
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct GetShares(HashSet<Receipt>);
20
21impl GetShares {
22    pub fn new<I, T>(iterable: I) -> Self where I: IntoIterator<Item = T>, T: Clone + Into<Receipt> {
23        Self(
24            iterable
25                .into_iter()
26                .map(|item| item.clone().into())
27                .collect()
28        )
29    }
30
31    pub fn new_all_shares() -> Self {
32        Self(HashSet::new())
33    }
34
35    pub fn receipts(&self) -> &HashSet<Receipt> {
36        &self.0
37    }
38}
39
40impl From<GetShares> for Expression {
41    fn from(value: GetShares) -> Self {
42        let mut expression = Expression::new(GET_SHARES_FUNCTION);
43        for receipt in value.0.into_iter() {
44            expression = expression.with_parameter(RECEIPT_PARAM, receipt);
45        }
46        expression
47    }
48}
49
50impl TryFrom<Expression> for GetShares {
51    type Error = Error;
52
53    fn try_from(expression: Expression) -> Result<Self> {
54        let receipts = expression
55            .objects_for_parameter(RECEIPT_PARAM)
56            .into_iter()
57            .map(|parameter| parameter.try_into())
58            .collect::<Result<HashSet<Receipt>>>()?;
59        Ok(Self(receipts))
60    }
61}
62
63impl std::fmt::Display for GetShares {
64    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65        f.write_fmt(format_args!("{} {}", "getShares".flanked_function(), self.receipts().abbrev()))
66    }
67}
68
69//
70// Response
71//
72
73#[derive(Debug, Clone, PartialEq, Eq)]
74pub struct GetSharesResult(HashMap<Receipt, ByteString>);
75
76impl GetSharesResult {
77    pub fn new(receipt_to_data: HashMap<Receipt, ByteString>) -> Self {
78        Self(receipt_to_data)
79    }
80
81    pub fn receipt_to_data(&self) -> &HashMap<Receipt, ByteString> {
82        &self.0
83    }
84
85    pub fn data_for_receipt(&self, receipt: &Receipt) -> Option<&ByteString> {
86        self.0.get(receipt)
87    }
88}
89
90impl From<GetSharesResult> for Envelope {
91    fn from(value: GetSharesResult) -> Self {
92        let mut result = known_values::OK_VALUE.to_envelope();
93        for (receipt, data) in value.0 {
94            result = result.add_assertion(receipt, data);
95        }
96        result
97    }
98}
99
100impl TryFrom<Envelope> for GetSharesResult {
101    type Error = Error;
102
103    fn try_from(envelope: Envelope) -> Result<Self> {
104        let mut receipt_to_data = HashMap::new();
105        for assertion in envelope.assertions() {
106            let receipt = Receipt::try_from(assertion.try_predicate()?)?;
107            let object = assertion.try_object()?;
108            let data = ByteString::try_from(object)?;
109            receipt_to_data.insert(receipt, data);
110        }
111        Ok(Self::new(receipt_to_data))
112    }
113}
114
115impl TryFrom<SealedResponse> for GetSharesResult {
116    type Error = Error;
117
118    fn try_from(response: SealedResponse) -> Result<Self> {
119        response.result()?.clone().try_into()
120    }
121}
122
123impl std::fmt::Display for GetSharesResult {
124    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125        let abbrevable: HashMap<Receipt, ByteString> = self
126            .receipt_to_data()
127            .iter()
128            .map(|(k, v)| (k.clone(), v.clone()))
129            .collect();
130        f.write_fmt(format_args!("{} OK {}", "getShares".flanked_function(), abbrevable.abbrev()))
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use bc_components::XID;
137    use indoc::indoc;
138
139    use super::*;
140
141    fn user_id() -> XID {
142        XID::from_data_ref(
143            hex_literal::hex!("8712dfac3d0ebfa910736b2a9ee39d4b68f64222a77bcc0074f3f5f1c9216d30")
144        ).unwrap()
145    }
146
147    fn data_1() -> ByteString {
148        b"data_1".to_vec().into()
149    }
150
151    fn receipt_1() -> Receipt {
152        Receipt::new(user_id(), data_1())
153    }
154
155    fn data_2() -> ByteString {
156        b"data_2".to_vec().into()
157    }
158
159    fn receipt_2() -> Receipt {
160        Receipt::new(user_id(), data_2())
161    }
162
163    #[test]
164    fn test_request() {
165        bc_envelope::register_tags();
166
167        let receipts = vec![receipt_1(), receipt_2()];
168
169        let request = GetShares::new(receipts);
170        let expression: Expression = request.clone().into();
171        let request_envelope = expression.to_envelope();
172        // println!("{}", request_envelope.format());
173        #[rustfmt::skip]
174        assert_eq!(request_envelope.format(), indoc! {r#"
175            «"getShares"» [
176                ❰"receipt"❱: Bytes(32) [
177                    'isA': "Receipt"
178                ]
179                ❰"receipt"❱: Bytes(32) [
180                    'isA': "Receipt"
181                ]
182            ]
183        "#}.trim());
184        let decoded_expression = Expression::try_from(request_envelope).unwrap();
185        let decoded = GetShares::try_from(decoded_expression).unwrap();
186        assert_eq!(request, decoded);
187    }
188
189    #[test]
190    fn test_response() {
191        bc_envelope::register_tags();
192
193        let receipts_to_data = vec![(receipt_1(), data_1()), (receipt_2(), data_2())]
194            .into_iter()
195            .collect();
196        let response = GetSharesResult::new(receipts_to_data);
197        let response_envelope = response.to_envelope();
198        // println!("{}", response_envelope.format());
199        #[rustfmt::skip]
200        assert_eq!(response_envelope.format(), indoc! {r#"
201            'OK' [
202                Bytes(32) [
203                    'isA': "Receipt"
204                ]
205                : Bytes(6)
206                Bytes(32) [
207                    'isA': "Receipt"
208                ]
209                : Bytes(6)
210            ]
211        "#}.trim());
212        let decoded = GetSharesResult::try_from(response_envelope).unwrap();
213        assert_eq!(response, decoded);
214    }
215}