depo_api/request/
get_shares.rs1use 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#[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#[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 #[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 #[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}