tarantool_rs/client/
call_response.rs1use rmpv::Value;
2use serde::de::DeserializeOwned;
3
4use crate::{errors::DecodingError, utils::extract_iproto_data, Error};
5
6#[derive(Clone, Debug, PartialEq)]
8pub struct CallResponse(pub(crate) rmpv::Value);
9
10impl CallResponse {
11 pub fn decode_first<T>(self) -> Result<T, DecodingError>
15 where
16 T: DeserializeOwned,
17 {
18 let first = self
19 .into_data_tuple()?
20 .into_iter()
21 .next()
22 .ok_or_else(|| DecodingError::invalid_tuple_length(1, 0))?;
23 Ok(rmpv::ext::from_value(first)?)
24 }
25
26 pub fn decode_two<T1, T2>(self) -> Result<(T1, T2), DecodingError>
28 where
29 T1: DeserializeOwned,
30 T2: DeserializeOwned,
31 {
32 let mut tuple_iter = self.into_data_tuple()?.into_iter();
33 if tuple_iter.len() < 2 {
34 return Err(DecodingError::invalid_tuple_length(2, tuple_iter.len()));
35 }
36 let first = tuple_iter
38 .next()
39 .expect("tuple_iter should have length >= 2");
40 let second = tuple_iter
41 .next()
42 .expect("tuple_iter should have length >= 2");
43 Ok((
44 rmpv::ext::from_value(first)?,
45 rmpv::ext::from_value(second)?,
46 ))
47 }
48
49 pub fn decode_result<T>(self) -> Result<T, Error>
56 where
57 T: DeserializeOwned,
58 {
59 let mut tuple_iter = self.into_data_tuple()?.into_iter();
60 let first = tuple_iter
61 .next()
62 .ok_or_else(|| DecodingError::invalid_tuple_length(1, 0))?;
63 let second = tuple_iter.next();
64 match second {
65 Some(Value::Nil) | None => {
66 Ok(rmpv::ext::from_value(first).map_err(DecodingError::from)?)
67 }
68 Some(err) => Err(Error::CallEval(err)),
69 }
70 }
71
72 pub fn decode_full<T>(self) -> Result<T, DecodingError>
77 where
78 T: DeserializeOwned,
79 {
80 Ok(rmpv::ext::from_value(extract_iproto_data(self.0)?)?)
81 }
82
83 fn into_data_tuple(self) -> Result<Vec<Value>, DecodingError> {
84 match extract_iproto_data(self.0)? {
85 Value::Array(x) => Ok(x),
86 rest => Err(DecodingError::type_mismatch("array", rest.to_string())),
87 }
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use assert_matches::assert_matches;
94
95 use crate::codec::consts::keys::DATA;
96
97 use super::*;
98
99 fn build_tuple_response(data: Vec<Value>) -> Value {
100 Value::Map(vec![(DATA.into(), Value::Array(data))])
101 }
102
103 #[test]
104 fn decode_first() {
105 let resp = build_tuple_response(vec![Value::Boolean(true)]);
106 assert_matches!(CallResponse(resp).decode_first(), Ok(true));
107 }
108
109 #[test]
110 fn decode_first_err_len() {
111 let resp = build_tuple_response(vec![]);
112 assert_matches!(CallResponse(resp).decode_first::<()>(), Err(_));
113 }
114
115 #[test]
116 fn decode_first_err_wrong_type() {
117 let resp = build_tuple_response(vec![Value::Boolean(true)]);
118 assert_matches!(CallResponse(resp).decode_first::<String>(), Err(_));
119 }
120
121 #[test]
122 fn decode_two() {
123 let resp = build_tuple_response(vec![Value::Boolean(true), Value::Boolean(false)]);
124 assert_matches!(CallResponse(resp).decode_two(), Ok((true, false)));
125 }
126
127 #[test]
128 fn decode_two_err_len() {
129 let resp = build_tuple_response(vec![]);
130 assert_matches!(CallResponse(resp).decode_two::<(), ()>(), Err(_));
131
132 let resp = build_tuple_response(vec![Value::Boolean(true)]);
133 assert_matches!(CallResponse(resp).decode_two::<(), ()>(), Err(_));
134 }
135
136 #[test]
137 fn decode_result_ok() {
138 let resp = build_tuple_response(vec![Value::Boolean(true)]);
139 assert_matches!(CallResponse(resp).decode_result(), Ok(true));
140
141 let resp = build_tuple_response(vec![Value::Boolean(true), Value::Nil]);
142 assert_matches!(CallResponse(resp).decode_result(), Ok(true));
143 }
144
145 #[test]
146 fn decode_result_err_present() {
147 let resp = build_tuple_response(vec![Value::Boolean(true), Value::Boolean(false)]);
148 assert_matches!(
149 CallResponse(resp).decode_result::<bool>(),
150 Err(Error::CallEval(Value::Boolean(false)))
151 );
152 }
153
154 #[test]
155 fn decode_result_err_wrong_type() {
156 let resp = build_tuple_response(vec![Value::Boolean(true), Value::Nil]);
157 assert_matches!(CallResponse(resp).decode_result::<String>(), Err(_));
158 }
159
160 #[test]
161 fn decode_full() {
162 let resp = build_tuple_response(vec![Value::Boolean(true), Value::Boolean(false)]);
163 assert_matches!(CallResponse(resp).decode_full(), Ok((true, Some(false))));
164 }
165}