]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/thrift/tutorial/rs/README.md
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / thrift / tutorial / rs / README.md
CommitLineData
f67539c2
TL
1# 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
38mod tutorial;
39
40use thrift::protocol::{TCompactInputProtocol, TCompactOutputProtocol};
41use thrift::protocol::{TInputProtocol, TOutputProtocol};
42use thrift::transport::{TFramedReadTransport, TFramedWriteTransport};
43use thrift::transport::{TIoChannel, TTcpChannel};
44
45use tutorial::{CalculatorSyncClient, TCalculatorSyncClient};
46use tutorial::{Operation, Work};
47
48fn main() {
49 match run() {
50 Ok(()) => println!("client ran successfully"),
51 Err(e) => {
52 println!("client failed with {:?}", e);
53 std::process::exit(1);
54 }
55 }
56}
57
58fn run() -> thrift::Result<()> {
59 //
60 // build client
61 //
62
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")?;
66
67 let (i_chan, o_chan) = c.split()?;
68
69 let i_prot = TCompactInputProtocol::new(
70 TFramedReadTransport::new(i_chan)
71 );
72 let o_prot = TCompactOutputProtocol::new(
73 TFramedWriteTransport::new(o_chan)
74 );
75
76 let mut client = CalculatorSyncClient::new(i_prot, o_prot);
77
78 //
79 // alright! - let's make some calls
80 //
81
82 // two-way, void return
83 client.ping()?;
84
85 // two-way with some return
86 let res = client.calculate(
87 72,
88 Work::new(7, 8, Operation::Multiply, None)
89 )?;
90 println!("multiplied 7 and 8, got {}", res);
91
92 // two-way and returns a Thrift-defined exception
93 let res = client.calculate(
94 77,
95 Work::new(2, 0, Operation::Divide, None)
96 );
97 match res {
98 Ok(v) => panic!("shouldn't have succeeded with result {}", v),
99 Err(e) => println!("divide by zero failed with {:?}", e),
100 }
101
102 // one-way
103 client.zip()?;
104
105 // done!
106 Ok(())
107}
108```
109
110## Code Generation
111
112### Thrift Files and Generated Modules
113
114The Thrift code generator takes each Thrift file and generates a Rust module
115with 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
118each generated file.
119
120### Results and Errors
121
122The Thrift runtime library defines a `thrift::Result` and a `thrift::Error` type,
123both of which are used throught the runtime library and in all generated code.
124Conversions are defined from `std::io::Error`, `str` and `String` into
125`thrift::Error`.
126
127### Thrift Type and their Rust Equivalents
128
129Thrift defines a number of types, each of which is translated into its Rust
130equivalent by the code generator.
131
132* Primitives (bool, i8, i16, i32, i64, double, string, binary)
133* Typedefs
134* Enums
135* Containers
136* Structs
137* Unions
138* Exceptions
139* Services
140* Constants (primitives, containers, structs)
141
142In addition, unless otherwise noted, thrift includes are translated into
143`use ...` statements in the generated code, and all declarations, parameters,
144traits and types in the generated code are namespaced appropriately.
145
146The following subsections cover each type and their generated Rust equivalent.
147
148### Primitives
149
150Thrift primitives have straightforward Rust equivalents.
151
152* bool: `bool`
153* i8: `i8`
154* i16: `i16`
155* i32: `i32`
156* i64: `i64`
157* double: `OrderedFloat<f64>`
158* string: `String`
159* binary: `Vec<u8>`
160
161### Typedefs
162
163A typedef is translated to a `pub type` declaration.
164
165```thrift
166typedef i64 UserId
167
168typedef map<string, UserId> MapType
169```
170```rust
171pub type UserId = i64;
172
173pub type MapType = BTreeMap<String, Bonk>;
174```
175
176### Enums
177
178A Thrift enum is represented as a Rust enum, and each variant is transcribed 1:1.
179
180```thrift
181enum Numberz
182{
183 ONE = 1,
184 TWO,
185 THREE,
186 FIVE = 5,
187 SIX,
188 EIGHT = 8
189}
190```
191
192```rust
193#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
194pub enum Numberz {
195 ONE = 1,
196 TWO = 2,
197 THREE = 3,
198 FIVE = 5,
199 SIX = 6,
200 EIGHT = 8,
201}
202
203impl TryFrom<i32> for Numberz {
204 // ...
205}
206
207```
208
209### Containers
210
211Thrift has three container types: list, set and map. They are translated into
212Rust `Vec`, `BTreeSet` and `BTreeMap` respectively. Any Thrift type (this
213includes structs, enums and typedefs) can be a list/set element or a map
214key/value.
215
216#### List
217
218```thrift
219list <i32> numbers
220```
221
222```rust
223numbers: Vec<i32>
224```
225
226#### Set
227
228```thrift
229set <i32> numbers
230```
231
232```rust
233numbers: BTreeSet<i32>
234```
235
236#### Map
237
238```thrift
239map <string, i32> numbers
240```
241
242```rust
243numbers: BTreeMap<String, i32>
244```
245
246### Structs
247
248A Thrift struct is represented as a Rust struct, and each field transcribed 1:1.
249
250```thrift
251struct CrazyNesting {
252 1: string string_field,
253 2: optional set<Insanity> set_field,
254 3: required list<
255 map<set<i32>, map<i32,set<list<map<Insanity,string>>>>>
256 >
257 4: binary binary_field
258}
259```
260```rust
261#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
262pub struct CrazyNesting {
263 pub string_field: Option<String>,
264 pub set_field: Option<BTreeSet<Insanity>>,
265 pub list_field: Vec<
266 BTreeMap<
267 BTreeSet<i32>,
268 BTreeMap<i32, BTreeSet<Vec<BTreeMap<Insanity, String>>>>
269 >
270 >,
271 pub binary_field: Option<Vec<u8>>,
272}
273
274impl CrazyNesting {
275 pub fn read_from_in_protocol(i_prot: &mut TInputProtocol)
276 ->
277 thrift::Result<CrazyNesting> {
278 // ...
279 }
280 pub fn write_to_out_protocol(&self, o_prot: &mut TOutputProtocol)
281 ->
282 thrift::Result<()> {
283 // ...
284 }
285}
286
287```
288##### Optionality
289
290Thrift has 3 "optionality" types:
291
2921. Required
2932. Optional
2943. Default
295
296The Rust code generator encodes *Required* fields as the bare type itself, while
297*Optional* and *Default* fields are encoded as `Option<TypeName>`.
298
299```thrift
300struct Foo {
301 1: required string bar // 1. required
302 2: optional string baz // 2. optional
303 3: string qux // 3. default
304}
305```
306
307```rust
308pub struct Foo {
309 bar: String, // 1. required
310 baz: Option<String>, // 2. optional
311 qux: Option<String>, // 3. default
312}
313```
314
315## Known Issues
316
317* Struct constants are not supported
318* Map, list and set constants require a const holder struct