segment_rs/
command.rs

1use crate::connection::{Connection, ConnectionError};
2use crate::frame::Frame;
3use bytes::Bytes;
4use std::any::type_name;
5use std::collections::HashMap;
6use std::hash::Hash;
7use std::str::{self, Utf8Error};
8use thiserror::Error;
9
10/// Used to convert a value to a Segment frame
11pub trait ToSegmentFrame {
12    /// Creates a new Segment frame from value
13    fn to_segment_frame(&self) -> Frame;
14}
15
16/// Used to create a value from a Segment frame
17pub trait FromSegmentFrame: Sized {
18    /// Creates a new value from Segment frame
19    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError>;
20}
21
22/// Specifies a Segment command
23#[derive(Debug)]
24pub struct Command {
25    args: Vec<Frame>,
26}
27
28/// Represents a command error
29#[derive(Debug, Error)]
30pub enum CommandError {
31    /// Occurs when the type returned by the server and the type requested are incompatible
32    #[error("incompatible response type: failed to convert from {0} to {1}")]
33    IncompatibleType(&'static str, &'static str),
34
35    /// Represents a utf8 conversion error
36    #[error(transparent)]
37    Utf8Error(#[from] Utf8Error),
38
39    /// Represents an error returned by the segment server
40    #[error("{0}")]
41    QueryError(String),
42
43    /// Represents a connection error
44    #[error(transparent)]
45    ConnectionError(#[from] ConnectionError),
46
47    /// Represents a frame decoding error
48    #[error("failed to decode the frame")]
49    Decode,
50}
51
52impl Command {
53    /// Creates an empty command
54    pub fn new() -> Self {
55        Command { args: Vec::new() }
56    }
57
58    /// Pushes an arg to command's arg vec
59    pub fn arg<T: ToSegmentFrame>(&mut self, arg: T) -> &mut Self {
60        self.args.push(arg.to_segment_frame());
61        self
62    }
63
64    /// Constructs a command from the args, executes it and returns the result
65    pub async fn query<T: FromSegmentFrame>(
66        self,
67        connection: &mut Connection,
68    ) -> Result<T, CommandError> {
69        let cmd = Frame::Array(self.args);
70        connection.write_frame(&cmd).await?;
71        let response = connection.read_frame().await?;
72
73        match response {
74            Frame::Error(val) => Err(CommandError::QueryError(
75                str::from_utf8(&val[..])?.to_string(),
76            )),
77            _ => T::from_segment_frame(&response),
78        }
79    }
80}
81
82impl Default for Command {
83    fn default() -> Self {
84        Self::new()
85    }
86}
87
88impl ToSegmentFrame for u8 {
89    fn to_segment_frame(&self) -> Frame {
90        Frame::Integer(*self as i64)
91    }
92}
93
94impl ToSegmentFrame for i8 {
95    fn to_segment_frame(&self) -> Frame {
96        Frame::Integer(*self as i64)
97    }
98}
99
100impl ToSegmentFrame for u16 {
101    fn to_segment_frame(&self) -> Frame {
102        Frame::Integer(*self as i64)
103    }
104}
105
106impl ToSegmentFrame for i16 {
107    fn to_segment_frame(&self) -> Frame {
108        Frame::Integer(*self as i64)
109    }
110}
111
112impl ToSegmentFrame for u32 {
113    fn to_segment_frame(&self) -> Frame {
114        Frame::Integer(*self as i64)
115    }
116}
117
118impl ToSegmentFrame for i32 {
119    fn to_segment_frame(&self) -> Frame {
120        Frame::Integer(*self as i64)
121    }
122}
123
124impl ToSegmentFrame for u64 {
125    fn to_segment_frame(&self) -> Frame {
126        Frame::Integer(*self as i64)
127    }
128}
129
130impl ToSegmentFrame for i64 {
131    fn to_segment_frame(&self) -> Frame {
132        Frame::Integer(*self as i64)
133    }
134}
135
136impl ToSegmentFrame for usize {
137    fn to_segment_frame(&self) -> Frame {
138        Frame::Integer(*self as i64)
139    }
140}
141
142impl ToSegmentFrame for isize {
143    fn to_segment_frame(&self) -> Frame {
144        Frame::Integer(*self as i64)
145    }
146}
147
148impl ToSegmentFrame for f32 {
149    fn to_segment_frame(&self) -> Frame {
150        Frame::Double(*self as f64)
151    }
152}
153
154impl ToSegmentFrame for f64 {
155    fn to_segment_frame(&self) -> Frame {
156        Frame::Double(*self as f64)
157    }
158}
159
160impl ToSegmentFrame for bool {
161    fn to_segment_frame(&self) -> Frame {
162        Frame::Boolean(*self)
163    }
164}
165
166impl ToSegmentFrame for String {
167    fn to_segment_frame(&self) -> Frame {
168        Frame::String(Bytes::from(self.clone()))
169    }
170}
171
172impl ToSegmentFrame for &str {
173    fn to_segment_frame(&self) -> Frame {
174        Frame::String(Bytes::from(self.to_string()))
175    }
176}
177
178impl ToSegmentFrame for Bytes {
179    fn to_segment_frame(&self) -> Frame {
180        Frame::String(self.clone())
181    }
182}
183
184impl<T: ToSegmentFrame> ToSegmentFrame for Option<T> {
185    fn to_segment_frame(&self) -> Frame {
186        if let Some(val) = self {
187            return T::to_segment_frame(val);
188        }
189        Frame::Null
190    }
191}
192
193impl<K: ToSegmentFrame, V: ToSegmentFrame> ToSegmentFrame for HashMap<K, V> {
194    fn to_segment_frame(&self) -> Frame {
195        let mut map = Vec::with_capacity(2 * self.len());
196        for (key, value) in self.iter() {
197            map.push(key.to_segment_frame());
198            map.push(value.to_segment_frame());
199        }
200
201        Frame::Map(map)
202    }
203}
204
205impl FromSegmentFrame for u8 {
206    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
207        match frame {
208            Frame::Integer(val) => Ok(*val as u8),
209            Frame::Double(val) => Ok(*val as u8),
210            other => Err(CommandError::IncompatibleType(
211                other.as_str(),
212                type_name::<Self>(),
213            )),
214        }
215    }
216}
217
218impl FromSegmentFrame for i8 {
219    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
220        match frame {
221            Frame::Integer(val) => Ok(*val as i8),
222            Frame::Double(val) => Ok(*val as i8),
223            other => Err(CommandError::IncompatibleType(
224                other.as_str(),
225                type_name::<Self>(),
226            )),
227        }
228    }
229}
230
231impl FromSegmentFrame for u16 {
232    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
233        match frame {
234            Frame::Integer(val) => Ok(*val as u16),
235            Frame::Double(val) => Ok(*val as u16),
236            other => Err(CommandError::IncompatibleType(
237                other.as_str(),
238                type_name::<Self>(),
239            )),
240        }
241    }
242}
243
244impl FromSegmentFrame for i16 {
245    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
246        match frame {
247            Frame::Integer(val) => Ok(*val as i16),
248            Frame::Double(val) => Ok(*val as i16),
249            other => Err(CommandError::IncompatibleType(
250                other.as_str(),
251                type_name::<Self>(),
252            )),
253        }
254    }
255}
256
257impl FromSegmentFrame for u32 {
258    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
259        match frame {
260            Frame::Integer(val) => Ok(*val as u32),
261            Frame::Double(val) => Ok(*val as u32),
262            other => Err(CommandError::IncompatibleType(
263                other.as_str(),
264                type_name::<Self>(),
265            )),
266        }
267    }
268}
269
270impl FromSegmentFrame for i32 {
271    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
272        match frame {
273            Frame::Integer(val) => Ok(*val as i32),
274            Frame::Double(val) => Ok(*val as i32),
275            other => Err(CommandError::IncompatibleType(
276                other.as_str(),
277                type_name::<Self>(),
278            )),
279        }
280    }
281}
282
283impl FromSegmentFrame for u64 {
284    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
285        match frame {
286            Frame::Integer(val) => Ok(*val as u64),
287            Frame::Double(val) => Ok(*val as u64),
288            other => Err(CommandError::IncompatibleType(
289                other.as_str(),
290                type_name::<Self>(),
291            )),
292        }
293    }
294}
295
296impl FromSegmentFrame for i64 {
297    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
298        match frame {
299            Frame::Integer(val) => Ok(*val),
300            Frame::Double(val) => Ok(*val as i64),
301            other => Err(CommandError::IncompatibleType(
302                other.as_str(),
303                type_name::<Self>(),
304            )),
305        }
306    }
307}
308
309impl FromSegmentFrame for f32 {
310    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
311        match frame {
312            Frame::Integer(val) => Ok(*val as f32),
313            Frame::Double(val) => Ok(*val as f32),
314            other => Err(CommandError::IncompatibleType(
315                other.as_str(),
316                type_name::<Self>(),
317            )),
318        }
319    }
320}
321
322impl FromSegmentFrame for f64 {
323    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
324        match frame {
325            Frame::Integer(val) => Ok(*val as f64),
326            Frame::Double(val) => Ok(*val),
327            other => Err(CommandError::IncompatibleType(
328                other.as_str(),
329                type_name::<Self>(),
330            )),
331        }
332    }
333}
334
335impl FromSegmentFrame for bool {
336    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
337        match frame {
338            Frame::Boolean(val) => Ok(*val),
339            other => Err(CommandError::IncompatibleType(
340                other.as_str(),
341                type_name::<Self>(),
342            )),
343        }
344    }
345}
346
347impl FromSegmentFrame for String {
348    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
349        match frame {
350            Frame::String(val) => Ok(str::from_utf8(&val[..])?.to_string()),
351            other => Err(CommandError::IncompatibleType(
352                other.as_str(),
353                type_name::<Self>(),
354            )),
355        }
356    }
357}
358
359impl FromSegmentFrame for Bytes {
360    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
361        match frame {
362            Frame::String(val) => Ok(val.clone()),
363            other => Err(CommandError::IncompatibleType(
364                other.as_str(),
365                type_name::<Self>(),
366            )),
367        }
368    }
369}
370
371impl<T: FromSegmentFrame> FromSegmentFrame for Option<T> {
372    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
373        match frame {
374            Frame::Null => Ok(None),
375            _ => Ok(Some(T::from_segment_frame(frame)?)),
376        }
377    }
378}
379
380impl<T: FromSegmentFrame> FromSegmentFrame for Vec<T> {
381    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
382        let mut vec = Vec::new();
383        match frame {
384            Frame::Array(array) => {
385                for v in array {
386                    vec.push(T::from_segment_frame(v)?);
387                }
388                Ok(vec)
389            }
390            other => Err(CommandError::IncompatibleType(
391                other.as_str(),
392                type_name::<Self>(),
393            )),
394        }
395    }
396}
397
398impl<K, V> FromSegmentFrame for HashMap<K, V>
399where
400    K: FromSegmentFrame + Eq + Hash,
401    V: FromSegmentFrame,
402{
403    fn from_segment_frame(frame: &Frame) -> Result<Self, CommandError> {
404        match frame {
405            Frame::Map(map) => {
406                let len = map.len();
407                if len == 0 {
408                    return Ok(HashMap::new());
409                }
410                if len % 2 != 0 {
411                    return Err(CommandError::Decode);
412                }
413                let mut result = HashMap::with_capacity(len / 2);
414                let mut idx = 0;
415
416                while idx < len - 1 {
417                    let key = K::from_segment_frame(&map[idx])?;
418                    idx += 1;
419                    let value = V::from_segment_frame(&map[idx])?;
420                    idx += 1;
421
422                    result.insert(key, value);
423                }
424
425                Ok(result)
426            }
427            other => Err(CommandError::IncompatibleType(
428                other.as_str(),
429                type_name::<Self>(),
430            )),
431        }
432    }
433}