1 # Rust Language Bindings for Thrift
5 1. Get the [Thrift compiler](https://thrift.apache.org).
7 2. Add the following crates to your `Cargo.toml`.
10 thrift = "x.y.z" # x.y.z is the version of the thrift compiler
11 ordered-float = "0.3.0"
15 3. Add the same crates to your `lib.rs` or `main.rs`.
18 extern crate ordered_float;
20 extern crate try_from;
23 4. Generate Rust sources for your IDL (for example, `Tutorial.thrift`).
26 thrift -out my_rust_program/src --gen rs -r Tutorial.thrift
29 5. Use the generated source in your code.
32 // add extern crates here, or in your lib.rs
33 extern crate ordered_float;
35 extern crate try_from;
37 // generated Rust module
40 use thrift::protocol::{TCompactInputProtocol, TCompactOutputProtocol};
41 use thrift::protocol::{TInputProtocol, TOutputProtocol};
42 use thrift::transport::{TFramedReadTransport, TFramedWriteTransport};
43 use thrift::transport::{TIoChannel, TTcpChannel};
45 use tutorial::{CalculatorSyncClient, TCalculatorSyncClient};
46 use tutorial::{Operation, Work};
50 Ok(()) => println!("client ran successfully"),
52 println!("client failed with {:?}", e);
53 std::process::exit(1);
58 fn run() -> thrift::Result<()> {
63 println!("connect to server on 127.0.0.1:9090");
64 let mut c = TTcpChannel::new();
65 c.open("127.0.0.1:9090")?;
67 let (i_chan, o_chan) = c.split()?;
69 let i_prot = TCompactInputProtocol::new(
70 TFramedReadTransport::new(i_chan)
72 let o_prot = TCompactOutputProtocol::new(
73 TFramedWriteTransport::new(o_chan)
76 let mut client = CalculatorSyncClient::new(i_prot, o_prot);
79 // alright! - let's make some calls
82 // two-way, void return
85 // two-way with some return
86 let res = client.calculate(
88 Work::new(7, 8, Operation::Multiply, None)
90 println!("multiplied 7 and 8, got {}", res);
92 // two-way and returns a Thrift-defined exception
93 let res = client.calculate(
95 Work::new(2, 0, Operation::Divide, None)
98 Ok(v) => panic!("shouldn't have succeeded with result {}", v),
99 Err(e) => println!("divide by zero failed with {:?}", e),
112 ### Thrift Files and Generated Modules
114 The Thrift code generator takes each Thrift file and generates a Rust module
115 with the same name snake-cased. For example, running the compiler on
116 `ThriftTest.thrift` creates `thrift_test.rs`. To use these generated files add
117 `mod ...` and `use ...` declarations to your `lib.rs` or `main.rs` - one for
120 ### Results and Errors
122 The Thrift runtime library defines a `thrift::Result` and a `thrift::Error` type,
123 both of which are used throught the runtime library and in all generated code.
124 Conversions are defined from `std::io::Error`, `str` and `String` into
127 ### Thrift Type and their Rust Equivalents
129 Thrift defines a number of types, each of which is translated into its Rust
130 equivalent by the code generator.
132 * Primitives (bool, i8, i16, i32, i64, double, string, binary)
140 * Constants (primitives, containers, structs)
142 In addition, unless otherwise noted, thrift includes are translated into
143 `use ...` statements in the generated code, and all declarations, parameters,
144 traits and types in the generated code are namespaced appropriately.
146 The following subsections cover each type and their generated Rust equivalent.
150 Thrift primitives have straightforward Rust equivalents.
157 * double: `OrderedFloat<f64>`
163 A typedef is translated to a `pub type` declaration.
168 typedef map<string, UserId> MapType
171 pub type UserId = i64;
173 pub type MapType = BTreeMap<String, Bonk>;
178 A Thrift enum is represented as a Rust enum, and each variant is transcribed 1:1.
193 #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
203 impl TryFrom<i32> for Numberz {
211 Thrift has three container types: list, set and map. They are translated into
212 Rust `Vec`, `BTreeSet` and `BTreeMap` respectively. Any Thrift type (this
213 includes structs, enums and typedefs) can be a list/set element or a map
233 numbers: BTreeSet<i32>
239 map <string, i32> numbers
243 numbers: BTreeMap<String, i32>
248 A Thrift struct is represented as a Rust struct, and each field transcribed 1:1.
251 struct CrazyNesting {
252 1: string string_field,
253 2: optional set<Insanity> set_field,
255 map<set<i32>, map<i32,set<list<map<Insanity,string>>>>>
257 4: binary binary_field
261 #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
262 pub struct CrazyNesting {
263 pub string_field: Option<String>,
264 pub set_field: Option<BTreeSet<Insanity>>,
268 BTreeMap<i32, BTreeSet<Vec<BTreeMap<Insanity, String>>>>
271 pub binary_field: Option<Vec<u8>>,
275 pub fn read_from_in_protocol(i_prot: &mut TInputProtocol)
277 thrift::Result<CrazyNesting> {
280 pub fn write_to_out_protocol(&self, o_prot: &mut TOutputProtocol)
290 Thrift has 3 "optionality" types:
296 The Rust code generator encodes *Required* fields as the bare type itself, while
297 *Optional* and *Default* fields are encoded as `Option<TypeName>`.
301 1: required string bar // 1. required
302 2: optional string baz // 2. optional
303 3: string qux // 3. default
309 bar: String, // 1. required
310 baz: Option<String>, // 2. optional
311 qux: Option<String>, // 3. default
317 * Struct constants are not supported
318 * Map, list and set constants require a const holder struct