blob: b230d636388b15da98060d7ccaac91127acaf366 [file] [log] [blame]
Allen George8b96bfb2016-11-02 08:01:08 -04001// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Types used to send and receive primitives between a Thrift client and server.
19//!
20//! # Examples
21//!
22//! Create and use a `TOutputProtocol`.
23//!
24//! ```no_run
25//! use std::cell::RefCell;
26//! use std::rc::Rc;
27//! use thrift::protocol::{TBinaryOutputProtocol, TFieldIdentifier, TOutputProtocol, TType};
28//! use thrift::transport::{TTcpTransport, TTransport};
29//!
30//! // create the I/O channel
31//! let mut transport = TTcpTransport::new();
32//! transport.open("127.0.0.1:9090").unwrap();
33//! let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
34//!
35//! // create the protocol to encode types into bytes
36//! let mut o_prot = TBinaryOutputProtocol::new(transport.clone(), true);
37//!
38//! // write types
39//! o_prot.write_field_begin(&TFieldIdentifier::new("string_thing", TType::String, 1)).unwrap();
40//! o_prot.write_string("foo").unwrap();
41//! o_prot.write_field_end().unwrap();
42//! ```
43//!
44//! Create and use a `TInputProtocol`.
45//!
46//! ```no_run
47//! use std::cell::RefCell;
48//! use std::rc::Rc;
49//! use thrift::protocol::{TBinaryInputProtocol, TInputProtocol};
50//! use thrift::transport::{TTcpTransport, TTransport};
51//!
52//! // create the I/O channel
53//! let mut transport = TTcpTransport::new();
54//! transport.open("127.0.0.1:9090").unwrap();
55//! let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
56//!
57//! // create the protocol to decode bytes into types
58//! let mut i_prot = TBinaryInputProtocol::new(transport.clone(), true);
59//!
60//! // read types from the wire
61//! let field_identifier = i_prot.read_field_begin().unwrap();
62//! let field_contents = i_prot.read_string().unwrap();
63//! let field_end = i_prot.read_field_end().unwrap();
64//! ```
65
66use std::cell::RefCell;
67use std::fmt;
68use std::fmt::{Display, Formatter};
69use std::convert::From;
70use std::rc::Rc;
71use try_from::TryFrom;
72
73use ::{ProtocolError, ProtocolErrorKind};
74use ::transport::TTransport;
75
76mod binary;
77mod compact;
78mod multiplexed;
79mod stored;
80
81pub use self::binary::{TBinaryInputProtocol, TBinaryInputProtocolFactory, TBinaryOutputProtocol,
82 TBinaryOutputProtocolFactory};
83pub use self::compact::{TCompactInputProtocol, TCompactInputProtocolFactory,
84 TCompactOutputProtocol, TCompactOutputProtocolFactory};
85pub use self::multiplexed::TMultiplexedOutputProtocol;
86pub use self::stored::TStoredInputProtocol;
87
88// Default maximum depth to which `TInputProtocol::skip` will skip a Thrift
89// field. A default is necessary because Thrift structs or collections may
90// contain nested structs and collections, which could result in indefinite
91// recursion.
92const MAXIMUM_SKIP_DEPTH: i8 = 64;
93
94/// Converts a stream of bytes into Thrift identifiers, primitives,
95/// containers, or structs.
96///
97/// This trait does not deal with higher-level Thrift concepts like structs or
98/// exceptions - only with primitives and message or container boundaries. Once
99/// bytes are read they are deserialized and an identifier (for example
100/// `TMessageIdentifier`) or a primitive is returned.
101///
102/// All methods return a `thrift::Result`. If an `Err` is returned the protocol
103/// instance and its underlying transport should be terminated.
104///
105/// # Examples
106///
107/// Create and use a `TInputProtocol`
108///
109/// ```no_run
110/// use std::cell::RefCell;
111/// use std::rc::Rc;
112/// use thrift::protocol::{TBinaryInputProtocol, TInputProtocol};
113/// use thrift::transport::{TTcpTransport, TTransport};
114///
115/// let mut transport = TTcpTransport::new();
116/// transport.open("127.0.0.1:9090").unwrap();
117/// let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
118///
119/// let mut i_prot = TBinaryInputProtocol::new(transport.clone(), true);
120///
121/// let field_identifier = i_prot.read_field_begin().unwrap();
122/// let field_contents = i_prot.read_string().unwrap();
123/// let field_end = i_prot.read_field_end().unwrap();
124/// ```
125pub trait TInputProtocol {
126 /// Read the beginning of a Thrift message.
127 fn read_message_begin(&mut self) -> ::Result<TMessageIdentifier>;
128 /// Read the end of a Thrift message.
129 fn read_message_end(&mut self) -> ::Result<()>;
130 /// Read the beginning of a Thrift struct.
131 fn read_struct_begin(&mut self) -> ::Result<Option<TStructIdentifier>>;
132 /// Read the end of a Thrift struct.
133 fn read_struct_end(&mut self) -> ::Result<()>;
134 /// Read the beginning of a Thrift struct field.
135 fn read_field_begin(&mut self) -> ::Result<TFieldIdentifier>;
136 /// Read the end of a Thrift struct field.
137 fn read_field_end(&mut self) -> ::Result<()>;
138 /// Read a bool.
139 fn read_bool(&mut self) -> ::Result<bool>;
140 /// Read a fixed-length byte array.
141 fn read_bytes(&mut self) -> ::Result<Vec<u8>>;
142 /// Read a word.
143 fn read_i8(&mut self) -> ::Result<i8>;
144 /// Read a 16-bit signed integer.
145 fn read_i16(&mut self) -> ::Result<i16>;
146 /// Read a 32-bit signed integer.
147 fn read_i32(&mut self) -> ::Result<i32>;
148 /// Read a 64-bit signed integer.
149 fn read_i64(&mut self) -> ::Result<i64>;
150 /// Read a 64-bit float.
151 fn read_double(&mut self) -> ::Result<f64>;
152 /// Read a fixed-length string (not null terminated).
153 fn read_string(&mut self) -> ::Result<String>;
154 /// Read the beginning of a list.
155 fn read_list_begin(&mut self) -> ::Result<TListIdentifier>;
156 /// Read the end of a list.
157 fn read_list_end(&mut self) -> ::Result<()>;
158 /// Read the beginning of a set.
159 fn read_set_begin(&mut self) -> ::Result<TSetIdentifier>;
160 /// Read the end of a set.
161 fn read_set_end(&mut self) -> ::Result<()>;
162 /// Read the beginning of a map.
163 fn read_map_begin(&mut self) -> ::Result<TMapIdentifier>;
164 /// Read the end of a map.
165 fn read_map_end(&mut self) -> ::Result<()>;
166 /// Skip a field with type `field_type` recursively until the default
167 /// maximum skip depth is reached.
168 fn skip(&mut self, field_type: TType) -> ::Result<()> {
169 self.skip_till_depth(field_type, MAXIMUM_SKIP_DEPTH)
170 }
171 /// Skip a field with type `field_type` recursively up to `depth` levels.
172 fn skip_till_depth(&mut self, field_type: TType, depth: i8) -> ::Result<()> {
173 if depth == 0 {
174 return Err(::Error::Protocol(ProtocolError {
175 kind: ProtocolErrorKind::DepthLimit,
176 message: format!("cannot parse past {:?}", field_type),
177 }));
178 }
179
180 match field_type {
181 TType::Bool => self.read_bool().map(|_| ()),
182 TType::I08 => self.read_i8().map(|_| ()),
183 TType::I16 => self.read_i16().map(|_| ()),
184 TType::I32 => self.read_i32().map(|_| ()),
185 TType::I64 => self.read_i64().map(|_| ()),
186 TType::Double => self.read_double().map(|_| ()),
187 TType::String => self.read_string().map(|_| ()),
188 TType::Struct => {
189 self.read_struct_begin()?;
190 loop {
191 let field_ident = self.read_field_begin()?;
192 if field_ident.field_type == TType::Stop {
193 break;
194 }
195 self.skip_till_depth(field_ident.field_type, depth - 1)?;
196 }
197 self.read_struct_end()
198 }
199 TType::List => {
200 let list_ident = self.read_list_begin()?;
201 for _ in 0..list_ident.size {
202 self.skip_till_depth(list_ident.element_type, depth - 1)?;
203 }
204 self.read_list_end()
205 }
206 TType::Set => {
207 let set_ident = self.read_set_begin()?;
208 for _ in 0..set_ident.size {
209 self.skip_till_depth(set_ident.element_type, depth - 1)?;
210 }
211 self.read_set_end()
212 }
213 TType::Map => {
214 let map_ident = self.read_map_begin()?;
215 for _ in 0..map_ident.size {
216 let key_type = map_ident.key_type
217 .expect("non-zero sized map should contain key type");
218 let val_type = map_ident.value_type
219 .expect("non-zero sized map should contain value type");
220 self.skip_till_depth(key_type, depth - 1)?;
221 self.skip_till_depth(val_type, depth - 1)?;
222 }
223 self.read_map_end()
224 }
225 u => {
226 Err(::Error::Protocol(ProtocolError {
227 kind: ProtocolErrorKind::Unknown,
228 message: format!("cannot skip field type {:?}", &u),
229 }))
230 }
231 }
232 }
233
234 // utility (DO NOT USE IN GENERATED CODE!!!!)
235 //
236
237 /// Read an unsigned byte.
238 ///
239 /// This method should **never** be used in generated code.
240 fn read_byte(&mut self) -> ::Result<u8>;
241}
242
243/// Converts Thrift identifiers, primitives, containers or structs into a
244/// stream of bytes.
245///
246/// This trait does not deal with higher-level Thrift concepts like structs or
247/// exceptions - only with primitives and message or container boundaries.
248/// Write methods take an identifier (for example, `TMessageIdentifier`) or a
249/// primitive. Any or all of the fields in an identifier may be omitted when
250/// writing to the transport. Write methods may even be noops. All of this is
251/// transparent to the caller; as long as a matching `TInputProtocol`
252/// implementation is used, received messages will be decoded correctly.
253///
254/// All methods return a `thrift::Result`. If an `Err` is returned the protocol
255/// instance and its underlying transport should be terminated.
256///
257/// # Examples
258///
259/// Create and use a `TOutputProtocol`
260///
261/// ```no_run
262/// use std::cell::RefCell;
263/// use std::rc::Rc;
264/// use thrift::protocol::{TBinaryOutputProtocol, TFieldIdentifier, TOutputProtocol, TType};
265/// use thrift::transport::{TTcpTransport, TTransport};
266///
267/// let mut transport = TTcpTransport::new();
268/// transport.open("127.0.0.1:9090").unwrap();
269/// let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
270///
271/// let mut o_prot = TBinaryOutputProtocol::new(transport.clone(), true);
272///
273/// o_prot.write_field_begin(&TFieldIdentifier::new("string_thing", TType::String, 1)).unwrap();
274/// o_prot.write_string("foo").unwrap();
275/// o_prot.write_field_end().unwrap();
276/// ```
277pub trait TOutputProtocol {
278 /// Write the beginning of a Thrift message.
279 fn write_message_begin(&mut self, identifier: &TMessageIdentifier) -> ::Result<()>;
280 /// Write the end of a Thrift message.
281 fn write_message_end(&mut self) -> ::Result<()>;
282 /// Write the beginning of a Thrift struct.
283 fn write_struct_begin(&mut self, identifier: &TStructIdentifier) -> ::Result<()>;
284 /// Write the end of a Thrift struct.
285 fn write_struct_end(&mut self) -> ::Result<()>;
286 /// Write the beginning of a Thrift field.
287 fn write_field_begin(&mut self, identifier: &TFieldIdentifier) -> ::Result<()>;
288 /// Write the end of a Thrift field.
289 fn write_field_end(&mut self) -> ::Result<()>;
290 /// Write a STOP field indicating that all the fields in a struct have been
291 /// written.
292 fn write_field_stop(&mut self) -> ::Result<()>;
293 /// Write a bool.
294 fn write_bool(&mut self, b: bool) -> ::Result<()>;
295 /// Write a fixed-length byte array.
296 fn write_bytes(&mut self, b: &[u8]) -> ::Result<()>;
297 /// Write an 8-bit signed integer.
298 fn write_i8(&mut self, i: i8) -> ::Result<()>;
299 /// Write a 16-bit signed integer.
300 fn write_i16(&mut self, i: i16) -> ::Result<()>;
301 /// Write a 32-bit signed integer.
302 fn write_i32(&mut self, i: i32) -> ::Result<()>;
303 /// Write a 64-bit signed integer.
304 fn write_i64(&mut self, i: i64) -> ::Result<()>;
305 /// Write a 64-bit float.
306 fn write_double(&mut self, d: f64) -> ::Result<()>;
307 /// Write a fixed-length string.
308 fn write_string(&mut self, s: &str) -> ::Result<()>;
309 /// Write the beginning of a list.
310 fn write_list_begin(&mut self, identifier: &TListIdentifier) -> ::Result<()>;
311 /// Write the end of a list.
312 fn write_list_end(&mut self) -> ::Result<()>;
313 /// Write the beginning of a set.
314 fn write_set_begin(&mut self, identifier: &TSetIdentifier) -> ::Result<()>;
315 /// Write the end of a set.
316 fn write_set_end(&mut self) -> ::Result<()>;
317 /// Write the beginning of a map.
318 fn write_map_begin(&mut self, identifier: &TMapIdentifier) -> ::Result<()>;
319 /// Write the end of a map.
320 fn write_map_end(&mut self) -> ::Result<()>;
321 /// Flush buffered bytes to the underlying transport.
322 fn flush(&mut self) -> ::Result<()>;
323
324 // utility (DO NOT USE IN GENERATED CODE!!!!)
325 //
326
327 /// Write an unsigned byte.
328 ///
329 /// This method should **never** be used in generated code.
330 fn write_byte(&mut self, b: u8) -> ::Result<()>; // FIXME: REMOVE
331}
332
333/// Helper type used by servers to create `TInputProtocol` instances for
334/// accepted client connections.
335///
336/// # Examples
337///
338/// Create a `TInputProtocolFactory` and use it to create a `TInputProtocol`.
339///
340/// ```no_run
341/// use std::cell::RefCell;
342/// use std::rc::Rc;
343/// use thrift::protocol::{TBinaryInputProtocolFactory, TInputProtocolFactory};
344/// use thrift::transport::{TTcpTransport, TTransport};
345///
346/// let mut transport = TTcpTransport::new();
347/// transport.open("127.0.0.1:9090").unwrap();
348/// let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
349///
350/// let mut i_proto_factory = TBinaryInputProtocolFactory::new();
351/// let i_prot = i_proto_factory.create(transport);
352/// ```
353pub trait TInputProtocolFactory {
354 /// Create a `TInputProtocol` that reads bytes from `transport`.
355 fn create(&mut self, transport: Rc<RefCell<Box<TTransport>>>) -> Box<TInputProtocol>;
356}
357
358/// Helper type used by servers to create `TOutputProtocol` instances for
359/// accepted client connections.
360///
361/// # Examples
362///
363/// Create a `TOutputProtocolFactory` and use it to create a `TOutputProtocol`.
364///
365/// ```no_run
366/// use std::cell::RefCell;
367/// use std::rc::Rc;
368/// use thrift::protocol::{TBinaryOutputProtocolFactory, TOutputProtocolFactory};
369/// use thrift::transport::{TTcpTransport, TTransport};
370///
371/// let mut transport = TTcpTransport::new();
372/// transport.open("127.0.0.1:9090").unwrap();
373/// let transport = Rc::new(RefCell::new(Box::new(transport) as Box<TTransport>));
374///
375/// let mut o_proto_factory = TBinaryOutputProtocolFactory::new();
376/// let o_prot = o_proto_factory.create(transport);
377/// ```
378pub trait TOutputProtocolFactory {
379 /// Create a `TOutputProtocol` that writes bytes to `transport`.
380 fn create(&mut self, transport: Rc<RefCell<Box<TTransport>>>) -> Box<TOutputProtocol>;
381}
382
383/// Thrift message identifier.
384#[derive(Clone, Debug, Eq, PartialEq)]
385pub struct TMessageIdentifier {
386 /// Service call the message is associated with.
387 pub name: String,
388 /// Message type.
389 pub message_type: TMessageType,
390 /// Ordered sequence number identifying the message.
391 pub sequence_number: i32,
392}
393
394impl TMessageIdentifier {
395 /// Create a `TMessageIdentifier` for a Thrift service-call named `name`
396 /// with message type `message_type` and sequence number `sequence_number`.
397 pub fn new<S: Into<String>>(name: S,
398 message_type: TMessageType,
399 sequence_number: i32)
400 -> TMessageIdentifier {
401 TMessageIdentifier {
402 name: name.into(),
403 message_type: message_type,
404 sequence_number: sequence_number,
405 }
406 }
407}
408
409/// Thrift struct identifier.
410#[derive(Clone, Debug, Eq, PartialEq)]
411pub struct TStructIdentifier {
412 /// Name of the encoded Thrift struct.
413 pub name: String,
414}
415
416impl TStructIdentifier {
417 /// Create a `TStructIdentifier` for a struct named `name`.
418 pub fn new<S: Into<String>>(name: S) -> TStructIdentifier {
419 TStructIdentifier { name: name.into() }
420 }
421}
422
423/// Thrift field identifier.
424#[derive(Clone, Debug, Eq, PartialEq)]
425pub struct TFieldIdentifier {
426 /// Name of the Thrift field.
427 ///
428 /// `None` if it's not sent over the wire.
429 pub name: Option<String>,
430 /// Field type.
431 ///
432 /// This may be a primitive, container, or a struct.
433 pub field_type: TType,
434 /// Thrift field id.
435 ///
436 /// `None` only if `field_type` is `TType::Stop`.
437 pub id: Option<i16>,
438}
439
440impl TFieldIdentifier {
441 /// Create a `TFieldIdentifier` for a field named `name` with type
442 /// `field_type` and field id `id`.
443 ///
444 /// `id` should be `None` if `field_type` is `TType::Stop`.
445 pub fn new<N, S, I>(name: N, field_type: TType, id: I) -> TFieldIdentifier
446 where N: Into<Option<S>>,
447 S: Into<String>,
448 I: Into<Option<i16>>
449 {
450 TFieldIdentifier {
451 name: name.into().map(|n| n.into()),
452 field_type: field_type,
453 id: id.into(),
454 }
455 }
456}
457
458/// Thrift list identifier.
459#[derive(Clone, Debug, Eq, PartialEq)]
460pub struct TListIdentifier {
461 /// Type of the elements in the list.
462 pub element_type: TType,
463 /// Number of elements in the list.
464 pub size: i32,
465}
466
467impl TListIdentifier {
468 /// Create a `TListIdentifier` for a list with `size` elements of type
469 /// `element_type`.
470 pub fn new(element_type: TType, size: i32) -> TListIdentifier {
471 TListIdentifier {
472 element_type: element_type,
473 size: size,
474 }
475 }
476}
477
478/// Thrift set identifier.
479#[derive(Clone, Debug, Eq, PartialEq)]
480pub struct TSetIdentifier {
481 /// Type of the elements in the set.
482 pub element_type: TType,
483 /// Number of elements in the set.
484 pub size: i32,
485}
486
487impl TSetIdentifier {
488 /// Create a `TSetIdentifier` for a set with `size` elements of type
489 /// `element_type`.
490 pub fn new(element_type: TType, size: i32) -> TSetIdentifier {
491 TSetIdentifier {
492 element_type: element_type,
493 size: size,
494 }
495 }
496}
497
498/// Thrift map identifier.
499#[derive(Clone, Debug, Eq, PartialEq)]
500pub struct TMapIdentifier {
501 /// Map key type.
502 pub key_type: Option<TType>,
503 /// Map value type.
504 pub value_type: Option<TType>,
505 /// Number of entries in the map.
506 pub size: i32,
507}
508
509impl TMapIdentifier {
510 /// Create a `TMapIdentifier` for a map with `size` entries of type
511 /// `key_type -> value_type`.
512 pub fn new<K, V>(key_type: K, value_type: V, size: i32) -> TMapIdentifier
513 where K: Into<Option<TType>>,
514 V: Into<Option<TType>>
515 {
516 TMapIdentifier {
517 key_type: key_type.into(),
518 value_type: value_type.into(),
519 size: size,
520 }
521 }
522}
523
524/// Thrift message types.
525#[derive(Clone, Copy, Debug, Eq, PartialEq)]
526pub enum TMessageType {
527 /// Service-call request.
528 Call,
529 /// Service-call response.
530 Reply,
531 /// Unexpected error in the remote service.
532 Exception,
533 /// One-way service-call request (no response is expected).
534 OneWay,
535}
536
537impl Display for TMessageType {
538 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
539 match *self {
540 TMessageType::Call => write!(f, "Call"),
541 TMessageType::Reply => write!(f, "Reply"),
542 TMessageType::Exception => write!(f, "Exception"),
543 TMessageType::OneWay => write!(f, "OneWay"),
544 }
545 }
546}
547
548impl From<TMessageType> for u8 {
549 fn from(message_type: TMessageType) -> Self {
550 match message_type {
551 TMessageType::Call => 0x01,
552 TMessageType::Reply => 0x02,
553 TMessageType::Exception => 0x03,
554 TMessageType::OneWay => 0x04,
555 }
556 }
557}
558
559impl TryFrom<u8> for TMessageType {
560 type Err = ::Error;
561 fn try_from(b: u8) -> ::Result<Self> {
562 match b {
563 0x01 => Ok(TMessageType::Call),
564 0x02 => Ok(TMessageType::Reply),
565 0x03 => Ok(TMessageType::Exception),
566 0x04 => Ok(TMessageType::OneWay),
567 unkn => {
568 Err(::Error::Protocol(ProtocolError {
569 kind: ProtocolErrorKind::InvalidData,
570 message: format!("cannot convert {} to TMessageType", unkn),
571 }))
572 }
573 }
574 }
575}
576
577/// Thrift struct-field types.
578#[derive(Clone, Copy, Debug, Eq, PartialEq)]
579pub enum TType {
580 /// Indicates that there are no more serialized fields in this Thrift struct.
581 Stop,
582 /// Void (`()`) field.
583 Void,
584 /// Boolean.
585 Bool,
586 /// Signed 8-bit int.
587 I08,
588 /// Double-precision number.
589 Double,
590 /// Signed 16-bit int.
591 I16,
592 /// Signed 32-bit int.
593 I32,
594 /// Signed 64-bit int.
595 I64,
596 /// UTF-8 string.
597 String,
598 /// UTF-7 string. *Unsupported*.
599 Utf7,
600 /// Thrift struct.
601 Struct,
602 /// Map.
603 Map,
604 /// Set.
605 Set,
606 /// List.
607 List,
608 /// UTF-8 string.
609 Utf8,
610 /// UTF-16 string. *Unsupported*.
611 Utf16,
612}
613
614impl Display for TType {
615 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
616 match *self {
617 TType::Stop => write!(f, "STOP"),
618 TType::Void => write!(f, "void"),
619 TType::Bool => write!(f, "bool"),
620 TType::I08 => write!(f, "i08"),
621 TType::Double => write!(f, "double"),
622 TType::I16 => write!(f, "i16"),
623 TType::I32 => write!(f, "i32"),
624 TType::I64 => write!(f, "i64"),
625 TType::String => write!(f, "string"),
626 TType::Utf7 => write!(f, "UTF7"),
627 TType::Struct => write!(f, "struct"),
628 TType::Map => write!(f, "map"),
629 TType::Set => write!(f, "set"),
630 TType::List => write!(f, "list"),
631 TType::Utf8 => write!(f, "UTF8"),
632 TType::Utf16 => write!(f, "UTF16"),
633 }
634 }
635}
636
637/// Compare the expected message sequence number `expected` with the received
638/// message sequence number `actual`.
639///
640/// Return `()` if `actual == expected`, `Err` otherwise.
641pub fn verify_expected_sequence_number(expected: i32, actual: i32) -> ::Result<()> {
642 if expected == actual {
643 Ok(())
644 } else {
645 Err(::Error::Application(::ApplicationError {
646 kind: ::ApplicationErrorKind::BadSequenceId,
647 message: format!("expected {} got {}", expected, actual),
648 }))
649 }
650}
651
652/// Compare the expected service-call name `expected` with the received
653/// service-call name `actual`.
654///
655/// Return `()` if `actual == expected`, `Err` otherwise.
656pub fn verify_expected_service_call(expected: &str, actual: &str) -> ::Result<()> {
657 if expected == actual {
658 Ok(())
659 } else {
660 Err(::Error::Application(::ApplicationError {
661 kind: ::ApplicationErrorKind::WrongMethodName,
662 message: format!("expected {} got {}", expected, actual),
663 }))
664 }
665}
666
667/// Compare the expected message type `expected` with the received message type
668/// `actual`.
669///
670/// Return `()` if `actual == expected`, `Err` otherwise.
671pub fn verify_expected_message_type(expected: TMessageType, actual: TMessageType) -> ::Result<()> {
672 if expected == actual {
673 Ok(())
674 } else {
675 Err(::Error::Application(::ApplicationError {
676 kind: ::ApplicationErrorKind::InvalidMessageType,
677 message: format!("expected {} got {}", expected, actual),
678 }))
679 }
680}
681
682/// Check if a required Thrift struct field exists.
683///
684/// Return `()` if it does, `Err` otherwise.
685pub fn verify_required_field_exists<T>(field_name: &str, field: &Option<T>) -> ::Result<()> {
686 match *field {
687 Some(_) => Ok(()),
688 None => {
689 Err(::Error::Protocol(::ProtocolError {
690 kind: ::ProtocolErrorKind::Unknown,
691 message: format!("missing required field {}", field_name),
692 }))
693 }
694 }
695}
696
697/// Extract the field id from a Thrift field identifier.
698///
699/// `field_ident` must *not* have `TFieldIdentifier.field_type` of type `TType::Stop`.
700///
701/// Return `TFieldIdentifier.id` if an id exists, `Err` otherwise.
702pub fn field_id(field_ident: &TFieldIdentifier) -> ::Result<i16> {
703 field_ident.id.ok_or_else(|| {
704 ::Error::Protocol(::ProtocolError {
705 kind: ::ProtocolErrorKind::Unknown,
706 message: format!("missing field in in {:?}", field_ident),
707 })
708 })
709}