tarantool_rs/client/
call_response.rs

1use rmpv::Value;
2use serde::de::DeserializeOwned;
3
4use crate::{errors::DecodingError, utils::extract_iproto_data, Error};
5
6/// Tuple, returned from `call` and `eval` requests.
7#[derive(Clone, Debug, PartialEq)]
8pub struct CallResponse(pub(crate) rmpv::Value);
9
10impl CallResponse {
11    /// Decode first element of the tuple, dropping everything else.
12    ///
13    /// This is useful if function doesn't return an error.
14    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    /// Decode first 2 elements of the tuple, dropping everything else.
27    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        // SAFETY: this should be safe since we just checked tuple length
37        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    /// Decode first two elements of the tuple into result, where
50    /// either first element deserialized into `T` and returned as `Ok(T)`
51    /// or second element returned as `Err(Error::CallEval)`.
52    ///
53    /// If second element is `nil` or not present, first element will be returned,
54    /// otherwise second element will be returned as error.
55    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    /// Decode entire response into type.
73    ///
74    /// Note that currently every response would be a tuple, so be careful what type
75    /// you are specifying.
76    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}