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