blob: a686b9b19f8ef56ffb1c0c36a6f22fa40f02045d [file] [log] [blame] [view]
Allen George8b96bfb2016-11-02 08:01:08 -04001# Rust Language Bindings for Thrift
2
3## Getting Started
4
51. Get the [Thrift compiler](https://thrift.apache.org).
6
72. Add the following crates to your `Cargo.toml`.
8
9```toml
10thrift = "x.y.z" # x.y.z is the version of the thrift compiler
11ordered_float = "0.3.0"
12try_from = "0.2.0"
13```
14
153. Add the same crates to your `lib.rs` or `main.rs`.
16
17```rust
18extern crate ordered_float;
19extern crate thrift;
20extern crate try_from;
21```
22
234. Generate Rust sources for your IDL (for example, `Tutorial.thrift`).
24
25```shell
26thrift -out my_rust_program/src --gen rs -r Tutorial.thrift
27```
28
295. Use the generated source in your code.
30
31```rust
32// add extern crates here, or in your lib.rs
33extern crate ordered_float;
34extern crate thrift;
35extern crate try_from;
36
37// generated Rust module
Allen George0e22c362017-01-30 07:15:00 -050038use tutorial;
Allen George8b96bfb2016-11-02 08:01:08 -040039
Allen George8b96bfb2016-11-02 08:01:08 -040040use thrift::protocol::{TCompactInputProtocol, TCompactOutputProtocol};
Allen George0e22c362017-01-30 07:15:00 -050041use thrift::protocol::{TInputProtocol, TOutputProtocol};
42use thrift::transport::{TFramedReadTransport, TFramedWriteTransport};
43use thrift::transport::{TIoChannel, TTcpChannel};
Allen George8b96bfb2016-11-02 08:01:08 -040044use tutorial::{CalculatorSyncClient, TCalculatorSyncClient};
45use tutorial::{Operation, Work};
46
47fn main() {
48 match run() {
49 Ok(()) => println!("client ran successfully"),
50 Err(e) => {
51 println!("client failed with {:?}", e);
52 std::process::exit(1);
53 }
54 }
55}
56
57fn run() -> thrift::Result<()> {
58 //
59 // build client
60 //
61
62 println!("connect to server on 127.0.0.1:9090");
Allen George0e22c362017-01-30 07:15:00 -050063 let mut c = TTcpTransport::new();
64 c.open("127.0.0.1:9090")?;
Allen George8b96bfb2016-11-02 08:01:08 -040065
Allen George0e22c362017-01-30 07:15:00 -050066 let (i_chan, o_chan) = c.split()?;
67
68 let i_prot = TCompactInputProtocol::new(
69 TFramedReadTransport::new(i_chan)
Allen George8b96bfb2016-11-02 08:01:08 -040070 );
Allen George0e22c362017-01-30 07:15:00 -050071 let o_prot = TCompactOutputProtocol::new(
72 TFramedWriteTransport::new(o_chan)
Allen George8b96bfb2016-11-02 08:01:08 -040073 );
74
75 let client = CalculatorSyncClient::new(i_prot, o_prot);
76
77 //
78 // alright! - let's make some calls
79 //
80
81 // two-way, void return
82 client.ping()?;
83
84 // two-way with some return
85 let res = client.calculate(
86 72,
jose andres0124c4d2019-05-14 15:13:17 +020087 Work::new(7, 8, Operation::Multiply, None)
Allen George8b96bfb2016-11-02 08:01:08 -040088 )?;
89 println!("multiplied 7 and 8, got {}", res);
90
91 // two-way and returns a Thrift-defined exception
92 let res = client.calculate(
93 77,
jose andres0124c4d2019-05-14 15:13:17 +020094 Work::new(2, 0, Operation::Divide, None)
Allen George8b96bfb2016-11-02 08:01:08 -040095 );
96 match res {
97 Ok(v) => panic!("shouldn't have succeeded with result {}", v),
98 Err(e) => println!("divide by zero failed with {:?}", e),
99 }
100
101 // one-way
102 client.zip()?;
103
104 // done!
105 Ok(())
106}
107```
108
109## Code Generation
110
111### Thrift Files and Generated Modules
112
113The Thrift code generator takes each Thrift file and generates a Rust module
114with the same name snake-cased. For example, running the compiler on
115`ThriftTest.thrift` creates `thrift_test.rs`. To use these generated files add
116`mod ...` and `use ...` declarations to your `lib.rs` or `main.rs` - one for
117each generated file.
118
119### Results and Errors
120
121The Thrift runtime library defines a `thrift::Result` and a `thrift::Error` type,
122both of which are used throught the runtime library and in all generated code.
123Conversions are defined from `std::io::Error`, `str` and `String` into
124`thrift::Error`.
125
126### Thrift Type and their Rust Equivalents
127
128Thrift defines a number of types, each of which is translated into its Rust
129equivalent by the code generator.
130
131* Primitives (bool, i8, i16, i32, i64, double, string, binary)
132* Typedefs
133* Enums
134* Containers
135* Structs
136* Unions
137* Exceptions
138* Services
139* Constants (primitives, containers, structs)
140
141In addition, unless otherwise noted, thrift includes are translated into
142`use ...` statements in the generated code, and all declarations, parameters,
143traits and types in the generated code are namespaced appropriately.
144
145The following subsections cover each type and their generated Rust equivalent.
146
147### Primitives
148
149Thrift primitives have straightforward Rust equivalents.
150
151* bool: `bool`
152* i8: `i8`
153* i16: `i16`
154* i32: `i32`
155* i64: `i64`
156* double: `OrderedFloat<f64>`
157* string: `String`
158* binary: `Vec<u8>`
159
160### Typedefs
161
162A typedef is translated to a `pub type` declaration.
163
164```thrift
165typedef i64 UserId
166
Allen George0e22c362017-01-30 07:15:00 -0500167typedef map<string, UserId> MapType
Allen George8b96bfb2016-11-02 08:01:08 -0400168```
169```rust
Allen George0e22c362017-01-30 07:15:00 -0500170pub type UserId = i64;
Allen George8b96bfb2016-11-02 08:01:08 -0400171
172pub type MapType = BTreeMap<String, Bonk>;
173```
174
175### Enums
176
177A Thrift enum is represented as a Rust enum, and each variant is transcribed 1:1.
178
179```thrift
180enum Numberz
181{
182 ONE = 1,
183 TWO,
184 THREE,
185 FIVE = 5,
186 SIX,
187 EIGHT = 8
188}
189```
190
191```rust
192#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
193pub enum Numberz {
194 ONE = 1,
195 TWO = 2,
196 THREE = 3,
197 FIVE = 5,
198 SIX = 6,
199 EIGHT = 8,
200}
201
202impl TryFrom<i32> for Numberz {
203 // ...
204}
205
206```
207
208### Containers
209
210Thrift has three container types: list, set and map. They are translated into
211Rust `Vec`, `BTreeSet` and `BTreeMap` respectively. Any Thrift type (this
212includes structs, enums and typedefs) can be a list/set element or a map
213key/value.
214
215#### List
216
217```thrift
218list <i32> numbers
219```
220
221```rust
222numbers: Vec<i32>
223```
224
225#### Set
226
227```thrift
228set <i32> numbers
229```
230
231```rust
232numbers: BTreeSet<i32>
233```
234
235#### Map
236
237```thrift
238map <string, i32> numbers
239```
240
241```rust
242numbers: BTreeMap<String, i32>
243```
244
245### Structs
246
247A Thrift struct is represented as a Rust struct, and each field transcribed 1:1.
248
249```thrift
250struct CrazyNesting {
251 1: string string_field,
252 2: optional set<Insanity> set_field,
253 3: required list<
254 map<set<i32>, map<i32,set<list<map<Insanity,string>>>>>
255 >
256 4: binary binary_field
257}
258```
259```rust
260#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
261pub struct CrazyNesting {
262 pub string_field: Option<String>,
263 pub set_field: Option<BTreeSet<Insanity>>,
264 pub list_field: Vec<
265 BTreeMap<
266 BTreeSet<i32>,
267 BTreeMap<i32, BTreeSet<Vec<BTreeMap<Insanity, String>>>>
268 >
269 >,
270 pub binary_field: Option<Vec<u8>>,
271}
272
273impl CrazyNesting {
274 pub fn read_from_in_protocol(i_prot: &mut TInputProtocol)
275 ->
276 thrift::Result<CrazyNesting> {
277 // ...
278 }
279 pub fn write_to_out_protocol(&self, o_prot: &mut TOutputProtocol)
280 ->
281 thrift::Result<()> {
282 // ...
283 }
284}
285
286```
287##### Optionality
288
289Thrift has 3 "optionality" types:
290
2911. Required
2922. Optional
2933. Default
294
295The Rust code generator encodes *Required* fields as the bare type itself, while
296*Optional* and *Default* fields are encoded as `Option<TypeName>`.
297
298```thrift
299struct Foo {
300 1: required string bar // 1. required
301 2: optional string baz // 2. optional
302 3: string qux // 3. default
303}
304```
305
306```rust
307pub struct Foo {
308 bar: String, // 1. required
309 baz: Option<String>, // 2. optional
310 qux: Option<String>, // 3. default
311}
312```
313
314## Known Issues
315
316* Struct constants are not supported
Allen George0e22c362017-01-30 07:15:00 -0500317* Map, list and set constants require a const holder struct