├── .gitignore ├── .travis.yml ├── Cargo.toml ├── Makefile ├── Readme.md ├── src ├── bin │ └── thrust.rs ├── binary_protocol.rs ├── dispatcher.rs ├── event_loop.rs ├── lib.rs ├── protocol.rs ├── reactor.rs ├── result.rs ├── runner.rs ├── service.rs ├── testing.rs ├── transport.rs └── util.rs ├── tests ├── namespace.rs └── struct.rs ├── thrust-codegen ├── Cargo.toml └── src │ └── lib.rs ├── thrust-examples ├── Cargo.toml ├── main.thrift └── src │ ├── foobar.rs │ ├── foobar1.rs │ └── lib.rs ├── thrust-macros-test ├── Cargo.toml └── src │ └── lib.rs ├── thrust-macros ├── Cargo.toml └── src │ └── lib.rs └── thrust-parser ├── Cargo.toml └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | matrix: 3 | include: 4 | - rust: nightly 5 | env: TEST_SUITE=suite_nightly 6 | script: 7 | - cargo build --verbose 8 | - cargo test --verbose 9 | - cd thrust-parser && cargo test --verbose && cd .. 10 | - cd thrust-macros && cargo test --verbose && cd .. 11 | - cd thrust-macros-test && cargo test --verbose && cd .. 12 | - if [ "$TEST_SUITE" = "suite_nightly" ]; then cargo bench --verbose; fi 13 | after_success: | 14 | [ $TRAVIS_BRANCH = master ] && 15 | [ $TRAVIS_PULL_REQUEST = false ] && 16 | cargo doc && 17 | echo "" > target/doc/index.html && 18 | sudo pip install ghp-import && 19 | ghp-import -n target/doc && 20 | git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages 21 | env: 22 | global: 23 | secure: R/VUiFqpQX5wA1aeK8GasWjBQQd4XvpmktacItZ885tNvjOZvj6sGs9OOnpj0fiMgbO8csUBlVcprPRUyl0B+QxuetWZAcNf09sPqR2eQrtU94p3f2Ce41SHqHGaz1tLdnIUHjjm+F8FM514tDMPY3GXeScqSyl68obtMpJf/pU= 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "thrust" 3 | version = "0.1.0" 4 | description = "Thrift for Rust" 5 | documentation = "https://thehydroimpulse.github.io/thrust/thrust/index.html" 6 | homepage = "https://github.com/thehydroimpulse/thrust" 7 | repository = "https://github.com/thehydroimpulse/thrust" 8 | readme = "Readme.md" 9 | keywords = ["thrift", "rpc", "async", "networking"] 10 | license = "MIT" 11 | authors = ["Daniel Fagnan "] 12 | 13 | [dependencies] 14 | byteorder = "0.4" 15 | docopt = "0.6" 16 | rustc-serialize = "0.3" 17 | lazy_static = "0.1.*" 18 | tangle = "0.4.0" 19 | rand = "0.3" 20 | slab = "0.1.3" 21 | num_cpus = "0.2" 22 | libc = "0.2" 23 | 24 | [dependencies.mio] 25 | git = "https://github.com/carllerche/mio" 26 | 27 | [dependencies.bytes] 28 | git = "https://github.com/carllerche/bytes" 29 | 30 | [dependencies.thrust_codegen] 31 | path = "thrust-codegen" 32 | 33 | [dependencies.thrust_parser] 34 | path = "thrust-parser" 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | echo Nothing to do... 3 | 4 | docs: 5 | cargo doc 6 | in-dir ./target/doc fix-perms 7 | rscp ./target/doc/* gopher:~/www/burntsushi.net/rustdoc/ 8 | 9 | push: 10 | git push origin master 11 | git push github master 12 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Thrust [![Build Status](https://travis-ci.org/thehydroimpulse/thrust.svg?branch=master)](https://travis-ci.org/thehydroimpulse/thrust) 2 | 3 | **Note:** A work in progress. It's not in a useful state right now. 4 | 5 | A Rust implementation of the [Apache Thrift](https://thrift.apache.org/) protocol that simplifies communicating between independent systems that may be implemented in various languages. 6 | 7 | ## Features 8 | 9 | - Scalable Thrift RPC 10 | - Rust code generator from a `.thrift` file. 11 | - Built on-top of Asynchronous I/O via Mio. 12 | - Heavily uses Futures to manage asynchronous code. 13 | - Multiplexing multiple RPC services on a single event-loop. 14 | - (Currently limited to one for now) Automatically spawn an `EventLoop` per CPU core. 15 | 16 | ## Installing 17 | 18 | ```toml 19 | [dependencies] 20 | thrust = "*" 21 | ``` 22 | 23 | You may also want to install the code generator using Cargo: 24 | 25 | ```bash 26 | cargo install thrust 27 | ``` 28 | 29 | ## Generating Rust Code 30 | 31 | Thrust comes with a `thrust` binary that compiles your `.thrift` files into Rust code. 32 | 33 | ```bash 34 | thrust hello.thrift . 35 | ``` 36 | 37 | The first argument is the input thrift file and the second is the *path* where you want your 38 | Rust file to be written to. The filename will be based on the Rust namespace in your thrift file `namespace rust `. 39 | 40 | ## Spawning The Reactor 41 | 42 | All the I/O and networking is built using Mio. By default, a single Reactor is spun up globally. Support for multiple event loops/Reactors are supported but not working correctly right now. 43 | 44 | ```rust 45 | use thrust::Reactor; 46 | 47 | fn main() { 48 | // Run the reactor that multiplexes many clients and servers. 49 | Reactor::run(); 50 | } 51 | ``` 52 | 53 | ## Creating a Thrift Service 54 | 55 | Thrust supports creating Thrift services, backed by non-blocking TCP sockets with Mio. 56 | 57 | ```thrift 58 | namespace rust thrift; 59 | // Start by defining a service in your Thrift file. 60 | service Flock { 61 | bool isLoggedIn(1: string token); 62 | } 63 | ``` 64 | 65 | After using Thrust to generate the service in Rust, we can start using it. 66 | 67 | ```rust 68 | extern crate thrust; 69 | // Tangle is a futures implementation 70 | extern crate tangle; 71 | 72 | // The generated Rust module. 73 | use thrift::Flock; 74 | 75 | use thrust::{Reactor, Server}; 76 | use tangle::{Future, Async}; 77 | 78 | pub struct FlockService; 79 | 80 | impl Flock for FlockService { 81 | fn isLoggedIn(&mut self, token: String) -> Future { 82 | if &*token == "123" { 83 | Async::Ok(true) 84 | } else { 85 | Async::Ok(false) 86 | } 87 | } 88 | } 89 | 90 | fn main() { 91 | let addr: SocketAddr = "127.0.0.1:7899".parse().unwrap(); 92 | 93 | // Asynchronously bind the server to the specified port. This does 94 | // not block the current thread. 95 | Server::new(FlockService).bind(addr); 96 | 97 | // Run the Reactor with the server. 98 | Reactor::run(); 99 | } 100 | ``` 101 | 102 | ## Connecting to a Service 103 | 104 | A client is automatically generated for each service you define in your `.thrift` file. Let's keep using our previously defined service as an example. 105 | 106 | ```rust 107 | extern crate thrust; 108 | // Tangle is a futures implementation 109 | extern crate tangle; 110 | 111 | // The generated Rust module. 112 | use thrift::{Flock, Client}; 113 | 114 | use thrust::Reactor; 115 | use tangle::{Future, Async}; 116 | 117 | fn main() { 118 | let addr: SocketAddr = "127.0.0.1:7899".parse().unwrap(); 119 | 120 | // Connect to the service 121 | let flock = Client::connect(addr); 122 | 123 | // Initiate an RPC call 124 | flock.isLoggedIn("123").and_then(move |is| { 125 | if is == true { 126 | println!("You're logged in!") 127 | } else { 128 | println!("Nada"); 129 | } 130 | 131 | Async::Ok(()) 132 | }); 133 | 134 | // Just as before, running the Reactor is required. 135 | Reactor::run(); 136 | } 137 | ``` 138 | 139 | Remember, Thrust is built using asynchronous primitives and futures are currently the common language for asynchronous tasks. Futures prevent much of the problems in traditional callback-based systems. 140 | 141 | ```rust 142 | enum Error { 143 | AccessDenied 144 | } 145 | 146 | flock.isLoggedIn("123").and_then(move |is_logged_in| { 147 | if is_logged_in == true { 148 | Async::Ok(()) 149 | } else { 150 | Async::Err(Error::AccessDenied) 151 | } 152 | }).and_then(move || { 153 | // This will only run if the user has been logged in. Errors 154 | // can be caught later on. 155 | 156 | // ... Do some other fun stuff here. 157 | Async::Ok(()) 158 | }).error(move |err| { 159 | Async::Err(err) 160 | }) 161 | ``` 162 | 163 | ## Sharing Clients 164 | 165 | You might want to share clients across threads and that's perfectly supported! Clients are fully clone-able and are thread-safe. 166 | 167 | ```rust 168 | let shared = client.clone(); 169 | 170 | thread::spawn(move || { 171 | shared... 172 | }) 173 | ``` 174 | 175 | This will re-use the same connection underneath. All TCP connections run in a single Mio event loop (baring multiple event loops). If you wish to use multiple connections, you may create a new client. 176 | 177 | ## License 178 | 179 | MIT — go ham! 180 | -------------------------------------------------------------------------------- /src/bin/thrust.rs: -------------------------------------------------------------------------------- 1 | extern crate thrust_codegen; 2 | extern crate thrust_parser; 3 | extern crate rustc_serialize; 4 | extern crate docopt; 5 | 6 | use docopt::Docopt; 7 | 8 | use std::io::{Write, Read}; 9 | use std::fs::File; 10 | use std::path::Path; 11 | use thrust_parser::Parser; 12 | use thrust_codegen::{compile, find_rust_namespace}; 13 | 14 | const USAGE: &'static str = " 15 | Thrust: Thrift compiler for Rust 16 | 17 | Usage: 18 | thrust 19 | thrust --version 20 | 21 | Options: 22 | -h --help Show this screen. 23 | --version Show version. 24 | "; 25 | 26 | #[derive(Debug, RustcDecodable)] 27 | struct Args { 28 | arg_input: String, 29 | arg_output: String 30 | } 31 | 32 | fn main() { 33 | let args: Args = Docopt::new(USAGE) 34 | .and_then(|d| d.decode()) 35 | .unwrap_or_else(|e| e.exit()); 36 | 37 | println!("{:?}", args); 38 | 39 | let mut input = File::open(args.arg_input).expect("input file does not exist."); 40 | let mut s = String::new(); 41 | input.read_to_string(&mut s).unwrap(); 42 | let mut parser = Parser::new(&s); 43 | let ns = find_rust_namespace(&mut parser).unwrap(); 44 | 45 | let module = Path::new(&args.arg_output).join(ns.module).with_extension("rs"); 46 | let mut output = File::create(module).expect("error creating the module."); 47 | 48 | compile(&mut parser, &mut output).unwrap(); 49 | // println!("{}", String::from_utf8(buf).unwrap()); 50 | // let mut file = File::create("src/testing.rs").unwrap(); 51 | // file.write_all(&buf[..]).unwrap(); 52 | } 53 | -------------------------------------------------------------------------------- /src/binary_protocol.rs: -------------------------------------------------------------------------------- 1 | use protocol::{Serializer, Deserializer, ThriftSerializer, ThriftField, ThriftMessage, ThriftDeserializer, ThriftMessageType, ThriftType, Error}; 2 | use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; 3 | use std::io::{self, Read, Write}; 4 | use std::iter; 5 | use byteorder; 6 | use std::convert; 7 | 8 | pub const THRIFT_VERSION_1: i32 = 0x80010000; 9 | pub const THRIFT_VERSION_MASK: i32 = 0xffff0000; 10 | pub const THRIFT_TYPE_MASK: i32 = 0x000000ff; 11 | 12 | pub struct BinarySerializer<'a> { 13 | wr: &'a mut Write 14 | } 15 | 16 | impl<'a> BinarySerializer<'a> { 17 | pub fn new(wr: &'a mut Write) -> BinarySerializer<'a> { 18 | BinarySerializer { 19 | wr: wr 20 | } 21 | } 22 | } 23 | 24 | impl<'a> Serializer for BinarySerializer<'a> { 25 | 26 | fn serialize_bool(&mut self, val: bool) -> Result<(), Error> { 27 | if val { 28 | self.serialize_i8(1) 29 | } else { 30 | self.serialize_i8(0) 31 | } 32 | } 33 | 34 | fn serialize_usize(&mut self, val: usize) -> Result<(), Error> { 35 | self.serialize_isize(val as isize) 36 | } 37 | 38 | fn serialize_isize(&mut self, val: isize) -> Result<(), Error> { 39 | self.serialize_i64(val as i64) 40 | } 41 | 42 | fn serialize_u64(&mut self, val: u64) -> Result<(), Error> { 43 | self.serialize_i64(val as i64) 44 | } 45 | 46 | fn serialize_i64(&mut self, val: i64) -> Result<(), Error> { 47 | try!(self.wr.write_i64::(val)); 48 | Ok(()) 49 | } 50 | 51 | fn serialize_u32(&mut self, val: u32) -> Result<(), Error> { 52 | self.serialize_i32(val as i32) 53 | } 54 | 55 | fn serialize_i32(&mut self, val: i32) -> Result<(), Error> { 56 | try!(self.wr.write_i32::(val)); 57 | Ok(()) 58 | } 59 | 60 | fn serialize_u16(&mut self, val: u16) -> Result<(), Error> { 61 | self.serialize_i16(val as i16) 62 | } 63 | 64 | fn serialize_i16(&mut self, val: i16) -> Result<(), Error> { 65 | try!(self.wr.write_i16::(val)); 66 | Ok(()) 67 | } 68 | 69 | fn serialize_u8(&mut self, val: u8) -> Result<(), Error> { 70 | self.serialize_i8(val as i8) 71 | } 72 | 73 | fn serialize_i8(&mut self, val: i8) -> Result<(), Error> { 74 | try!(self.wr.write_i8(val)); 75 | Ok(()) 76 | } 77 | 78 | fn serialize_bytes(&mut self, val: &[u8]) -> Result<(), Error> { 79 | self.serialize_i32(val.len() as i32); 80 | try!(self.wr.write(val)); 81 | Ok(()) 82 | } 83 | 84 | fn serialize_str(&mut self, val: &str) -> Result<(), Error> { 85 | self.serialize_bytes(val.as_bytes()) 86 | } 87 | 88 | fn serialize_string(&mut self, val: String) -> Result<(), Error> { 89 | self.serialize_str(&*val) 90 | } 91 | } 92 | 93 | impl<'a> ThriftSerializer for BinarySerializer<'a> { 94 | fn write_message_begin(&mut self, name: &str, message_type: ThriftMessageType) -> Result<(), Error> { 95 | let version = THRIFT_VERSION_1 | message_type as i32; 96 | 97 | try!(self.serialize_i32(version)); 98 | try!(self.serialize_str(name)); 99 | try!(self.serialize_i16(0)); 100 | 101 | Ok(()) 102 | } 103 | 104 | fn write_struct_begin(&mut self, name: &str) -> Result<(), Error> { 105 | Ok(()) 106 | } 107 | 108 | fn write_struct_end(&mut self) -> Result<(), Error> { 109 | Ok(()) 110 | } 111 | 112 | fn write_field_begin(&mut self, name: &str, ty: ThriftType, id: i16) -> Result<(), Error> { 113 | try!(self.serialize_i8(ty as i8)); 114 | try!(self.serialize_i16(id)); 115 | Ok(()) 116 | } 117 | 118 | fn write_field_end(&mut self) -> Result<(), Error> { 119 | Ok(()) 120 | } 121 | 122 | fn write_field_stop(&mut self) -> Result<(), Error> { 123 | try!(self.serialize_i8(ThriftType::Stop as i8)); 124 | Ok(()) 125 | } 126 | 127 | fn write_message_end(&mut self) -> Result<(), Error> { 128 | Ok(()) 129 | } 130 | } 131 | 132 | pub struct BinaryDeserializer { 133 | rd: R 134 | } 135 | 136 | impl BinaryDeserializer { 137 | pub fn new(rd: R) -> BinaryDeserializer { 138 | BinaryDeserializer { 139 | rd: rd 140 | } 141 | } 142 | } 143 | 144 | impl Deserializer for BinaryDeserializer { 145 | fn deserialize_bool(&mut self) -> Result { 146 | Ok(try!(self.rd.read_i8()) != 0) 147 | } 148 | 149 | fn deserialize_usize(&mut self) -> Result { 150 | Ok(try!(self.deserialize_isize()) as usize) 151 | } 152 | 153 | fn deserialize_isize(&mut self) -> Result { 154 | Ok(try!(self.deserialize_i64()) as isize) 155 | } 156 | 157 | fn deserialize_u64(&mut self) -> Result { 158 | Ok(try!(self.deserialize_i64()) as u64) 159 | } 160 | 161 | fn deserialize_i64(&mut self) -> Result { 162 | Ok(try!(self.rd.read_i64::())) 163 | } 164 | 165 | fn deserialize_u32(&mut self) -> Result { 166 | Ok(try!(self.deserialize_i32()) as u32) 167 | } 168 | 169 | fn deserialize_i32(&mut self) -> Result { 170 | Ok(try!(self.rd.read_i32::())) 171 | } 172 | 173 | fn deserialize_u16(&mut self) -> Result { 174 | Ok(try!(self.deserialize_i16()) as u16) 175 | } 176 | 177 | fn deserialize_i16(&mut self) -> Result { 178 | Ok(try!(self.rd.read_i16::())) 179 | } 180 | 181 | fn deserialize_u8(&mut self) -> Result { 182 | Ok(try!(self.deserialize_i8()) as u8) 183 | } 184 | 185 | fn deserialize_i8(&mut self) -> Result { 186 | Ok(try!(self.rd.read_i8())) 187 | } 188 | 189 | fn deserialize_bytes(&mut self) -> Result, Error> { 190 | let len = try!(self.deserialize_i32()) as usize; 191 | let mut buf = Vec::with_capacity(len); 192 | 193 | buf.extend(iter::repeat(0).take(len)); 194 | try!(self.rd.read(&mut buf)); 195 | 196 | Ok(buf) 197 | } 198 | 199 | fn deserialize_str(&mut self) -> Result { 200 | let buf = try!(self.deserialize_bytes()); 201 | let s = try!(String::from_utf8(buf)); 202 | Ok(s) 203 | } 204 | } 205 | 206 | impl ThriftDeserializer for BinaryDeserializer { 207 | fn read_message_begin(&mut self) -> Result { 208 | let size: i32 = try!(self.deserialize_i32()); 209 | 210 | if size < 0 { 211 | let version = size & THRIFT_VERSION_MASK; 212 | if version != THRIFT_VERSION_1 { 213 | Err(Error::BadVersion) 214 | } else { 215 | Ok(ThriftMessage { 216 | name: try!(self.deserialize_str()), 217 | ty: ThriftMessageType::from((size & THRIFT_TYPE_MASK) as i8), 218 | seq: try!(self.deserialize_i16()) 219 | }) 220 | } 221 | } else { 222 | Err(Error::ProtocolVersionMissing) 223 | } 224 | } 225 | 226 | fn read_message_end(&mut self) -> Result<(), Error> { 227 | Ok(()) 228 | } 229 | 230 | fn read_struct_begin(&mut self) -> Result { 231 | Ok("".to_string()) 232 | } 233 | 234 | fn read_struct_end(&mut self) -> Result<(), Error> { 235 | Ok(()) 236 | } 237 | 238 | fn read_field_begin(&mut self) -> Result { 239 | let mut field = ThriftField { 240 | name: None, 241 | ty: ThriftType::from(try!(self.deserialize_i8())), 242 | seq: 0 243 | }; 244 | 245 | if field.ty == ThriftType::Stop { 246 | Ok(field) 247 | } else { 248 | field.seq = try!(self.deserialize_i16()); 249 | Ok(field) 250 | } 251 | } 252 | 253 | fn read_field_end(&mut self) -> Result<(), Error> { 254 | Ok(()) 255 | } 256 | } 257 | 258 | #[cfg(test)] 259 | mod tests { 260 | use std::io::{Cursor, Read}; 261 | use byteorder::{ReadBytesExt, BigEndian}; 262 | use protocol::{ThriftMessageType, ThriftType, ThriftMessage, ThriftDeserializer, ThriftSerializer, Serializer, Serialize, Deserializer}; 263 | use super::*; 264 | 265 | #[test] 266 | fn serialize_bool_true() { 267 | let mut v = Vec::new(); 268 | { 269 | let mut s = BinarySerializer::new(&mut v); 270 | s.serialize_bool(true); 271 | } 272 | 273 | assert_eq!(v[0], 1); 274 | } 275 | 276 | #[test] 277 | fn serialize_bool_false() { 278 | let mut v = Vec::new(); 279 | { 280 | let mut s = BinarySerializer::new(&mut v); 281 | s.serialize_bool(false); 282 | } 283 | 284 | assert_eq!(v[0], 0); 285 | } 286 | 287 | #[test] 288 | fn serialize_i8() { 289 | let mut v = Vec::new(); 290 | { 291 | let mut s = BinarySerializer::new(&mut v); 292 | s.serialize_i8(5); 293 | } 294 | 295 | assert_eq!(v[0], 5); 296 | } 297 | 298 | #[test] 299 | fn serialize_i8_neg() { 300 | let mut v = Vec::new(); 301 | { 302 | let mut s = BinarySerializer::new(&mut v); 303 | s.serialize_i8(-5); 304 | } 305 | 306 | assert_eq!(v[0] as i8, -5); 307 | } 308 | 309 | #[test] 310 | fn serialize_i16() { 311 | let mut v = Vec::new(); 312 | { 313 | let mut s = BinarySerializer::new(&mut v); 314 | s.serialize_i16(900); 315 | } 316 | 317 | let mut cursor = Cursor::new(v); 318 | assert_eq!(900, cursor.read_i16::().unwrap()); 319 | } 320 | 321 | #[test] 322 | fn serialize_i16_neg() { 323 | let mut v = Vec::new(); 324 | { 325 | let mut s = BinarySerializer::new(&mut v); 326 | s.serialize_i16(-900); 327 | } 328 | 329 | let mut cursor = Cursor::new(v); 330 | assert_eq!(-900, cursor.read_i16::().unwrap()); 331 | } 332 | 333 | #[test] 334 | fn serialize_i32() { 335 | let mut v = Vec::new(); 336 | { 337 | let mut s = BinarySerializer::new(&mut v); 338 | s.serialize_i32(3000000); 339 | } 340 | 341 | let mut cursor = Cursor::new(v); 342 | assert_eq!(3000000, cursor.read_i32::().unwrap()); 343 | } 344 | 345 | #[test] 346 | fn serialize_i32_neg() { 347 | let mut v = Vec::new(); 348 | { 349 | let mut s = BinarySerializer::new(&mut v); 350 | s.serialize_i32(-3000000); 351 | } 352 | 353 | let mut cursor = Cursor::new(v); 354 | assert_eq!(-3000000, cursor.read_i32::().unwrap()); 355 | } 356 | 357 | #[test] 358 | fn serialize_i64() { 359 | let mut v = Vec::new(); 360 | { 361 | let mut s = BinarySerializer::new(&mut v); 362 | s.serialize_i64(33000000); 363 | } 364 | 365 | let mut cursor = Cursor::new(v); 366 | assert_eq!(33000000, cursor.read_i64::().unwrap()); 367 | } 368 | 369 | #[test] 370 | fn serialize_i64_neg() { 371 | let mut v = Vec::new(); 372 | { 373 | let mut s = BinarySerializer::new(&mut v); 374 | s.serialize_i64(-33000000); 375 | } 376 | 377 | let mut cursor = Cursor::new(v); 378 | assert_eq!(-33000000, cursor.read_i64::().unwrap()); 379 | } 380 | 381 | #[test] 382 | fn protocol_begin() { 383 | let mut v = Vec::new(); 384 | { 385 | let mut proto = BinarySerializer::new(&mut v); 386 | proto.write_message_begin("foobar", ThriftMessageType::Call); 387 | } 388 | 389 | let mut cursor = Cursor::new(v); 390 | let version = THRIFT_VERSION_1 | ThriftMessageType::Call as i32; 391 | 392 | assert_eq!(version, cursor.read_i32::().unwrap()); 393 | // XXX Decode string and seqid. 394 | } 395 | 396 | #[test] 397 | fn write_and_read_message_begin() { 398 | let mut buf = Vec::new(); 399 | 400 | { 401 | let mut se = BinarySerializer::new(&mut buf); 402 | se.write_message_begin("Foobar123", ThriftMessageType::Call); 403 | } 404 | 405 | let mut de = BinaryDeserializer::new(Cursor::new(buf)); 406 | let msg = de.read_message_begin().unwrap(); 407 | 408 | assert_eq!(msg.name, "Foobar123"); 409 | assert_eq!(msg.ty, ThriftMessageType::Call); 410 | } 411 | } 412 | -------------------------------------------------------------------------------- /src/dispatcher.rs: -------------------------------------------------------------------------------- 1 | use std::sync::mpsc::{Sender, Receiver, channel}; 2 | use std::collections::HashMap; 3 | use std::thread::{self, JoinHandle}; 4 | use event_loop::SENDER; 5 | use std::net::SocketAddr; 6 | use mio::{self, Token}; 7 | use result::{ThrustResult, ThrustError}; 8 | use tangle::{Future, Async}; 9 | use std::io::Cursor; 10 | use protocol::*; 11 | use binary_protocol::*; 12 | use reactor::{self, Dispatch, Message, Id}; 13 | use util; 14 | use runner::Runner; 15 | 16 | pub enum Role { 17 | /// A server will be tasked with actually calling a user defined 18 | /// RPC method and dispatching the response back to the event loop. 19 | Server(SocketAddr, Sender<(Token, Vec)>), 20 | /// A client is tasked with sending an initial RPC and dispatching a response. 21 | /// 22 | Client(SocketAddr) 23 | } 24 | 25 | pub enum Incoming { 26 | /// Method name, data buf, and response channel. 27 | Call(String, Vec, Option>>)>>), 28 | Reply(Token, Vec), 29 | Shutdown 30 | } 31 | 32 | /// A middleman between incoming and outgoing messages from the event loop and 33 | /// clients or servers. Each instance of a server or client has it's own Dispatcher. 34 | /// 35 | /// Dispatchers run in their own thread and only expose a channel interface. This makes it 36 | /// extremely easy to do multi-threading by simply cloning the dispatcher. 37 | pub struct Dispatcher { 38 | role: Role, 39 | /// The connection token as used and exposed by the event loop. This is required 40 | /// to know where to send and receive Rpc calls. 41 | token: Token, 42 | data_rx: Receiver, 43 | /// The channel to communicate with the event loop. 44 | event_loop: mio::Sender, 45 | rx: Receiver, 46 | /// The response queue that is used to match up outgoing requests with future 47 | /// responses. Each response has it's own sender channel. 48 | queue: HashMap>>)>> 49 | } 50 | 51 | impl Dispatcher { 52 | pub fn spawn(role: Role) -> ThrustResult<(JoinHandle>, Sender)> { 53 | let (ret_tx, ret_rx) = channel(); 54 | let handle = thread::spawn(move || { 55 | let (sender, receiver) = channel(); 56 | ret_tx.send(sender); 57 | 58 | let (id_tx, id_rx) = channel(); 59 | let event_loop_sender = SENDER.clone(); 60 | let (data_tx, data_rx) = channel(); 61 | 62 | match &role { 63 | &Role::Server(addr, ref method_dispatch) => { 64 | event_loop_sender.send(Message::Bind(addr, id_tx, data_tx))?; 65 | }, 66 | &Role::Client(addr) => { 67 | event_loop_sender.send(Message::Connect(addr, id_tx, data_tx))?; 68 | } 69 | } 70 | 71 | let Id(token) = id_rx.recv()?; 72 | 73 | Dispatcher { 74 | role: role, 75 | token: token, 76 | data_rx: data_rx, 77 | event_loop: event_loop_sender, 78 | rx: receiver, 79 | queue: HashMap::new() 80 | }.run() 81 | }); 82 | 83 | Ok((handle, ret_rx.recv()?)) 84 | } 85 | 86 | pub fn run(mut self) -> ThrustResult<()> { 87 | let rx = self.rx; 88 | let event_loop_rx = self.data_rx; 89 | 90 | loop { 91 | select! { 92 | user_msg = rx.recv() => { 93 | match user_msg { 94 | Ok(Incoming::Shutdown) => break, 95 | Ok(Incoming::Call(method, buf, tx)) => { 96 | self.event_loop.send(Message::Rpc(self.token, buf)); 97 | match tx { 98 | Some(tx) => { 99 | self.queue.insert(method, tx); 100 | }, 101 | None => {} 102 | } 103 | }, 104 | Ok(Incoming::Reply(token, buf)) => { 105 | self.event_loop.send(Message::Rpc(token, buf)); 106 | }, 107 | // The sender-part of the channel has been disconnected. 108 | Err(err) => break 109 | } 110 | }, 111 | event_loop_msg = event_loop_rx.recv() => { 112 | match event_loop_msg { 113 | Ok(Dispatch::Data(token, buf)) => { 114 | println!("[dispatcher]: reading data from {:?}", token); 115 | match self.role { 116 | // Received an RPC call 117 | Role::Server(_, ref sender) => { 118 | try!(sender.send((token, buf))); 119 | }, 120 | // Received a reply RPC call 121 | Role::Client(_) => { 122 | let mut de = BinaryDeserializer::new(Cursor::new(buf)); 123 | let msg = de.read_message_begin()?; 124 | 125 | match self.queue.remove(&msg.name) { 126 | Some(tx) => { 127 | println!("[dispatcher/client]: reply received."); 128 | tx.send((msg, de))?; 129 | }, 130 | None => { println!("Cannot find {:?} method name", msg.name); } 131 | } 132 | } 133 | } 134 | }, 135 | Err(err) => break 136 | } 137 | } 138 | } 139 | } 140 | 141 | Ok(()) 142 | } 143 | } 144 | 145 | #[cfg(test)] 146 | mod tests { 147 | use super::*; 148 | use tangle::{Future, Async}; 149 | use std::net::SocketAddr; 150 | use std::io::Cursor; 151 | use reactor::{Reactor, Message}; 152 | use event_loop::SENDER; 153 | use protocol::{ThriftMessage, ThriftMessageType}; 154 | use binary_protocol::BinaryDeserializer; 155 | use std::sync::mpsc::channel; 156 | use util; 157 | use std::thread; 158 | use std::time::Duration; 159 | 160 | #[test] 161 | fn should_create_server_dispatcher() { 162 | let addr = "127.0.0.1:5495".parse().unwrap(); 163 | let (tx, rx) = channel(); 164 | let (handle, tx) = Dispatcher::spawn(Role::Server(addr, tx)).unwrap(); 165 | } 166 | 167 | #[test] 168 | fn should_start_server() { 169 | let addr: SocketAddr = "127.0.0.1:5955".parse().unwrap(); 170 | let (method_dispatch_tx, method_dispatch_rx) = channel(); 171 | let (handle_server, server) = Dispatcher::spawn(Role::Server(addr.clone(), method_dispatch)).unwrap(); 172 | thread::sleep(Duration::from_millis(30)); 173 | let (handle_client, client) = Dispatcher::spawn(Role::Client(addr.clone())).unwrap(); 174 | 175 | let buf = util::create_empty_thrift_message("foobar123", ThriftMessageType::Call); 176 | 177 | let (res, future) = Future::<(ThriftMessage, BinaryDeserializer>>)>::channel(); 178 | client.send(Incoming::Call("foobar123".to_string(), buf, Some(res))).unwrap(); 179 | 180 | let (res_tx, res_rx) = channel(); 181 | let cloned = res_tx.clone(); 182 | future.and_then(move |(msg, de)| { 183 | println!("[test]: Received: {:?}", msg); 184 | SENDER.clone().send(Message::Shutdown); 185 | res_tx.send(0); 186 | Async::Ok(()) 187 | }); 188 | 189 | // Ensure that the test exists after at least 3 seconds if the response was not 190 | // received. 191 | thread::spawn(move || -> Result<(), ()> { 192 | thread::sleep(Duration::from_millis(3000)); 193 | SENDER.clone().send(Message::Shutdown); 194 | panic!("Test timeout was hit. This means the Reactor did not shutdown and a response was not received."); 195 | cloned.send(1); 196 | }); 197 | 198 | Reactor::run().join(); 199 | 200 | assert_eq!(res_rx.recv().unwrap(), 0); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/event_loop.rs: -------------------------------------------------------------------------------- 1 | use mio::{EventLoop, Sender}; 2 | use reactor::{Reactor, Message}; 3 | use std::sync::{Arc, Mutex}; 4 | use num_cpus; 5 | 6 | lazy_static! { 7 | /// XXX: We currently cannot have more than one event loop because of the shared socket 8 | /// issue. 9 | pub static ref EVENT_LOOP: Mutex> = { 10 | Mutex::new(EventLoop::new().unwrap()) 11 | }; 12 | 13 | pub static ref SENDER: Sender = { 14 | EVENT_LOOP.lock().unwrap().channel() 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports, unused_variables, dead_code, unused_must_use, unused_mut)] 2 | #![feature(associated_type_defaults, mpsc_select, question_mark)] 3 | 4 | #[macro_use] 5 | extern crate lazy_static; 6 | extern crate mio; 7 | extern crate byteorder; 8 | extern crate tangle; 9 | extern crate rand; 10 | extern crate slab; 11 | extern crate bytes; 12 | extern crate num_cpus; 13 | extern crate libc; 14 | 15 | use std::str; 16 | use std::convert; 17 | use std::string; 18 | 19 | mod util; 20 | mod event_loop; 21 | pub mod reactor; 22 | pub mod protocol; 23 | pub mod binary_protocol; 24 | // mod service; 25 | mod runner; 26 | pub mod dispatcher; 27 | mod result; 28 | mod transport; 29 | 30 | pub use reactor::Reactor; 31 | pub use runner::Runner; 32 | pub use result::{ThrustResult, ThrustError}; 33 | pub use protocol::{Serializer, Serialize, Deserialize, ThriftSerializer, ThriftDeserializer}; 34 | -------------------------------------------------------------------------------- /src/protocol.rs: -------------------------------------------------------------------------------- 1 | use std::io::{self, Read, Write}; 2 | use std::convert; 3 | use byteorder; 4 | use std::string::FromUtf8Error; 5 | 6 | #[derive(Debug)] 7 | pub enum Error { 8 | Byteorder(byteorder::Error), 9 | Io(io::Error), 10 | Utf8Error(FromUtf8Error), 11 | BadVersion, 12 | ProtocolVersionMissing 13 | } 14 | 15 | impl convert::From for Error { 16 | fn from(err: byteorder::Error) -> Error { 17 | Error::Byteorder(err) 18 | } 19 | } 20 | 21 | impl convert::From for Error { 22 | fn from(err: FromUtf8Error) -> Error { 23 | Error::Utf8Error(err) 24 | } 25 | } 26 | 27 | impl convert::From for Error { 28 | fn from(err: io::Error) -> Error { 29 | Error::Io(err) 30 | } 31 | } 32 | 33 | #[derive(PartialEq, Eq, Debug)] 34 | pub enum ThriftType { 35 | Stop = 0, 36 | Void = 1, 37 | Bool = 2, 38 | Byte = 3, 39 | Double = 4, 40 | I16 = 6, 41 | I32 = 8, 42 | U64 = 9, 43 | I64 = 10, 44 | String = 11, 45 | Struct = 12, 46 | Map = 13, 47 | Set = 14, 48 | List = 15 49 | } 50 | 51 | impl convert::From for ThriftType { 52 | fn from(val: i8) -> ThriftType { 53 | match val { 54 | 0 => ThriftType::Stop, 55 | 1 => ThriftType::Void, 56 | 2 => ThriftType::Bool, 57 | 3 => ThriftType::Byte, 58 | 4 => ThriftType::Double, 59 | 6 => ThriftType::I16, 60 | 8 => ThriftType::I32, 61 | 9 => ThriftType::U64, 62 | 10 => ThriftType::I64, 63 | 11 => ThriftType::String, 64 | 12 => ThriftType::Struct, 65 | 13 => ThriftType::Map, 66 | 14 => ThriftType::Set, 67 | 15 => ThriftType::List, 68 | e => panic!("Unexpected value: {}", e) 69 | } 70 | } 71 | } 72 | 73 | #[derive(PartialEq, Eq, Debug)] 74 | pub enum ThriftMessageType { 75 | Call = 1, 76 | Reply = 2, 77 | Exception = 3, 78 | Oneway = 4 79 | } 80 | 81 | impl convert::From for ThriftMessageType { 82 | fn from(val: i8) -> ThriftMessageType { 83 | match val { 84 | 1 => ThriftMessageType::Call, 85 | 2 => ThriftMessageType::Reply, 86 | 3 => ThriftMessageType::Exception, 87 | 4 => ThriftMessageType::Oneway, 88 | _ => panic!("Unexpected value for ThriftMessageType.") 89 | } 90 | } 91 | } 92 | 93 | pub trait Serializer { 94 | fn serialize_bool(&mut self, val: bool) -> Result<(), Error>; 95 | fn serialize_str(&mut self, val: &str) -> Result<(), Error>; 96 | fn serialize_string(&mut self, val: String) -> Result<(), Error>; 97 | fn serialize_usize(&mut self, val: usize) -> Result<(), Error>; 98 | fn serialize_isize(&mut self, val: isize) -> Result<(), Error>; 99 | fn serialize_u64(&mut self, val: u64) -> Result<(), Error>; 100 | fn serialize_i64(&mut self, val: i64) -> Result<(), Error>; 101 | fn serialize_i32(&mut self, val: i32) -> Result<(), Error>; 102 | fn serialize_u32(&mut self, val: u32) -> Result<(), Error>; 103 | fn serialize_i16(&mut self, val: i16) -> Result<(), Error>; 104 | fn serialize_u16(&mut self, val: u16) -> Result<(), Error>; 105 | fn serialize_u8(&mut self, val: u8) -> Result<(), Error>; 106 | fn serialize_i8(&mut self, val: i8) -> Result<(), Error>; 107 | fn serialize_bytes(&mut self, val: &[u8]) -> Result<(), Error>; 108 | } 109 | 110 | pub trait Deserializer { 111 | fn deserialize_bool(&mut self) -> Result; 112 | fn deserialize_usize(&mut self) -> Result; 113 | fn deserialize_isize(&mut self) -> Result; 114 | fn deserialize_u64(&mut self) -> Result; 115 | fn deserialize_i64(&mut self) -> Result; 116 | fn deserialize_u32(&mut self) -> Result; 117 | fn deserialize_i32(&mut self) -> Result; 118 | fn deserialize_u16(&mut self) -> Result; 119 | fn deserialize_i16(&mut self) -> Result; 120 | fn deserialize_u8(&mut self) -> Result; 121 | fn deserialize_i8(&mut self) -> Result; 122 | fn deserialize_bytes(&mut self) -> Result, Error>; 123 | fn deserialize_str(&mut self) -> Result; 124 | } 125 | 126 | pub trait Serialize { 127 | fn serialize(&self, s: &mut S) -> Result<(), Error> where S: Serializer + ThriftSerializer; 128 | } 129 | 130 | pub trait ThriftSerializer { 131 | fn write_message_begin(&mut self, name: &str, message_type: ThriftMessageType) -> Result<(), Error> { 132 | Ok(()) 133 | } 134 | 135 | fn write_struct_begin(&mut self, name: &str) -> Result<(), Error> { 136 | Ok(()) 137 | } 138 | 139 | fn write_struct_end(&mut self) -> Result<(), Error> { 140 | Ok(()) 141 | } 142 | 143 | fn write_field_begin(&mut self, name: &str, ty: ThriftType, id: i16) -> Result<(), Error> { 144 | Ok(()) 145 | } 146 | 147 | fn write_field_end(&mut self) -> Result<(), Error> { 148 | Ok(()) 149 | } 150 | 151 | fn write_field_stop(&mut self) -> Result<(), Error> { 152 | Ok(()) 153 | } 154 | 155 | fn write_message_end(&mut self) -> Result<(), Error> { 156 | Ok(()) 157 | } 158 | } 159 | 160 | #[derive(Debug)] 161 | pub struct ThriftMessage { 162 | pub name: String, 163 | pub ty: ThriftMessageType, 164 | pub seq: i16 165 | } 166 | #[derive(Debug)] 167 | pub struct ThriftField { 168 | pub name: Option, 169 | pub ty: ThriftType, 170 | pub seq: i16 171 | } 172 | 173 | pub trait ThriftDeserializer { 174 | fn read_message_begin(&mut self) -> Result; 175 | fn read_message_end(&mut self) -> Result<(), Error>; 176 | fn read_struct_begin(&mut self) -> Result; 177 | fn read_struct_end(&mut self) -> Result<(), Error>; 178 | fn read_field_begin(&mut self) -> Result; 179 | fn read_field_end(&mut self) -> Result<(), Error>; 180 | } 181 | 182 | pub trait Deserialize: Sized { 183 | fn deserialize(de: &mut D) -> Result where D: Deserializer + ThriftDeserializer; 184 | } 185 | 186 | /// ``` 187 | /// use std::io::Cursor; 188 | /// use thrust::binary_protocol::BinaryDeserializer; 189 | /// use thrust::protocol::Deserialize; 190 | /// 191 | /// let mut de = BinaryDeserializer::new(Cursor::new(vec![100u8])); 192 | /// let val: u8 = Deserialize::deserialize(&mut de).unwrap(); 193 | /// assert_eq!(val, 100); 194 | /// ``` 195 | impl Deserialize for u8 { 196 | fn deserialize(de: &mut D) -> Result 197 | where D: Deserializer + ThriftDeserializer 198 | { 199 | de.deserialize_u8() 200 | } 201 | } 202 | 203 | impl Deserialize for bool { 204 | fn deserialize(de: &mut D) -> Result 205 | where D: Deserializer + ThriftDeserializer 206 | { 207 | de.deserialize_bool() 208 | } 209 | } 210 | 211 | /// ``` 212 | /// use std::io::Cursor; 213 | /// use thrust::binary_protocol::BinaryDeserializer; 214 | /// use thrust::protocol::Deserialize; 215 | /// 216 | /// let mut de = BinaryDeserializer::new(Cursor::new(vec![100u8])); 217 | /// let val: i8 = Deserialize::deserialize(&mut de).unwrap(); 218 | /// assert_eq!(val, 100); 219 | /// ``` 220 | impl Deserialize for i8 { 221 | fn deserialize(de: &mut D) -> Result 222 | where D: Deserializer + ThriftDeserializer 223 | { 224 | de.deserialize_i8() 225 | } 226 | } 227 | 228 | impl Deserialize for u16 { 229 | fn deserialize(de: &mut D) -> Result 230 | where D: Deserializer + ThriftDeserializer 231 | { 232 | de.deserialize_u16() 233 | } 234 | } 235 | 236 | impl Deserialize for i16 { 237 | fn deserialize(de: &mut D) -> Result 238 | where D: Deserializer + ThriftDeserializer 239 | { 240 | de.deserialize_i16() 241 | } 242 | } 243 | 244 | impl Deserialize for u32 { 245 | fn deserialize(de: &mut D) -> Result 246 | where D: Deserializer + ThriftDeserializer 247 | { 248 | de.deserialize_u32() 249 | } 250 | } 251 | 252 | impl Deserialize for i32 { 253 | fn deserialize(de: &mut D) -> Result 254 | where D: Deserializer + ThriftDeserializer 255 | { 256 | de.deserialize_i32() 257 | } 258 | } 259 | 260 | impl Deserialize for u64 { 261 | fn deserialize(de: &mut D) -> Result 262 | where D: Deserializer + ThriftDeserializer 263 | { 264 | de.deserialize_u64() 265 | } 266 | } 267 | 268 | impl Deserialize for i64 { 269 | fn deserialize(de: &mut D) -> Result 270 | where D: Deserializer + ThriftDeserializer 271 | { 272 | de.deserialize_i64() 273 | } 274 | } 275 | 276 | impl Deserialize for String { 277 | fn deserialize(de: &mut D) -> Result 278 | where D: Deserializer + ThriftDeserializer 279 | { 280 | de.deserialize_str() 281 | } 282 | } 283 | 284 | impl Serialize for () { 285 | fn serialize(&self, s: &mut S) -> Result<(), Error> 286 | where S: Serializer + ThriftSerializer 287 | { 288 | Ok(()) 289 | } 290 | } 291 | 292 | impl Serialize for bool { 293 | fn serialize(&self, s: &mut S) -> Result<(), Error> 294 | where S: Serializer + ThriftSerializer 295 | { 296 | s.serialize_bool(*self) 297 | } 298 | } 299 | 300 | impl<'a> Serialize for &'a str { 301 | fn serialize(&self, s: &mut S) -> Result<(), Error> 302 | where S: Serializer + ThriftSerializer 303 | { 304 | s.serialize_str(self) 305 | } 306 | } 307 | 308 | impl Serialize for String { 309 | fn serialize(&self, s: &mut S) -> Result<(), Error> 310 | where S: Serializer + ThriftSerializer 311 | { 312 | s.serialize_string(self.clone()) 313 | } 314 | } 315 | 316 | impl Serialize for usize { 317 | fn serialize(&self, s: &mut S) -> Result<(), Error> 318 | where S: Serializer + ThriftSerializer 319 | { 320 | s.serialize_usize(*self) 321 | } 322 | } 323 | 324 | impl Serialize for isize { 325 | fn serialize(&self, s: &mut S) -> Result<(), Error> 326 | where S: Serializer + ThriftSerializer 327 | { 328 | s.serialize_isize(*self) 329 | } 330 | } 331 | 332 | impl Serialize for u64 { 333 | fn serialize(&self, s: &mut S) -> Result<(), Error> 334 | where S: Serializer + ThriftSerializer 335 | { 336 | s.serialize_u64(*self) 337 | } 338 | } 339 | 340 | impl Serialize for i64 { 341 | fn serialize(&self, s: &mut S) -> Result<(), Error> 342 | where S: Serializer + ThriftSerializer 343 | { 344 | s.serialize_i64(*self) 345 | } 346 | } 347 | 348 | impl Serialize for i32 { 349 | fn serialize(&self, s: &mut S) -> Result<(), Error> 350 | where S: Serializer + ThriftSerializer 351 | { 352 | s.serialize_i32(*self) 353 | } 354 | } 355 | 356 | impl Serialize for u32 { 357 | fn serialize(&self, s: &mut S) -> Result<(), Error> 358 | where S: Serializer + ThriftSerializer 359 | { 360 | s.serialize_u32(*self) 361 | } 362 | } 363 | 364 | impl Serialize for u16 { 365 | fn serialize(&self, s: &mut S) -> Result<(), Error> 366 | where S: Serializer + ThriftSerializer 367 | { 368 | s.serialize_u16(*self) 369 | } 370 | } 371 | 372 | impl Serialize for i16 { 373 | fn serialize(&self, s: &mut S) -> Result<(), Error> 374 | where S: Serializer + ThriftSerializer 375 | { 376 | s.serialize_i16(*self) 377 | } 378 | } 379 | 380 | impl Serialize for i8 { 381 | fn serialize(&self, s: &mut S) -> Result<(), Error> 382 | where S: Serializer + ThriftSerializer 383 | { 384 | s.serialize_i8(*self) 385 | } 386 | } 387 | 388 | impl Serialize for u8 { 389 | fn serialize(&self, s: &mut S) -> Result<(), Error> 390 | where S: Serializer + ThriftSerializer 391 | { 392 | s.serialize_u8(*self) 393 | } 394 | } 395 | 396 | impl<'a> Serialize for &'a [u8] { 397 | fn serialize(&self, s: &mut S) -> Result<(), Error> 398 | where S: Serializer + ThriftSerializer 399 | { 400 | s.serialize_bytes(self) 401 | } 402 | } 403 | 404 | #[cfg(test)] 405 | mod tests { 406 | use super::*; 407 | use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; 408 | use binary_protocol::BinaryDeserializer; 409 | use std::io::{Write, Cursor}; 410 | 411 | #[test] 412 | fn deserialize_bool() { 413 | let mut de = BinaryDeserializer::new(Cursor::new(vec![1u8])); 414 | let val: bool = Deserialize::deserialize(&mut de).unwrap(); 415 | assert_eq!(val, true); 416 | } 417 | 418 | #[test] 419 | fn deserialize_u16() { 420 | let mut buf = Vec::new(); 421 | buf.write_u16::(32000); 422 | let mut de = BinaryDeserializer::new(Cursor::new(buf)); 423 | let val: u16 = Deserialize::deserialize(&mut de).unwrap(); 424 | assert_eq!(val, 32000); 425 | } 426 | 427 | #[test] 428 | fn deserialize_i16() { 429 | let mut buf = Vec::new(); 430 | buf.write_i16::(-32000); 431 | let mut de = BinaryDeserializer::new(Cursor::new(buf)); 432 | let val: i16 = Deserialize::deserialize(&mut de).unwrap(); 433 | assert_eq!(val, -32000); 434 | } 435 | 436 | #[test] 437 | fn deserialize_u32() { 438 | let mut buf = Vec::new(); 439 | buf.write_u32::(32000); 440 | let mut de = BinaryDeserializer::new(Cursor::new(buf)); 441 | let val: u32 = Deserialize::deserialize(&mut de).unwrap(); 442 | assert_eq!(val, 32000); 443 | } 444 | 445 | #[test] 446 | fn deserialize_i32() { 447 | let mut buf = Vec::new(); 448 | buf.write_i32::(32000); 449 | let mut de = BinaryDeserializer::new(Cursor::new(buf)); 450 | let val: i32 = Deserialize::deserialize(&mut de).unwrap(); 451 | assert_eq!(val, 32000); 452 | } 453 | 454 | #[test] 455 | fn deserialize_u64() { 456 | let mut buf = Vec::new(); 457 | buf.write_u64::(32000); 458 | let mut de = BinaryDeserializer::new(Cursor::new(buf)); 459 | let val: u64 = Deserialize::deserialize(&mut de).unwrap(); 460 | assert_eq!(val, 32000); 461 | } 462 | 463 | #[test] 464 | fn deserialize_i64() { 465 | let mut buf = Vec::new(); 466 | buf.write_i64::(32000); 467 | let mut de = BinaryDeserializer::new(Cursor::new(buf)); 468 | let val: i64 = Deserialize::deserialize(&mut de).unwrap(); 469 | assert_eq!(val, 32000); 470 | } 471 | 472 | #[test] 473 | fn deserialize_string() { 474 | let mut buf = Vec::new(); 475 | let i = "foobar"; 476 | buf.write_i32::(i.len() as i32); 477 | buf.write(i.as_bytes()); 478 | let mut de = BinaryDeserializer::new(Cursor::new(buf)); 479 | let val: String = Deserialize::deserialize(&mut de).unwrap(); 480 | assert_eq!(&*val, "foobar"); 481 | } 482 | } 483 | -------------------------------------------------------------------------------- /src/reactor.rs: -------------------------------------------------------------------------------- 1 | use mio::tcp::*; 2 | use mio; 3 | use mio::{Token, Handler, EventLoop, EventSet, PollOpt, TryRead, TryWrite, Evented}; 4 | use std::io::{self, Cursor, Write, Read}; 5 | use std::net::{self, SocketAddr}; 6 | use std::time::Duration; 7 | use std::mem; 8 | use std::iter; 9 | use std::thread::{self, JoinHandle}; 10 | use event_loop::EVENT_LOOP; 11 | use std::sync::mpsc::{Receiver, Sender, channel}; 12 | use result::{ThrustResult, ThrustError}; 13 | use tangle::{Future, Async}; 14 | use bytes::buf::Buf; 15 | use std::collections::HashMap; 16 | use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; 17 | use libc; 18 | use std::os::unix::io::AsRawFd; 19 | 20 | pub struct Id(pub Token); 21 | 22 | /// Communication into the Mio event loop happens with a `Message`. For each new Mio 23 | /// event loop, a mio-specific `Sender` is returned. 24 | #[derive(Debug, Clone)] 25 | pub enum Message { 26 | /// `Connect` establishes a new `TcpStream` with a specified remote. The 27 | /// `Sender` channel part is used to communicate back with the initiator on 28 | /// certain socket events. 29 | /// 30 | /// The first `Sender` is used to communicate back the assigned `Token`. 31 | Connect(SocketAddr, Sender, Sender), 32 | /// To give a tighter feedback loop, a `Bind` message will accept a normal 33 | /// Rust blocking net::TcpListener. This allows the user to more easily handle 34 | /// binding errors before sending it into the event loop where you need to 35 | /// handle any errors asynchronously. 36 | Bind(SocketAddr, Sender, Sender), 37 | /// Initiate an `Rpc` request. Each request needs to know which `Token` the respective 38 | /// `Connection` is associated with. The `Reactor` also knows nothing about Thrift 39 | /// and simply works at the binary level. 40 | /// 41 | /// An `Rpc` message is also used for replying to an RPC call. 42 | Rpc(Token, Vec), 43 | /// Completely shutdown the `Reactor` and event loop. All current listeners 44 | /// and connections will be dropped. 45 | Shutdown 46 | } 47 | 48 | /// Communication from the `Reactor` to outside components happens with a `Dispatch` message 49 | /// and normal Rust channels instead of Mio's variant. 50 | #[derive(Debug)] 51 | pub enum Dispatch { 52 | /// When a socket has been read, the `Reactor` will send the `Dispatch::Data` message 53 | /// to the associating channel. 54 | /// 55 | /// We also associate any incoming data with the Token of the responsible socket. 56 | Data(Token, Vec) 57 | } 58 | 59 | pub enum Timeout { 60 | Reconnect(Token) 61 | } 62 | 63 | #[derive(Debug, PartialEq, Eq)] 64 | pub enum State { 65 | /// The length that has been read so far. 66 | ReadingFrame(usize), 67 | Reading, 68 | Writing, 69 | Closed 70 | } 71 | 72 | #[derive(Debug)] 73 | pub enum FrameState { 74 | Reading(u32), 75 | Writing 76 | } 77 | 78 | /// Wrap a `TcpStream` to handle reading and writing frames. Frames are simply some encoded thrift 79 | /// protocol byte buffer preceeded by a 32-bit unsigned length. 80 | pub struct FramedTransport { 81 | buffer: Vec, 82 | state: FrameState 83 | } 84 | 85 | impl FramedTransport { 86 | pub fn new() -> FramedTransport { 87 | FramedTransport { 88 | buffer: Vec::new(), 89 | state: FrameState::Reading(0) 90 | } 91 | } 92 | 93 | pub fn read(&mut self, socket: &mut S) -> ThrustResult>> 94 | where S: TryRead + TryWrite 95 | { 96 | match self.state { 97 | FrameState::Reading(total_len) if self.buffer.len() == 0 => { 98 | let mut buf = Vec::with_capacity(4); 99 | buf.extend(iter::repeat(0).take(4)); 100 | 101 | // Try reading the first unsigned 32-bits for the length of the frame. 102 | let len = match socket.try_read_buf(&mut buf)? { 103 | Some(n) if n == 4 => { 104 | let mut buf = Cursor::new(buf); 105 | buf.read_u32::()? 106 | }, 107 | Some(n) => { 108 | return Err(ThrustError::Other); 109 | }, 110 | None => panic!("err") 111 | }; 112 | 113 | // Set our internal buffer. 114 | self.buffer = Vec::with_capacity(len as usize); 115 | self.buffer.extend(iter::repeat(0).take(len as usize)); 116 | return self.read(socket); 117 | }, 118 | FrameState::Reading(ref mut total_len) => { 119 | while let Some(n) = socket.try_read_buf(&mut self.buffer)? { 120 | *total_len += n as u32; 121 | if *total_len == self.buffer.len() as u32 { 122 | return Ok(Some(mem::replace(&mut self.buffer, Vec::new()))); 123 | } else if n == 0 { 124 | return Ok(None); 125 | } 126 | } 127 | }, 128 | FrameState::Writing => return Err(ThrustError::Other) 129 | } 130 | 131 | Ok(None) 132 | } 133 | } 134 | 135 | 136 | pub struct Connection { 137 | stream: TcpStream, 138 | addr: SocketAddr, 139 | pub token: Token, 140 | state: State, 141 | chan: Sender, 142 | rbuffer: Vec, 143 | wbuffer: Cursor> 144 | } 145 | 146 | impl Connection { 147 | pub fn new(conn: (TcpStream, SocketAddr), token: Token, chan: Sender) -> Self { 148 | Connection { 149 | stream: conn.0, 150 | addr: conn.1, 151 | token: token, 152 | state: State::Reading, 153 | chan: chan, 154 | rbuffer: vec![], 155 | wbuffer: Cursor::new(vec![]) 156 | } 157 | } 158 | 159 | pub fn reset(&mut self, event_loop: &mut EventLoop) { 160 | event_loop.timeout(Timeout::Reconnect(self.token), Duration::from_millis(10)); 161 | } 162 | 163 | pub fn ready(&mut self, event_loop: &mut EventLoop, events: EventSet) { 164 | match self.state { 165 | State::Reading if events.is_readable() => { 166 | match self.readable() { 167 | Ok(_) => {}, 168 | Err(err) => { 169 | println!("[reactor]: could not dispatch incoming data. {:?}", err); 170 | panic!("{:?}", err); 171 | } 172 | } 173 | self.reregister(event_loop, self.token); 174 | }, 175 | State::Writing if events.is_writable() => { 176 | self.writable(); 177 | self.reregister(event_loop, self.token); 178 | }, 179 | _ => { 180 | self.reregister(event_loop, self.token); 181 | } 182 | } 183 | } 184 | 185 | pub fn read(&mut self) -> ThrustResult>> { 186 | match self.state { 187 | State::Reading => { 188 | let len = self.stream.read_u32::()?; 189 | self.state = State::ReadingFrame(0); 190 | self.rbuffer = Vec::with_capacity(len as usize); 191 | self.read() 192 | }, 193 | State::ReadingFrame(ref mut len) => { 194 | match self.stream.try_read_buf(&mut self.rbuffer) { 195 | Ok(Some(n)) => { 196 | if *len + n == self.rbuffer.len() { 197 | let buf = mem::replace(&mut self.rbuffer, Vec::new()); 198 | Ok(Some(buf)) 199 | } else { 200 | *len += n; 201 | // We don't have a complete frame yet. 202 | Ok(None) 203 | } 204 | }, 205 | Ok(None) => Err(ThrustError::NotReady), 206 | Err(err) => Err(ThrustError::Other) 207 | } 208 | }, 209 | _ => Err(ThrustError::Other) 210 | } 211 | } 212 | 213 | pub fn writable(&mut self) -> ThrustResult<()> { 214 | // Flush the whole buffer. The socket can, at any time, be unwritable. Thus, we 215 | // need to keep track of what we've written so far. 216 | while self.wbuffer.has_remaining() { 217 | self.flush(); 218 | } 219 | 220 | self.state = State::Reading; 221 | 222 | Ok(()) 223 | } 224 | 225 | pub fn readable(&mut self) -> ThrustResult<()> { 226 | while let Ok(op) = self.read() { 227 | match op { 228 | Some(buf) => { 229 | self.state = State::Reading; 230 | println!("[reactor/connection]: reading data from {:?}", self.token); 231 | try!(self.chan.send(Dispatch::Data(self.token, buf))); 232 | }, 233 | None => {} 234 | } 235 | } 236 | 237 | self.state = State::Writing; 238 | 239 | Ok(()) 240 | } 241 | 242 | fn register(&mut self, event_loop: &mut EventLoop, token: Token) -> ThrustResult<()> { 243 | event_loop.register(&self.stream, token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot())?; 244 | Ok(()) 245 | } 246 | 247 | pub fn reregister(&self, event_loop: &mut EventLoop, token: Token) -> ThrustResult<()> { 248 | let event_set = match self.state { 249 | State::Reading => EventSet::readable(), 250 | State::Writing => EventSet::writable(), 251 | _ => EventSet::none() 252 | }; 253 | 254 | event_loop.reregister(&self.stream, self.token, event_set, PollOpt::oneshot())?; 255 | Ok(()) 256 | } 257 | } 258 | 259 | impl Write for Connection { 260 | fn write(&mut self, data: &[u8]) -> io::Result { 261 | self.wbuffer.get_mut().write_u32::(data.len() as u32)?; 262 | self.wbuffer.get_mut().write(data)?; 263 | self.flush()?; 264 | Ok(0) 265 | } 266 | 267 | fn flush(&mut self) -> io::Result<()> { 268 | match self.stream.try_write_buf(&mut self.wbuffer) { 269 | Ok(Some(_)) => Ok(()), 270 | Ok(None) => Ok(()), 271 | Err(err) => Err(err) 272 | } 273 | } 274 | } 275 | 276 | /// The `Reactor` is the component that interacts with networking. The reactor is 277 | /// built around Mio's event loop and manages both TcpListeners and TcpStreams. 278 | /// 279 | /// The reactor isn't responsible for anything Thrift related, so it doesn't know 280 | /// about parsing, protocols, serialization, etc... All it's responsible for 281 | /// is sending and receiving data from various connections and dispatching them 282 | /// to the appropriate channels. 283 | /// 284 | /// To communicate into the event loop, you use a copy of Mio's `Sender` channel 285 | /// type to send `Message`s. These will be intercepted in the event loop and processed. 286 | /// 287 | /// Things you might send to the `Reactor` through this mechanism: 288 | /// 289 | /// 1. Binding a new TCP listener — Each reactor is capable of handling an unbounded 290 | /// number of listeners, who will all be able to accept new sockets. 291 | /// 292 | /// Binding a new listener requires that you have already established a blocking variant 293 | /// through `net::TcpListener`. The listener will be converted to Mio's non-blocking variant. 294 | /// 295 | /// ```notrust 296 | /// use std::net::TcpListener; 297 | /// use std::sync::mpsc::channel; 298 | /// 299 | /// // The channel is used as a channel. Any socket being accepted 300 | /// // by this listener will also use this channel (the sender part). 301 | /// let (tx, rx) = channel(); 302 | /// let addr = "127.0.0.1:4566".parse().unwrap(); 303 | /// 304 | /// reactor_sender.send(Message::Bind(addr, tx)); 305 | /// ``` 306 | /// 307 | /// 2. Connecting to a remote TCP server and establishing a new non-blocking `TcpStream`. 308 | /// 309 | /// ```notrust 310 | /// use std::sync::mpsc::channel; 311 | /// 312 | /// // The callback channel on the single socket. 313 | /// let (tx, rx) = channel(); 314 | /// let addr = "127.0.0.1::4566".parse().unwrap(); 315 | /// reactor_sender.send(Message::Connect(addr, tx)); 316 | /// ``` 317 | /// 318 | /// 319 | /// 3. Sending RPC calls (initiating or reply) to a socket. Instead of writing or reading 320 | /// primitives, we boil everything down to Rpc or Data messages, each with an associative Token 321 | /// to mark the responsible `TcpStream` or `Connection`. 322 | /// 323 | /// ```notrust 324 | /// reactor_sender.send(Message::Rpc(Token(1), vec![0, 1, 3, 4])); 325 | /// ``` 326 | pub struct Reactor { 327 | listeners: HashMap, 328 | connections: HashMap, 329 | /// Channels that are sent from `::Bind` messages to establish a listener will 330 | /// be appended in this map. All subsequent sockets being accepted from the listener 331 | /// will use the same sender channel to consolidate communications. 332 | servers: HashMap>, 333 | /// The `Reactor` manages a count of the number of tokens, the number being 334 | /// the token used for the next allocated resource. Tokens are used sequentially 335 | /// across both listeners and connections. 336 | current_token: usize 337 | } 338 | 339 | impl Reactor { 340 | pub fn new() -> Reactor { 341 | Reactor { 342 | listeners: HashMap::new(), 343 | connections: HashMap::new(), 344 | servers: HashMap::new(), 345 | current_token: 0 346 | } 347 | } 348 | 349 | pub fn run() -> JoinHandle<()> { 350 | thread::spawn(move || { 351 | let mut event_loop = EVENT_LOOP.lock().expect("Failed to take the `EVENT_LOOP` lock."); 352 | let mut reactor = Reactor::new(); 353 | event_loop.run(&mut reactor); 354 | }) 355 | } 356 | 357 | pub fn incoming_timeout(&mut self, event_loop: &mut EventLoop, timeout: Timeout) -> ThrustResult<()> { 358 | match timeout { 359 | Timeout::Reconnect(token) => { 360 | let mut conn = self.connections.get_mut(&token).expect("Could not find the connection."); 361 | let mut stream = TcpStream::connect(&conn.addr)?; 362 | conn.stream = stream; 363 | conn.register(event_loop, token); 364 | } 365 | } 366 | 367 | Ok(()) 368 | } 369 | 370 | pub fn incoming_msg(&mut self, event_loop: &mut EventLoop, msg: Message) -> ThrustResult<()> { 371 | match msg { 372 | Message::Rpc(id, data) => { 373 | println!("[reactor]: rpc @ {:?}", id); 374 | self.connections.get_mut(&id).expect("connection was not found #2").write(&*data); 375 | }, 376 | Message::Shutdown => { 377 | println!("Shutting down..."); 378 | event_loop.shutdown(); 379 | }, 380 | Message::Connect(addr, id_tx, tx) => { 381 | let mut mio_stream = TcpStream::connect(&addr)?; 382 | let new_token = Token(self.current_token); 383 | id_tx.send(Id(new_token)); 384 | let mut conn = Connection::new((mio_stream, addr), new_token, tx); 385 | 386 | println!("[reactor]: binding to {:?} @ {:?}", addr, new_token); 387 | 388 | self.connections.insert(new_token, conn); 389 | self.connections.get_mut(&new_token) 390 | .expect("Cannot find the connection from the token {:?}") 391 | .register(event_loop, new_token); 392 | 393 | self.current_token += 1; 394 | }, 395 | Message::Bind(addr, id_tx, tx) => { 396 | let token = Token(self.current_token); 397 | let mut lis = TcpListener::bind(&addr)?; 398 | 399 | id_tx.send(Id(token)); 400 | self.servers.insert(token, tx); 401 | 402 | println!("[reactor]: binding to {:?} @ {:?}", addr, token); 403 | 404 | event_loop.register(&lis, token, EventSet::readable(), PollOpt::edge())?; 405 | self.listeners.insert(token, lis); 406 | self.current_token += 1; 407 | } 408 | } 409 | 410 | Ok(()) 411 | } 412 | 413 | pub fn accept_connection(&mut self, event_loop: &mut EventLoop, token: Token) { 414 | let mut listener = self.listeners.get_mut(&token).expect("Listener was not found."); 415 | match listener.accept() { 416 | Ok(Some(socket)) => { 417 | let clone = self.servers[&token].clone(); 418 | let new_token = Token(self.current_token); 419 | let mut conn = Connection::new(socket, new_token, clone); 420 | 421 | self.connections.insert(new_token, conn); 422 | self.connections.get_mut(&new_token) 423 | .expect("Cannot find the connection in the cache.") 424 | .register(event_loop, new_token); 425 | 426 | self.current_token += 1; 427 | }, 428 | _ => {} 429 | } 430 | } 431 | } 432 | 433 | impl Handler for Reactor { 434 | type Timeout = Timeout; 435 | type Message = Message; 436 | 437 | fn ready(&mut self, event_loop: &mut EventLoop, token: Token, events: EventSet) { 438 | if events.is_hup() { 439 | if self.connections.contains_key(&token) { 440 | let mut conn = self.connections.get_mut(&token) 441 | .expect("Cannot find the connection in the cache.") 442 | .reset(event_loop); 443 | } 444 | 445 | return; 446 | } 447 | 448 | if events.is_error() { 449 | println!("Err: {:?}", events); 450 | return; 451 | } 452 | 453 | if events.is_readable() && self.listeners.contains_key(&token) { 454 | self.accept_connection(event_loop, token); 455 | return; 456 | } 457 | 458 | if self.connections.contains_key(&token) { 459 | self.connections.get_mut(&token).expect("connection was not found #1").ready(event_loop, events); 460 | } 461 | } 462 | 463 | /// XXX: Timeouts would be useful to implement. 464 | fn timeout(&mut self, event_loop: &mut EventLoop, timeout: Timeout) { 465 | match self.incoming_timeout(event_loop, timeout) { 466 | Ok(_) => {}, 467 | Err(err) => panic!("An error occurred while handling a timeout") 468 | } 469 | } 470 | 471 | fn notify(&mut self, event_loop: &mut EventLoop, msg: Message) { 472 | match self.incoming_msg(event_loop, msg) { 473 | Ok(_) => {}, 474 | Err(err) => panic!("Reactor failed to handle incoming msg") 475 | } 476 | } 477 | } 478 | 479 | #[cfg(test)] 480 | mod tests { 481 | use mio::{EventLoop, Token}; 482 | use super::*; 483 | use std::io::{Write, Cursor, Read}; 484 | use std::sync::mpsc::{Receiver, Sender, channel}; 485 | use tangle::{Future, Async}; 486 | use std::thread; 487 | use std::time::Duration; 488 | use std::net::{TcpListener, TcpStream, SocketAddr}; 489 | use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; 490 | 491 | // #[test] 492 | // fn should_read_frame() { 493 | // let mut buf = vec![1, 2, 3]; 494 | // let mut source = Vec::new(); 495 | // source.write_u32::(3); 496 | // source.write(&mut buf); 497 | 498 | // let mut source = Cursor::new(source); 499 | // let mut framed = FramedTransport::new(); 500 | // let buf = match framed.read(&mut source) { 501 | // Ok(Some(buf)) => buf, 502 | // Ok(None) => panic!("Could not read the next frame from the socket."), 503 | // Err(err) => panic!("Tests failed.") 504 | // }; 505 | 506 | // assert_eq!(&buf[..], &[1, 2, 3]); 507 | // } 508 | 509 | // #[test] 510 | // fn should_error_on_incomplete_frame() { 511 | // let mut buf = vec![1, 2]; 512 | // let mut source = Vec::new(); 513 | // source.write_u32::(3); 514 | // source.write(&mut buf); 515 | 516 | // let mut source = Cursor::new(source); 517 | // let mut framed = FramedTransport::new(); 518 | // match framed.read(&mut source) { 519 | // Ok(Some(buf)) => panic!("We shouldn't have gotten a read frame back."), 520 | // Ok(None) => {}, 521 | // Err(err) => panic!("Tests failed. {:?}", err) 522 | // } 523 | // } 524 | 525 | // #[test] 526 | // fn should_eventually_read_delayed_frame() { 527 | // let mut buf = vec![]; 528 | // let mut source = Vec::new(); 529 | // source.write_u32::(3); 530 | // source.write(&mut buf); 531 | 532 | // let mut reader = Cursor::new(source); 533 | // let mut framed = FramedTransport::new(); 534 | // match framed.read(&mut reader) { 535 | // Ok(Some(buf)) => panic!("We shouldn't have gotten a read frame back."), 536 | // Ok(None) => {}, 537 | // Err(err) => panic!("Tests failed. {:?}", err) 538 | // } 539 | // } 540 | 541 | 542 | #[test] 543 | fn create_reactor() { 544 | let (assert_tx, assert_rx) = channel(); 545 | let mut reactor = Reactor::new(); 546 | let mut event_loop = EventLoop::new().expect("[test]: EventLoop failed to create."); 547 | let sender = event_loop.channel(); 548 | 549 | let handle = thread::spawn(move || { 550 | event_loop.run(&mut reactor); 551 | }); 552 | 553 | // Establish a local TcpListener. 554 | let addr: SocketAddr = "127.0.0.1:6543".parse().expect("[test]: Parsing into SocketAddr failed."); 555 | let (rpc_server_tx, rpc_server_rx) = channel(); 556 | 557 | // Create a new non-blocking tcp server. 558 | let (id_tx, id_rx) = channel(); 559 | sender.send(Message::Bind(addr.clone(), id_tx, rpc_server_tx.clone())); 560 | 561 | let (rpc_client_tx, rpc_client_rx) = channel(); 562 | let (rpc_client_id_tx, rpc_client_id_rx) = channel(); 563 | 564 | sender.send(Message::Connect(addr, rpc_client_id_tx, rpc_client_tx)); 565 | 566 | let Id(client_id) = rpc_client_id_rx.recv().expect("[test]: Receiving from channel `rpc_client_id_rx` failed."); 567 | sender.send(Message::Rpc(client_id, b"abc".to_vec())); 568 | 569 | let server = thread::spawn(move || { 570 | for msg in rpc_server_rx.iter() { 571 | match msg { 572 | Dispatch::Data(id, msg) => { 573 | assert_tx.send((id, msg)).expect("Could not assert_tx"); 574 | } 575 | } 576 | } 577 | }); 578 | 579 | let (new_id, v) = assert_rx.recv().expect("Error trying to assert reactor test."); 580 | assert_eq!(new_id, Token(2)); 581 | assert_eq!(v.len(), 3); 582 | assert_eq!(v, b"abc"); 583 | 584 | // Send a "response" back. 585 | sender.send(Message::Rpc(new_id, b"bbb".to_vec())); 586 | 587 | match rpc_client_rx.recv().expect("[test]: Receiving from channel `rpc_client_rx` failed.") { 588 | Dispatch::Data(id, v) => { 589 | assert_eq!(id, client_id); 590 | assert_eq!(v, b"bbb"); 591 | } 592 | } 593 | } 594 | } 595 | -------------------------------------------------------------------------------- /src/result.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::convert; 3 | use std::sync::PoisonError; 4 | use byteorder; 5 | use std::sync::mpsc::{SendError, RecvError}; 6 | use mio::NotifyError; 7 | use reactor::Message; 8 | use protocol; 9 | 10 | #[derive(Debug)] 11 | pub enum ThrustError { 12 | Other, 13 | NotReady, 14 | Str(String), 15 | IO(io::Error), 16 | ByteOrder(byteorder::Error), 17 | PoisonError, 18 | RecvError(RecvError), 19 | SendError, 20 | NotifyError(NotifyError) 21 | } 22 | 23 | pub type ThrustResult = Result; 24 | 25 | impl convert::From for ThrustError { 26 | fn from(val: io::Error) -> ThrustError { 27 | ThrustError::IO(val) 28 | } 29 | } 30 | 31 | impl convert::From> for ThrustError { 32 | fn from(val: SendError) -> ThrustError { 33 | ThrustError::SendError 34 | } 35 | } 36 | 37 | impl convert::From> for ThrustError { 38 | fn from(val: NotifyError) -> ThrustError { 39 | ThrustError::NotifyError(val) 40 | } 41 | } 42 | 43 | impl convert::From for ThrustError { 44 | fn from(val: protocol::Error) -> ThrustError { 45 | ThrustError::Other 46 | } 47 | } 48 | 49 | impl convert::From for ThrustError { 50 | fn from(val: RecvError) -> ThrustError { 51 | ThrustError::RecvError(RecvError) 52 | } 53 | } 54 | 55 | impl convert::From for ThrustError { 56 | fn from(val: byteorder::Error) -> ThrustError { 57 | ThrustError::ByteOrder(val) 58 | } 59 | } 60 | 61 | impl convert::From> for ThrustError { 62 | fn from(val: PoisonError) -> ThrustError { 63 | ThrustError::PoisonError 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/runner.rs: -------------------------------------------------------------------------------- 1 | use protocol::{Deserializer, ThriftDeserializer, ThriftMessage, Error}; 2 | use tangle::Future; 3 | 4 | pub trait Runner { 5 | fn run(&mut self, de: &mut D, msg: ThriftMessage) -> Result>, Error> 6 | where D: Deserializer + ThriftDeserializer; 7 | } 8 | -------------------------------------------------------------------------------- /src/service.rs: -------------------------------------------------------------------------------- 1 | use std::io::Cursor; 2 | use std::sync::mpsc::{Sender, Receiver, channel}; 3 | use std::net::SocketAddr; 4 | use protocol::{Serializer, ThriftSerializer, ThriftMessage, ThriftDeserializer, Deserializer, 5 | Deserialize, Serialize, ThriftType, ThriftMessageType, Error}; 6 | use binary_protocol::{BinarySerializer, BinaryDeserializer}; 7 | use tangle::{Future, Async}; 8 | use server::{Server}; 9 | 10 | use pipeline::MessagePipeline; 11 | use runner::Runner; 12 | use dispatcher::{Message, dispatch}; 13 | use std::thread::JoinHandle; 14 | use reactor::Reactor; 15 | 16 | pub trait Service : Send { 17 | fn query(&mut self, val: bool) -> Future<()>; 18 | } 19 | 20 | pub struct ServiceRunner { 21 | service: S 22 | } 23 | 24 | impl ServiceRunner { 25 | pub fn new(service: S) -> ServiceRunner { 26 | ServiceRunner { 27 | service: service 28 | } 29 | } 30 | } 31 | 32 | impl Runner for ServiceRunner 33 | where D: Deserializer + ThriftDeserializer 34 | { 35 | fn run(&mut self, de: &mut D, msg: ThriftMessage) -> Result>, Error> { 36 | match &*msg.name { 37 | "query" => { 38 | let args: QueryArgs = try!(Deserialize::deserialize(de)); 39 | Ok(self.service.query(args.val).map(|val| { 40 | let mut v = Vec::new(); 41 | { 42 | let mut s = BinarySerializer::new(&mut v); 43 | s.write_message_begin("query", ThriftMessageType::Reply); 44 | 45 | s.write_struct_begin("query_ret"); 46 | 47 | s.write_field_begin("ret", ThriftType::Void, 1); 48 | s.write_field_stop(); 49 | s.write_field_end(); 50 | 51 | s.write_struct_end(); 52 | 53 | s.write_message_end(); 54 | } 55 | 56 | v 57 | })) 58 | }, 59 | _ => { 60 | unimplemented!() 61 | // Return Err. 62 | } 63 | } 64 | } 65 | } 66 | 67 | pub struct QueryArgs { 68 | val: bool 69 | } 70 | 71 | impl Deserialize for QueryArgs { 72 | fn deserialize(de: &mut D) -> Result 73 | where D: Deserializer + ThriftDeserializer 74 | { 75 | Ok(QueryArgs { 76 | val: try!(de.deserialize_bool()) 77 | }) 78 | } 79 | } 80 | 81 | impl Serialize for QueryArgs { 82 | fn serialize(&self, s: &mut S) -> Result<(), Error> 83 | where S: Serializer + ThriftSerializer 84 | { 85 | try!(s.write_struct_begin("query_args")); 86 | 87 | // for each field 88 | try!(s.write_field_begin("val", ThriftType::Bool, 1)); 89 | try!(self.val.serialize(s)); 90 | try!(s.write_field_stop()); 91 | try!(s.write_field_end()); 92 | 93 | try!(s.write_struct_end()); 94 | 95 | Ok(()) 96 | } 97 | } 98 | 99 | pub struct RpcClient { 100 | dispatcher: Sender, 101 | handle: JoinHandle<()> 102 | } 103 | 104 | impl RpcClient { 105 | pub fn new(addr: SocketAddr) -> RpcClient { 106 | let (handle, tx) = dispatch(addr); 107 | 108 | RpcClient { 109 | dispatcher: tx, 110 | handle: handle 111 | } 112 | } 113 | 114 | fn join(mut self) { 115 | self.handle.join(); 116 | } 117 | 118 | pub fn shutdown(mut self) { 119 | self.dispatcher.send(Message::Shutdown); 120 | self.join(); 121 | } 122 | } 123 | 124 | impl Service for RpcClient { 125 | fn query(&mut self, val: bool) -> Future<()> { 126 | let (tx, rx) = channel(); 127 | let future = Future::>::from_channel(rx); 128 | let mut buf = Vec::new(); 129 | 130 | { 131 | let mut proto = BinarySerializer::new(&mut buf); 132 | let args = QueryArgs { 133 | val: val 134 | }; 135 | 136 | proto.write_message_begin("query", ThriftMessageType::Call); 137 | args.serialize(&mut proto); 138 | proto.write_message_end(); 139 | } 140 | 141 | self.dispatcher.send(Message::Call("query".to_string(), buf, tx)); 142 | 143 | future.map(|v| { 144 | 145 | () 146 | }) 147 | } 148 | } 149 | 150 | #[test] 151 | fn call_query() { 152 | struct S; 153 | 154 | impl Service for S { 155 | fn query(&mut self, val: bool) -> Future<()> { 156 | assert_eq!(val, true); 157 | Future::unit(()) 158 | } 159 | } 160 | 161 | let run = ServiceRunner::new(S); 162 | let mut server = Server::new(run); 163 | server.bind("0.0.0.0:9455".parse().unwrap()); 164 | 165 | let addr = "0.0.0.0:9455".parse().unwrap(); 166 | let mut rpc = RpcClient::new(addr); 167 | 168 | rpc.query(true); 169 | 170 | // { 171 | // let mut de = BinaryDeserializer::new(Cursor::new(buf)); 172 | // let mut s = Server; 173 | // let mut caller = ServiceRunner::new(&mut s); 174 | // MessagePipeline::new(de).run(&mut caller).unwrap().and_then(|v| { 175 | // println!("#query result: {:?}", v); 176 | // Async::Ok(()) 177 | // }); 178 | // } 179 | 180 | Reactor::run(); 181 | rpc.shutdown(); 182 | } 183 | -------------------------------------------------------------------------------- /src/testing.rs: -------------------------------------------------------------------------------- 1 | // foobar: autogenerated by thrust 2 | #![allow(dead_code, unused_imports)] 3 | use thrust::protocol::{Error, ThriftType}; 4 | use thrust::{ThrustResult, ThrustError}; 5 | use thrust::dispatcher::{self, Dispatcher, Incoming}; 6 | use thrust::reactor::Message; 7 | use std::thread::JoinHandle; 8 | use std::net::SocketAddr; 9 | use std::sync::mpsc::{Sender, Receiver}; 10 | use tangle::{Future, Async}; 11 | use std::collections::{HashMap, HashSet}; 12 | use thrust::protocol::{ThriftDeserializer, ThriftSerializer}; 13 | use thrust::protocol::{Serializer, Deserializer}; 14 | use thrust::protocol::{Deserialize, Serialize, ThriftMessage}; 15 | use thrust::binary_protocol::{BinarySerializer, BinaryDeserializer}; 16 | 17 | 18 | pub trait FlockDbService { 19 | fn query(&mut self, voodoo: i32) -> Future; 20 | fn ack(&mut self, source_id: i64, tuple_id: i64) -> Future; 21 | } 22 | 23 | pub struct FlockDbClient { 24 | dispatcher: Sender, 25 | handle: JoinHandle>, 26 | } 27 | 28 | 29 | impl FlockDbClient { 30 | pub fn new(addr: SocketAddr) -> FlockDbClient { 31 | let (handle, tx) = Dispatcher::spawn(dispatcher::Role::Client(addr)).unwrap(); 32 | 33 | FlockDbClient { 34 | dispatcher: tx, 35 | handle: handle, 36 | } 37 | } 38 | } 39 | 40 | struct FlockDb_query_Args { 41 | voodoo: i32, 42 | } 43 | 44 | struct FlockDb_ack_Args { 45 | source_id: i64, 46 | tuple_id: i64, 47 | } 48 | 49 | impl Serialize for FlockDb_query_Args { 50 | fn serialize(&self, s: &mut S) -> Result<(), Error> 51 | where S: Serializer + ThriftSerializer 52 | { 53 | try!(s.write_struct_begin("FlockDb_query_Args")); 54 | try!(s.write_field_begin("voodoo", ThriftType::I32, 1)); 55 | try!(self.voodoo.serialize(s)); 56 | try!(s.write_field_stop()); 57 | try!(s.write_field_end()); 58 | try!(s.write_struct_end()); 59 | Ok(()) 60 | } 61 | } 62 | impl Serialize for FlockDb_ack_Args { 63 | fn serialize(&self, s: &mut S) -> Result<(), Error> 64 | where S: Serializer + ThriftSerializer 65 | { 66 | try!(s.write_struct_begin("FlockDb_ack_Args")); 67 | try!(s.write_field_begin("source_id", ThriftType::I64, 1)); 68 | try!(self.source_id.serialize(s)); 69 | try!(s.write_field_stop()); 70 | try!(s.write_field_end()); 71 | try!(s.write_field_begin("tuple_id", ThriftType::I64, 2)); 72 | try!(self.tuple_id.serialize(s)); 73 | try!(s.write_field_stop()); 74 | try!(s.write_field_end()); 75 | try!(s.write_struct_end()); 76 | Ok(()) 77 | } 78 | } 79 | impl Deserialize for FlockDb_query_Args { 80 | fn deserialize(&self, de: &mut D) -> Result<(), Error> 81 | where D: Deserializer + ThriftDeserializer 82 | { 83 | try!(de.read_struct_begin()); 84 | let args = FlockDb_query_Args { 85 | voodoo: { 86 | match try!(de.read_field_begin()).ty { 87 | ThriftType::Stop => { try!(de.read_field_begin()); }, 88 | _ => {} 89 | } 90 | let val = try!(de.deserialize_i32()); 91 | try!(de.read_field_end()); 92 | val 93 | } 94 | }; 95 | try!(de.read_struct_end()); 96 | Ok(args) 97 | } 98 | } 99 | impl Deserialize for FlockDb_ack_Args { 100 | fn deserialize(&self, de: &mut D) -> Result<(), Error> 101 | where D: Deserializer + ThriftDeserializer 102 | { 103 | try!(de.read_struct_begin()); 104 | let args = FlockDb_ack_Args { 105 | source_id: { 106 | match try!(de.read_field_begin()).ty { 107 | ThriftType::Stop => { try!(de.read_field_begin()); }, 108 | _ => {} 109 | } 110 | let val = try!(de.deserialize_i64()); 111 | try!(de.read_field_end()); 112 | val 113 | } 114 | tuple_id: { 115 | match try!(de.read_field_begin()).ty { 116 | ThriftType::Stop => { try!(de.read_field_begin()); }, 117 | _ => {} 118 | } 119 | let val = try!(de.deserialize_i64()); 120 | try!(de.read_field_end()); 121 | val 122 | } 123 | }; 124 | try!(de.read_struct_end()); 125 | Ok(args) 126 | } 127 | } -------------------------------------------------------------------------------- /src/transport.rs: -------------------------------------------------------------------------------- 1 | use result::{ThrustResult}; 2 | 3 | pub trait Transport { 4 | fn open(&mut self) -> ThrustResult<()>; 5 | fn close(&mut self) -> ThrustResult<()>; 6 | fn read(&mut self, buf: &mut [u8]) -> ThrustResult; 7 | fn write(&mut self, buf: &[u8]) -> ThrustResult<()>; 8 | fn flush(&mut self) -> ThrustResult<()>; 9 | } 10 | -------------------------------------------------------------------------------- /src/util.rs: -------------------------------------------------------------------------------- 1 | use protocol::*; 2 | use binary_protocol::*; 3 | 4 | pub fn create_empty_thrift_message(method: &str, ty: ThriftMessageType) -> Vec { 5 | let mut buf = Vec::new(); 6 | { 7 | let mut se = BinarySerializer::new(&mut buf); 8 | se.write_message_begin(method, ty); 9 | se.write_message_end(); 10 | } 11 | 12 | buf 13 | } 14 | 15 | -------------------------------------------------------------------------------- /tests/namespace.rs: -------------------------------------------------------------------------------- 1 | // extern crate thrust; 2 | 3 | // use thrust::ThriftCompiler; 4 | 5 | // pub const ns: &'static [u8] = b"namespace rust foobar\n"; 6 | // pub const ns_1: &'static [u8] = b" 7 | // namespace rust foobar\n 8 | // "; 9 | // pub const ns_2: &'static [u8] = b" 10 | // namespace rust foobar\n 11 | // "; 12 | // pub const empty: &'static [u8] = b""; 13 | 14 | // #[test] 15 | // #[should_panic] 16 | // fn ns_empty() { 17 | // let r = ThriftCompiler::run(empty).unwrap(); 18 | // } 19 | 20 | // #[test] 21 | // fn namespace() { 22 | // let r = ThriftCompiler::run(ns).unwrap(); 23 | // assert_eq!(&*r.namespace, "foobar"); 24 | // assert_eq!(&*r.buffer, ""); 25 | // } 26 | 27 | // #[test] 28 | // fn namespace_1() { 29 | // let r = ThriftCompiler::run(ns_1).unwrap(); 30 | // assert_eq!(&*r.namespace, "foobar"); 31 | // assert_eq!(&*r.buffer, ""); 32 | // } 33 | 34 | // #[test] 35 | // fn namespace_2() { 36 | // let r = ThriftCompiler::run(ns_2).unwrap(); 37 | // assert_eq!(&*r.namespace, "foobar"); 38 | // assert_eq!(&*r.buffer, ""); 39 | // } 40 | -------------------------------------------------------------------------------- /tests/struct.rs: -------------------------------------------------------------------------------- 1 | // extern crate thrust; 2 | 3 | // use thrust::ThriftCompiler; 4 | 5 | // pub const empty: &'static [u8] = b" 6 | // namespace rust ping 7 | // struct Ping {} 8 | // "; 9 | 10 | // pub const empty_gen: &'static str = "pub struct Ping { 11 | // } 12 | // "; 13 | 14 | // pub const field: &'static [u8] = b" 15 | // namespace rust ping 16 | // struct Ping { 17 | // 1: required string foobar; 18 | // } 19 | // "; 20 | 21 | // pub const field_gen: &'static str = "pub struct Ping { 22 | // foobar: String, 23 | // } 24 | // "; 25 | 26 | // #[test] 27 | // fn test_empty_struct() { 28 | // let r = ThriftCompiler::run(empty).unwrap(); 29 | // assert_eq!(&*r.namespace, "ping"); 30 | // assert_eq!(&*r.buffer, empty_gen); 31 | // } 32 | 33 | // #[test] 34 | // fn test_field_struct() { 35 | // let r = ThriftCompiler::run(field).unwrap(); 36 | // assert_eq!(&*r.namespace, "ping"); 37 | // assert_eq!(&*r.buffer, field_gen); 38 | // } 39 | -------------------------------------------------------------------------------- /thrust-codegen/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "thrust_codegen" 3 | version = "0.1.0" 4 | authors = ["Daniel Fagnan "] 5 | 6 | [dependencies] 7 | 8 | [dependencies.thrust_parser] 9 | path = "../thrust-parser" 10 | -------------------------------------------------------------------------------- /thrust-codegen/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(question_mark)] 2 | 3 | use std::io::{self, Write}; 4 | 5 | pub fn write_runner_match(wr: &mut Write, name: &str, method: &ServiceMethod) { 6 | write!(wr, "\"{method}\" => {{\n", method=method.ident); 7 | write!(wr, "let args: {service}_{method}_Args = try!(Deserialize::deserialize(de));\n", service=name, method=method.ident); 8 | write!(wr, "let ret = self.service.{method}(", method=method.ident); 9 | 10 | for arg in method.args.iter() { 11 | write!(wr, "args.{},", arg.ident); 12 | } 13 | 14 | write!(wr, " 15 | ).map(|val| {{ 16 | let mut buf = Vec::new(); 17 | {{ 18 | let mut s = BinarySerializer::new(&mut buf); 19 | 20 | s.write_message_begin(\"{method}\", ThriftMessageType::Reply); 21 | s.write_struct_begin(\"{method}_ret\"); 22 | s.write_field_begin(\"ret\", {ty}, 1); 23 | val.serialize(&mut s); 24 | s.write_field_stop(); 25 | s.write_field_end(); 26 | s.write_struct_end(); 27 | s.write_message_end(); 28 | }} 29 | buf 30 | }}); 31 | Ok(ret)", method=method.ident, ty=method.ty.to_protocol()); 32 | 33 | write!(wr, "\n}},"); 34 | } 35 | 36 | pub fn write_runner_impl_begin(wr: &mut Write, name: &str) -> Result<(), Error> { 37 | write!(wr, " 38 | impl Runner for {name}Runner 39 | where S: {name}Service 40 | {{ 41 | fn run(&mut self, de: &mut D, msg: ThriftMessage) -> Result>, Error> 42 | where D: Deserializer + ThriftDeserializer 43 | {{ 44 | match &*msg.name {{ 45 | ", name=name); 46 | Ok(()) 47 | } 48 | 49 | pub fn write_runner_impl_end(wr: &mut Write) { 50 | write!(wr, " _ => unimplemented!() 51 | }} 52 | }} 53 | }}"); 54 | } 55 | 56 | pub fn write_runner(wr: &mut Write, name: &str) -> Result<(), Error> { 57 | write!(wr, " 58 | pub struct {name}Runner {{ 59 | service: S 60 | }} 61 | 62 | impl {name}Runner where S: {name}Service {{ 63 | pub fn new(service: S) -> {name}Runner {{ 64 | {name}Runner {{ 65 | service: service 66 | }} 67 | }} 68 | }}", name=name); 69 | Ok(()) 70 | } 71 | 72 | pub fn write_server(wr: &mut Write, name: &str) -> Result<(), Error> { 73 | write!(wr, "\n 74 | pub struct {name}Server {{ \ 75 | dispatcher: Sender, 76 | pub handle: JoinHandle>, 77 | }} 78 | 79 | impl {name}Server {{ 80 | pub fn new(service: S, addr: SocketAddr) -> {name}Server 81 | where S: 'static + {name}Service 82 | {{ 83 | use std::thread; 84 | use std::sync::mpsc::channel; 85 | use std::io::Cursor; 86 | 87 | let (sender, receiver) = channel(); 88 | let (handle, tx) = Dispatcher::spawn(dispatcher::Role::Server(addr, sender)).unwrap(); 89 | 90 | let send_tx = tx.clone(); 91 | thread::spawn(move || {{ 92 | let mut runner = {name}Runner::new(service); 93 | for (token, buf) in receiver.iter() {{ 94 | let mut de = BinaryDeserializer::new(Cursor::new(buf)); 95 | match de.read_message_begin() {{ 96 | Ok(msg) => {{ 97 | match runner.run(&mut de, msg) {{ 98 | Ok(f) => {{ 99 | let chan = send_tx.clone(); 100 | f.and_then(move |buf| {{ 101 | chan.send(Incoming::Reply(token, buf)); 102 | Async::Ok(()) 103 | }}); 104 | }}, 105 | Err(err) => {{\n 106 | }} 107 | }} 108 | }}, 109 | Err(err) => {{ 110 | println!(\"[server]: error parsing thrift message: {{:?}}\", err); 111 | }} 112 | }} 113 | }} 114 | }}); 115 | 116 | {name}Server {{ 117 | dispatcher: tx, 118 | handle: handle, 119 | }} 120 | }} 121 | }}", name=name); 122 | Ok(()) 123 | } 124 | 125 | use thrust_parser::{ 126 | Struct, 127 | Namespace, 128 | Enum, 129 | Service, 130 | ServiceMethod, 131 | Parser, 132 | Keyword, 133 | StructField, 134 | Ty 135 | }; 136 | 137 | extern crate thrust_parser; 138 | 139 | #[derive(Debug)] 140 | pub enum Error { 141 | Other, 142 | IO(io::Error), 143 | Parser(thrust_parser::Error), 144 | Eof 145 | } 146 | 147 | impl From for Error { 148 | fn from(val: io::Error) -> Error { 149 | Error::IO(val) 150 | } 151 | } 152 | 153 | impl From for Error { 154 | fn from(val: thrust_parser::Error) -> Error { 155 | Error::Parser(val) 156 | } 157 | } 158 | 159 | pub fn find_rust_namespace(parser: &mut Parser) -> Result { 160 | loop { 161 | let ns = parser.parse_namespace()?; 162 | 163 | if &*ns.lang == "rust" { 164 | return Ok(ns); 165 | } else { 166 | continue; 167 | } 168 | } 169 | } 170 | 171 | pub fn compile(parser: &mut Parser, wr: &mut Write) -> Result<(), Error> { 172 | 173 | // let ns = find_rust_namespace(parser)?; 174 | write!(wr, "// autogenerated by thrust\n"); 175 | write!(wr, "#![allow(dead_code, unused_imports)]\n"); 176 | let modules = vec![ 177 | "thrust::protocol::{Error, ThriftType}", 178 | "thrust::{ThrustResult, ThrustError}", 179 | "thrust::dispatcher::{self, Dispatcher, Incoming}", 180 | "thrust::reactor::Message", 181 | "std::thread::JoinHandle", 182 | "std::net::SocketAddr", 183 | "thrust::Runner", 184 | "std::sync::mpsc::{Sender, Receiver}", 185 | "tangle::{Future, Async}", 186 | "std::collections::{HashMap, HashSet}", 187 | "thrust::protocol::{ThriftDeserializer, ThriftSerializer, ThriftMessageType}", 188 | "thrust::protocol::{Serializer, Deserializer}", 189 | "thrust::protocol::{Deserialize, Serialize, ThriftMessage}", 190 | "thrust::binary_protocol::{BinarySerializer, BinaryDeserializer}" 191 | ]; 192 | 193 | for module in modules.iter() { 194 | write!(wr, "use {};\n", module); 195 | } 196 | 197 | write!(wr, "\n"); 198 | 199 | loop { 200 | if parser.lookahead_keyword(Keyword::Enum) { 201 | parser.parse_enum()?; 202 | } else if parser.lookahead_keyword(Keyword::Struct) { 203 | parser.parse_struct()?; 204 | } else if parser.lookahead_keyword(Keyword::Service) { 205 | let service = parser.parse_service()?; 206 | ServiceCodegen::build(wr, &service)?; 207 | } else { 208 | break; 209 | } 210 | } 211 | 212 | Ok(()) 213 | } 214 | 215 | pub struct ServiceCodegen; 216 | pub struct MethodCodegen; 217 | 218 | /// ```notrust 219 | /// Return type -> Future<$ty> 220 | /// ``` 221 | impl MethodCodegen { 222 | pub fn build(wr: &mut Write, method: &ServiceMethod) -> Result<(), Error> { 223 | write!(wr, "fn {}(&mut self", method.ident); 224 | 225 | MethodCodegen::args(wr, &method.args)?; 226 | 227 | write!(wr, ") "); 228 | write!(wr, "{}", MethodCodegen::ret(&method.ty)); 229 | Ok(()) 230 | } 231 | 232 | pub fn ret(val: &Ty) -> String { 233 | format!("-> Future<{}>", val.to_string()) 234 | } 235 | 236 | pub fn arg(wr: &mut Write, arg: &StructField) -> Result<(), Error> { 237 | write!(wr, ", {}: {}", arg.ident, arg.ty.to_string()); 238 | Ok(()) 239 | } 240 | 241 | pub fn args(wr: &mut Write, args: &Vec) -> Result<(), Error> { 242 | for arg in args { 243 | MethodCodegen::arg(wr, arg)?; 244 | } 245 | 246 | Ok(()) 247 | } 248 | } 249 | 250 | fn ws(wr: &mut Write, n: usize) -> Result<(), Error> { 251 | for i in 0..n { 252 | write!(wr, " "); 253 | } 254 | 255 | Ok(()) 256 | } 257 | 258 | impl ServiceCodegen { 259 | pub fn build(wr: &mut Write, service: &Service) -> Result<(), Error> { 260 | ServiceCodegen::build_trait(wr, service)?; 261 | ServiceCodegen::build_client_struct(wr, service)?; 262 | ServiceCodegen::build_client_impl(wr, service)?; 263 | ServiceCodegen::build_args_struct(wr, service)?; 264 | ServiceCodegen::impl_serialize_args(wr, service)?; 265 | ServiceCodegen::impl_deserialize_args(wr, service)?; 266 | ServiceCodegen::impl_service_client(wr, service)?; 267 | 268 | write_server(wr, &service.ident); 269 | write_runner(wr, &service.ident); 270 | write_runner_impl_begin(wr, &service.ident); 271 | 272 | for method in service.methods.iter() { 273 | write_runner_match(wr, &service.ident, method); 274 | } 275 | 276 | write_runner_impl_end(wr); 277 | 278 | Ok(()) 279 | } 280 | 281 | pub fn impl_service_client(wr: &mut Write, service: &Service) -> Result<(), Error> { 282 | write!(wr, "\nimpl {}Service for {}Client {{\n", service.ident, service.ident); 283 | 284 | for method in service.methods.iter() { 285 | write!(wr, "\n"); 286 | ws(wr, 1); 287 | MethodCodegen::build(wr, method)?; 288 | write!(wr, " {{\n"); 289 | 290 | ws(wr, 2); 291 | write!(wr, "use std::io::Cursor;\n"); 292 | 293 | ws(wr, 2); 294 | write!(wr, "let (res, future) = Future::<(ThriftMessage, BinaryDeserializer>>)>::channel();\n"); 295 | 296 | ws(wr, 2); 297 | write!(wr, "let mut buf = Vec::new();\n"); 298 | 299 | ws(wr, 2); 300 | write!(wr, "{{\n"); 301 | 302 | ws(wr, 3); 303 | write!(wr, "let mut se = BinarySerializer::new(&mut buf);\n"); 304 | 305 | ws(wr, 3); 306 | write!(wr, "se.write_message_begin(\"{method}\", ThriftMessageType::Call);\n", method=method.ident); 307 | 308 | ws(wr, 3); 309 | write!(wr, "let args = {}_{}_Args {{\n", service.ident, method.ident); 310 | 311 | for arg in method.args.iter() { 312 | ws(wr, 4); 313 | write!(wr, "{}: {},\n", arg.ident, arg.ident); 314 | } 315 | 316 | ws(wr, 3); 317 | write!(wr, "}};\n"); 318 | 319 | ws(wr, 3); 320 | write!(wr, "args.serialize(&mut se);\n"); 321 | 322 | ws(wr, 3); 323 | write!(wr, "se.write_message_end();\n"); 324 | 325 | ws(wr, 2); 326 | write!(wr, "}}\n"); 327 | 328 | ws(wr, 2); 329 | write!(wr, "self.dispatcher.send(Incoming::Call(\"{}\".to_string(), buf, Some(res))).unwrap();\n", method.ident); 330 | 331 | ws(wr, 2); 332 | write!(wr, "future.and_then(move |(msg, de)| {{\n"); 333 | 334 | ws(wr, 3); 335 | write!(wr, "Async::Ok(\"foobar\".to_string())\n"); 336 | 337 | ws(wr, 2); 338 | write!(wr, "}})\n"); 339 | 340 | ws(wr, 1); 341 | write!(wr, "}}\n"); 342 | } 343 | 344 | write!(wr, "}}\n"); 345 | Ok(()) 346 | } 347 | 348 | pub fn impl_serialize_args(wr: &mut Write, service: &Service) -> Result<(), Error> { 349 | for method in service.methods.iter() { 350 | ServiceCodegen::impl_serialize_arg(wr, &service.ident, method)?; 351 | } 352 | 353 | Ok(()) 354 | } 355 | 356 | pub fn serialize_arg(wr: &mut Write, arg: &StructField) -> Result<(), Error> { 357 | ws(wr, 2); 358 | 359 | write!(wr, "try!(s.write_field_begin(\"{}\", {}, {}));\n", arg.ident, arg.ty.to_protocol(), arg.seq); 360 | ws(wr, 2); 361 | write!(wr, "try!(self.{}.serialize(s));\n", arg.ident); 362 | ws(wr, 2); 363 | write!(wr, "try!(s.write_field_stop());\n"); 364 | ws(wr, 2); 365 | write!(wr, "try!(s.write_field_end());\n"); 366 | 367 | Ok(()) 368 | } 369 | 370 | pub fn deserialize_arg(wr: &mut Write, arg: &StructField) -> Result<(), Error> { 371 | 372 | let expr = match arg.ty { 373 | Ty::String => "de.deserialize_str()", 374 | Ty::I32 => "de.deserialize_i32()", 375 | Ty::I16 => "de.deserialize_i16()", 376 | Ty::I64 => "de.deserialize_i64()", 377 | _ => panic!("Unexpected type to deserialize_arg.") 378 | }; 379 | 380 | ws(wr, 3); 381 | write!(wr, "{}: {{\n", arg.ident); 382 | 383 | ws(wr, 4); 384 | write!(wr, "match try!(de.read_field_begin()).ty {{\n"); 385 | 386 | ws(wr, 5); 387 | write!(wr, "ThriftType::Stop => {{ try!(de.read_field_begin()); }},\n"); 388 | ws(wr, 5); 389 | write!(wr, "_ => {{}}\n"); 390 | 391 | ws(wr, 4); 392 | write!(wr, "}}\n"); 393 | 394 | ws(wr, 4); 395 | write!(wr, "let val = try!({});\n", expr); 396 | 397 | ws(wr, 4); 398 | write!(wr, "try!(de.read_field_end());\n"); 399 | ws(wr, 4); 400 | write!(wr, "val\n"); 401 | 402 | ws(wr, 3); 403 | write!(wr, "}},\n"); 404 | 405 | Ok(()) 406 | } 407 | 408 | pub fn impl_deserialize_args(wr: &mut Write, service: &Service) -> Result<(), Error> { 409 | for method in service.methods.iter() { 410 | ServiceCodegen::impl_deserialize_arg(wr, &service.ident, method); 411 | } 412 | Ok(()) 413 | } 414 | 415 | pub fn impl_deserialize_arg(wr: &mut Write, name: &str, method: &ServiceMethod) -> Result<(), Error> { 416 | write!(wr, "\nimpl Deserialize for {}_{}_Args {{\n", name, method.ident); 417 | ws(wr, 1); 418 | write!(wr, "fn deserialize(de: &mut D) -> Result\n"); 419 | ws(wr, 1); 420 | write!(wr, " where D: Deserializer + ThriftDeserializer\n"); 421 | ws(wr, 1); 422 | write!(wr, "{{\n"); 423 | 424 | ws(wr, 2); 425 | write!(wr, "try!(de.read_struct_begin());\n"); 426 | 427 | ws(wr, 2); 428 | write!(wr, "let args = {}_{}_Args {{\n", name, method.ident); 429 | 430 | for arg in method.args.iter() { 431 | ServiceCodegen::deserialize_arg(wr, arg)?; 432 | } 433 | 434 | ws(wr, 2); 435 | write!(wr, "}};\n"); 436 | 437 | ws(wr, 2); 438 | write!(wr, "try!(de.read_struct_end());\n"); 439 | ws(wr, 2); 440 | write!(wr, "Ok(args)\n"); 441 | 442 | ws(wr, 1); 443 | write!(wr, "}}"); 444 | write!(wr, "\n}}"); 445 | Ok(()) 446 | } 447 | 448 | pub fn impl_serialize_arg(wr: &mut Write, name: &str, method: &ServiceMethod) -> Result<(), Error> { 449 | write!(wr, "\nimpl Serialize for {}_{}_Args {{\n", name, method.ident); 450 | ws(wr, 1); 451 | write!(wr, "fn serialize(&self, s: &mut S) -> Result<(), Error>\n"); 452 | ws(wr, 1); 453 | write!(wr, " where S: Serializer + ThriftSerializer\n"); 454 | ws(wr, 1); 455 | write!(wr, "{{\n"); 456 | 457 | ws(wr, 2); 458 | write!(wr, "try!(s.write_struct_begin(\"{}_{}_Args\"));\n", name, method.ident); 459 | 460 | for arg in method.args.iter() { 461 | ServiceCodegen::serialize_arg(wr, arg)?; 462 | } 463 | 464 | ws(wr, 2); 465 | write!(wr, "try!(s.write_struct_end());\n"); 466 | ws(wr, 2); 467 | write!(wr, "Ok(())\n"); 468 | 469 | ws(wr, 1); 470 | write!(wr, "}}"); 471 | write!(wr, "\n}}"); 472 | Ok(()) 473 | } 474 | 475 | pub fn build_args_struct(wr: &mut Write, service: &Service) -> Result<(), Error> { 476 | for method in service.methods.iter() { 477 | ServiceCodegen::build_arg_struct(wr, &service.ident, method)?; 478 | } 479 | 480 | Ok(()) 481 | } 482 | 483 | pub fn build_arg_struct(wr: &mut Write, name: &str, method: &ServiceMethod) -> Result<(), Error> { 484 | write!(wr, "\nstruct {}_{}_Args {{\n", name, method.ident); 485 | 486 | for arg in method.args.iter() { 487 | ws(wr, 1); 488 | write!(wr, "{}: {},\n", arg.ident, arg.ty.to_string()); 489 | } 490 | 491 | write!(wr, "}}\n"); 492 | Ok(()) 493 | } 494 | 495 | pub fn build_client_service_impl(wr: &mut Write, service: &Service) -> Result<(), Error> { 496 | write!(wr, "\n\n"); 497 | write!(wr, "impl {}Client {{\n", service.ident); 498 | Ok(()) 499 | } 500 | 501 | pub fn build_client_impl(wr: &mut Write, service: &Service) -> Result<(), Error> { 502 | write!(wr, "\n\n"); 503 | write!(wr, "impl {}Client {{\n", service.ident); 504 | 505 | ws(wr, 1); 506 | write!(wr, "pub fn new(addr: SocketAddr) -> {}Client {{\n", service.ident); 507 | 508 | ws(wr, 2); 509 | write!(wr, "let (handle, tx) = Dispatcher::spawn(dispatcher::Role::Client(addr)).unwrap();\n"); 510 | 511 | write!(wr, "\n"); 512 | ws(wr, 2); 513 | write!(wr, "{}Client {{\n", service.ident); 514 | 515 | ws(wr, 3); 516 | write!(wr, "dispatcher: tx,\n"); 517 | 518 | ws(wr, 3); 519 | write!(wr, "handle: handle,\n"); 520 | 521 | ws(wr, 2); 522 | write!(wr, "}}\n"); 523 | 524 | ws(wr, 1); 525 | write!(wr, "}}\n"); 526 | 527 | write!(wr, "}}\n"); 528 | Ok(()) 529 | } 530 | 531 | pub fn build_client_struct(wr: &mut Write, service: &Service) -> Result<(), Error> { 532 | write!(wr, "\npub struct {}Client {{\n", service.ident); 533 | ws(wr, 1); 534 | write!(wr, "dispatcher: Sender,\n"); 535 | ws(wr, 1); 536 | write!(wr, "pub handle: JoinHandle>,\n"); 537 | write!(wr, "}}\n"); 538 | Ok(()) 539 | } 540 | 541 | pub fn build_trait(wr: &mut Write, service: &Service) -> Result<(), Error> { 542 | write!(wr, "\npub trait {}Service: Send {{\n", service.ident)?; 543 | 544 | for method in service.methods.iter() { 545 | ws(wr, 1); 546 | MethodCodegen::build(wr, method); 547 | write!(wr, ";\n"); 548 | } 549 | 550 | write!(wr, "}}\n")?; 551 | Ok(()) 552 | } 553 | } 554 | 555 | #[cfg(test)] 556 | mod tests { 557 | use super::*; 558 | use thrust_parser::{ 559 | Ty, 560 | ServiceMethod, 561 | Service, 562 | Struct, 563 | Enum, 564 | Namespace, 565 | FieldAttribute, 566 | StructField 567 | }; 568 | 569 | #[test] 570 | fn service_method_ret() { 571 | let method = ServiceMethod { 572 | ident: format!("Foobar"), 573 | ty: Ty::String, 574 | attr: FieldAttribute::Required, 575 | args: Vec::new() 576 | }; 577 | 578 | let ret = MethodCodegen::ret(&method.ty); 579 | assert_eq!(&*ret, "-> Future"); 580 | } 581 | 582 | #[test] 583 | fn arg() { 584 | let mut buf = Vec::new(); 585 | let arg = StructField { 586 | seq: 1, 587 | attr: FieldAttribute::Required, 588 | ty: Ty::I32, 589 | ident: "voodoo".to_string() 590 | }; 591 | 592 | let ret = MethodCodegen::arg(&mut buf, &arg); 593 | assert_eq!(buf, b", voodoo: i32"); 594 | } 595 | 596 | #[test] 597 | fn args() { 598 | let mut buf = Vec::new(); 599 | let arg = StructField { 600 | seq: 1, 601 | attr: FieldAttribute::Required, 602 | ty: Ty::I32, 603 | ident: "voodoo".to_string() 604 | }; 605 | 606 | let two = StructField { 607 | seq: 1, 608 | attr: FieldAttribute::Required, 609 | ty: Ty::String, 610 | ident: "sic".to_string() 611 | }; 612 | 613 | let ret = MethodCodegen::args(&mut buf, &vec![arg, two]); 614 | assert_eq!(buf, b", voodoo: i32, sic: String"); 615 | } 616 | 617 | #[test] 618 | fn service_method_build() { 619 | let mut buf = Vec::new(); 620 | let arg = StructField { 621 | seq: 1, 622 | attr: FieldAttribute::Required, 623 | ty: Ty::I32, 624 | ident: "voodoo".to_string() 625 | }; 626 | 627 | let ret = MethodCodegen::build(&mut buf, &ServiceMethod { 628 | ident: "query".to_string(), 629 | ty: Ty::String, 630 | attr: FieldAttribute::Required, 631 | args: vec![arg] 632 | }); 633 | assert_eq!(&*String::from_utf8(buf).unwrap(), "fn query(&mut self, voodoo: i32) -> Future;\n"); 634 | } 635 | 636 | #[test] 637 | fn service_trait_build() { 638 | let mut buf = Vec::new(); 639 | let arg = StructField { 640 | seq: 1, 641 | attr: FieldAttribute::Required, 642 | ty: Ty::I32, 643 | ident: "voodoo".to_string() 644 | }; 645 | 646 | let service = Service { 647 | ident: "Flock".to_string(), 648 | methods: vec![ServiceMethod { 649 | ident: "query".to_string(), 650 | ty: Ty::String, 651 | attr: FieldAttribute::Required, 652 | args: vec![arg] 653 | }] 654 | }; 655 | 656 | let ret = ServiceCodegen::build_trait(&mut buf, &service); 657 | } 658 | } 659 | -------------------------------------------------------------------------------- /thrust-examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "thrust-examples" 3 | version = "0.1.0" 4 | authors = ["Daniel Fagnan "] 5 | 6 | [dependencies] 7 | tangle = "*" 8 | 9 | [dependencies.thrust] 10 | path = ".." 11 | -------------------------------------------------------------------------------- /thrust-examples/main.thrift: -------------------------------------------------------------------------------- 1 | namespace rust foobar1 2 | 3 | service Blizzard { 4 | string ack(1: i64 source_id, 2: i64 tuple_id); 5 | } 6 | -------------------------------------------------------------------------------- /thrust-examples/src/foobar.rs: -------------------------------------------------------------------------------- 1 | // autogenerated by thrust 2 | #![allow(dead_code, unused_imports)] 3 | use thrust::protocol::{Error, ThriftType}; 4 | use thrust::{ThrustResult, ThrustError}; 5 | use thrust::dispatcher::{self, Dispatcher, Incoming}; 6 | use thrust::reactor::Message; 7 | use std::thread::JoinHandle; 8 | use std::net::SocketAddr; 9 | use std::sync::mpsc::{Sender, Receiver}; 10 | use tangle::{Future, Async}; 11 | use std::collections::{HashMap, HashSet}; 12 | use thrust::protocol::{ThriftDeserializer, ThriftSerializer}; 13 | use thrust::protocol::{Serializer, Deserializer}; 14 | use thrust::protocol::{Deserialize, Serialize, ThriftMessage, ThriftMessageType}; 15 | use thrust::binary_protocol::{BinarySerializer, BinaryDeserializer}; 16 | use thrust::Runner; 17 | 18 | 19 | pub trait BlizzardService: Send { 20 | fn ack(&mut self, source_id: i64, tuple_id: i64) -> Future; 21 | } 22 | 23 | pub struct BlizzardClient { 24 | dispatcher: Sender, 25 | pub handle: JoinHandle>, 26 | } 27 | 28 | 29 | impl BlizzardClient { 30 | pub fn new(addr: SocketAddr) -> BlizzardClient { 31 | let (handle, tx) = Dispatcher::spawn(dispatcher::Role::Client(addr)).unwrap(); 32 | 33 | BlizzardClient { 34 | dispatcher: tx, 35 | handle: handle, 36 | } 37 | } 38 | } 39 | 40 | struct Blizzard_ack_Args { 41 | source_id: i64, 42 | tuple_id: i64, 43 | } 44 | 45 | impl Serialize for Blizzard_ack_Args { 46 | fn serialize(&self, s: &mut S) -> Result<(), Error> 47 | where S: Serializer + ThriftSerializer 48 | { 49 | try!(s.write_struct_begin("Blizzard_ack_Args")); 50 | try!(s.write_field_begin("source_id", ThriftType::I64, 1)); 51 | try!(self.source_id.serialize(s)); 52 | try!(s.write_field_stop()); 53 | try!(s.write_field_end()); 54 | try!(s.write_field_begin("tuple_id", ThriftType::I64, 2)); 55 | try!(self.tuple_id.serialize(s)); 56 | try!(s.write_field_stop()); 57 | try!(s.write_field_end()); 58 | try!(s.write_struct_end()); 59 | Ok(()) 60 | } 61 | } 62 | impl Deserialize for Blizzard_ack_Args { 63 | fn deserialize(de: &mut D) -> Result 64 | where D: Deserializer + ThriftDeserializer 65 | { 66 | try!(de.read_struct_begin()); 67 | let args = Blizzard_ack_Args { 68 | source_id: { 69 | match try!(de.read_field_begin()).ty { 70 | ThriftType::Stop => { try!(de.read_field_begin()); }, 71 | _ => {} 72 | } 73 | let val = try!(de.deserialize_i64()); 74 | try!(de.read_field_end()); 75 | val 76 | }, 77 | tuple_id: { 78 | match try!(de.read_field_begin()).ty { 79 | ThriftType::Stop => { try!(de.read_field_begin()); }, 80 | _ => {} 81 | } 82 | let val = try!(de.deserialize_i64()); 83 | try!(de.read_field_end()); 84 | val 85 | }, 86 | }; 87 | try!(de.read_struct_end()); 88 | Ok(args) 89 | } 90 | } 91 | impl BlizzardService for BlizzardClient { 92 | 93 | fn ack(&mut self, source_id: i64, tuple_id: i64) -> Future { 94 | use std::io::Cursor; 95 | let (res, future) = Future::<(ThriftMessage, BinaryDeserializer>>)>::channel(); 96 | let mut buf = Vec::new(); 97 | { 98 | let mut se = BinarySerializer::new(&mut buf); 99 | se.write_message_begin("ack", ThriftMessageType::Call); 100 | let args = Blizzard_ack_Args { 101 | source_id: source_id, 102 | tuple_id: tuple_id, 103 | }; 104 | args.serialize(&mut se); 105 | se.write_message_end(); 106 | } 107 | 108 | self.dispatcher.send(Incoming::Call("ack".to_string(), buf, Some(res))).unwrap(); 109 | future.and_then(move |(msg, mut de)| { 110 | de.read_struct_begin(); 111 | de.read_field_begin(); 112 | let ret = de.deserialize_str().unwrap(); 113 | de.read_field_end(); 114 | de.read_struct_end(); 115 | Async::Ok(ret) 116 | }) 117 | } 118 | } 119 | 120 | // impl Runner for BlizzardRunner 121 | // where S: BlizzardService 122 | // { 123 | // fn run(&mut self, de: &mut D, msg: ThriftMessage) -> Result>, Error> 124 | // where D: Deserializer + ThriftDeserializer, 125 | // { 126 | // match &*msg.name { 127 | // "ack" => { 128 | // let args: Blizzard_ack_Args = try!(Deserialize::deserialize(de)); 129 | // let ret = self.service.ack(args.source_id, args.tuple_id).map(|val| { 130 | // let mut buf = Vec::new(); 131 | // { 132 | // let mut s = BinarySerializer::new(&mut buf); 133 | // s.write_message_begin("ack", ThriftMessageType::Reply); 134 | // s.write_struct_begin("ack_ret"); 135 | // s.write_field_begin("ret", ThriftType::String, 1); 136 | // val.serialize(&mut s); 137 | // s.write_field_stop(); 138 | // s.write_field_end(); 139 | // s.write_struct_end(); 140 | // s.write_message_end(); 141 | // } 142 | 143 | // buf 144 | // }); 145 | // Ok(ret) 146 | // }, 147 | // _ => unimplemented!() 148 | // } 149 | // } 150 | // } 151 | 152 | // pub struct BlizzardRunner { 153 | // service: S 154 | // } 155 | 156 | // impl BlizzardRunner where S: BlizzardService { 157 | // pub fn new(service: S) -> BlizzardRunner { 158 | // BlizzardRunner { 159 | // service: service 160 | // } 161 | // } 162 | // } 163 | 164 | // pub struct BlizzardServer { 165 | // dispatcher: Sender, 166 | // pub handle: JoinHandle>, 167 | // } 168 | 169 | // impl BlizzardServer { 170 | // /// ```notrust 171 | // /// BlizzardServer::new(Server, addr); 172 | // /// ``` 173 | // pub fn new(service: S, addr: SocketAddr) -> BlizzardServer 174 | // where S: 'static + BlizzardService 175 | // { 176 | // use std::thread; 177 | // use std::sync::mpsc::channel; 178 | // use std::io::Cursor; 179 | 180 | // let (sender, receiver) = channel(); 181 | // let (handle, tx) = Dispatcher::spawn(dispatcher::Role::Server(addr, sender)).unwrap(); 182 | 183 | // let send_tx = tx.clone(); 184 | // thread::spawn(move || { 185 | // let mut runner = BlizzardRunner::new(service); 186 | // for (token, buf) in receiver.iter() { 187 | // let mut de = BinaryDeserializer::new(Cursor::new(buf)); 188 | // match de.read_message_begin() { 189 | // Ok(msg) => { 190 | // match runner.run(&mut de, msg) { 191 | // Ok(f) => { 192 | // let chan = send_tx.clone(); 193 | // f.and_then(move |buf| { 194 | // chan.send(Incoming::Reply(token, buf)); 195 | // Async::Ok(()) 196 | // }); 197 | // }, 198 | // Err(err) => {} 199 | // } 200 | // }, 201 | // Err(err) => { 202 | // println!("[server]: error parsing thrift message: {:?}", err); 203 | // } 204 | // } 205 | // } 206 | // }); 207 | 208 | // BlizzardServer { 209 | // dispatcher: tx, 210 | // handle: handle, 211 | // } 212 | // } 213 | // } 214 | -------------------------------------------------------------------------------- /thrust-examples/src/foobar1.rs: -------------------------------------------------------------------------------- 1 | // autogenerated by thrust 2 | #![allow(dead_code, unused_imports)] 3 | use thrust::protocol::{Error, ThriftType}; 4 | use thrust::{ThrustResult, ThrustError}; 5 | use thrust::dispatcher::{self, Dispatcher, Incoming}; 6 | use thrust::reactor::Message; 7 | use std::thread::JoinHandle; 8 | use std::net::SocketAddr; 9 | use thrust::Runner; 10 | use std::sync::mpsc::{Sender, Receiver}; 11 | use tangle::{Future, Async}; 12 | use std::collections::{HashMap, HashSet}; 13 | use thrust::protocol::{ThriftDeserializer, ThriftSerializer, ThriftMessageType}; 14 | use thrust::protocol::{Serializer, Deserializer}; 15 | use thrust::protocol::{Deserialize, Serialize, ThriftMessage}; 16 | use thrust::binary_protocol::{BinarySerializer, BinaryDeserializer}; 17 | 18 | 19 | pub trait BlizzardService: Send { 20 | fn ack(&mut self, source_id: i64, tuple_id: i64) -> Future; 21 | } 22 | 23 | pub struct BlizzardClient { 24 | dispatcher: Sender, 25 | pub handle: JoinHandle>, 26 | } 27 | 28 | 29 | impl BlizzardClient { 30 | pub fn new(addr: SocketAddr) -> BlizzardClient { 31 | let (handle, tx) = Dispatcher::spawn(dispatcher::Role::Client(addr)).unwrap(); 32 | 33 | BlizzardClient { 34 | dispatcher: tx, 35 | handle: handle, 36 | } 37 | } 38 | } 39 | 40 | struct Blizzard_ack_Args { 41 | source_id: i64, 42 | tuple_id: i64, 43 | } 44 | 45 | impl Serialize for Blizzard_ack_Args { 46 | fn serialize(&self, s: &mut S) -> Result<(), Error> 47 | where S: Serializer + ThriftSerializer 48 | { 49 | try!(s.write_struct_begin("Blizzard_ack_Args")); 50 | try!(s.write_field_begin("source_id", ThriftType::I64, 1)); 51 | try!(self.source_id.serialize(s)); 52 | try!(s.write_field_stop()); 53 | try!(s.write_field_end()); 54 | try!(s.write_field_begin("tuple_id", ThriftType::I64, 2)); 55 | try!(self.tuple_id.serialize(s)); 56 | try!(s.write_field_stop()); 57 | try!(s.write_field_end()); 58 | try!(s.write_struct_end()); 59 | Ok(()) 60 | } 61 | } 62 | impl Deserialize for Blizzard_ack_Args { 63 | fn deserialize(de: &mut D) -> Result 64 | where D: Deserializer + ThriftDeserializer 65 | { 66 | try!(de.read_struct_begin()); 67 | let args = Blizzard_ack_Args { 68 | source_id: { 69 | match try!(de.read_field_begin()).ty { 70 | ThriftType::Stop => { try!(de.read_field_begin()); }, 71 | _ => {} 72 | } 73 | let val = try!(de.deserialize_i64()); 74 | try!(de.read_field_end()); 75 | val 76 | }, 77 | tuple_id: { 78 | match try!(de.read_field_begin()).ty { 79 | ThriftType::Stop => { try!(de.read_field_begin()); }, 80 | _ => {} 81 | } 82 | let val = try!(de.deserialize_i64()); 83 | try!(de.read_field_end()); 84 | val 85 | }, 86 | }; 87 | try!(de.read_struct_end()); 88 | Ok(args) 89 | } 90 | } 91 | impl BlizzardService for BlizzardClient { 92 | 93 | fn ack(&mut self, source_id: i64, tuple_id: i64) -> Future { 94 | use std::io::Cursor; 95 | let (res, future) = Future::<(ThriftMessage, BinaryDeserializer>>)>::channel(); 96 | let mut buf = Vec::new(); 97 | { 98 | let mut se = BinarySerializer::new(&mut buf); 99 | se.write_message_begin("ack", ThriftMessageType::Call); 100 | let args = Blizzard_ack_Args { 101 | source_id: source_id, 102 | tuple_id: tuple_id, 103 | }; 104 | args.serialize(&mut se); 105 | se.write_message_end(); 106 | } 107 | self.dispatcher.send(Incoming::Call("ack".to_string(), buf, Some(res))).unwrap(); 108 | future.and_then(move |(msg, de)| { 109 | Async::Ok("foobar".to_string()) 110 | }) 111 | } 112 | } 113 | 114 | 115 | pub struct BlizzardServer { dispatcher: Sender, 116 | pub handle: JoinHandle>, 117 | } 118 | 119 | impl BlizzardServer { 120 | pub fn new(service: S, addr: SocketAddr) -> BlizzardServer 121 | where S: 'static + BlizzardService 122 | { 123 | use std::thread; 124 | use std::sync::mpsc::channel; 125 | use std::io::Cursor; 126 | 127 | let (sender, receiver) = channel(); 128 | let (handle, tx) = Dispatcher::spawn(dispatcher::Role::Server(addr, sender)).unwrap(); 129 | 130 | let send_tx = tx.clone(); 131 | thread::spawn(move || { 132 | let mut runner = BlizzardRunner::new(service); 133 | for (token, buf) in receiver.iter() { 134 | let mut de = BinaryDeserializer::new(Cursor::new(buf)); 135 | match de.read_message_begin() { 136 | Ok(msg) => { 137 | match runner.run(&mut de, msg) { 138 | Ok(f) => { 139 | let chan = send_tx.clone(); 140 | f.and_then(move |buf| { 141 | chan.send(Incoming::Reply(token, buf)); 142 | Async::Ok(()) 143 | }); 144 | }, 145 | Err(err) => { 146 | 147 | } 148 | } 149 | }, 150 | Err(err) => { 151 | println!("[server]: error parsing thrift message: {:?}", err); 152 | } 153 | } 154 | } 155 | }); 156 | 157 | BlizzardServer { 158 | dispatcher: tx, 159 | handle: handle, 160 | } 161 | } 162 | } 163 | pub struct BlizzardRunner { 164 | service: S 165 | } 166 | 167 | impl BlizzardRunner where S: BlizzardService { 168 | pub fn new(service: S) -> BlizzardRunner { 169 | BlizzardRunner { 170 | service: service 171 | } 172 | } 173 | } 174 | impl Runner for BlizzardRunner 175 | where S: BlizzardService 176 | { 177 | fn run(&mut self, de: &mut D, msg: ThriftMessage) -> Result>, Error> 178 | where D: Deserializer + ThriftDeserializer 179 | { 180 | match &*msg.name { 181 | "ack" => { 182 | let args: Blizzard_ack_Args = try!(Deserialize::deserialize(de)); 183 | let ret = self.service.ack(args.source_id,args.tuple_id, 184 | ).map(|val| { 185 | let mut buf = Vec::new(); 186 | { 187 | let mut s = BinarySerializer::new(&mut buf); 188 | 189 | s.write_message_begin("ack", ThriftMessageType::Reply); 190 | s.write_struct_begin("ack_ret"); 191 | s.write_field_begin("ret", ThriftType::String, 1); 192 | val.serialize(&mut s); 193 | s.write_field_stop(); 194 | s.write_field_end(); 195 | s.write_struct_end(); 196 | s.write_message_end(); 197 | } 198 | buf 199 | }); 200 | Ok(ret) 201 | }, _ => unimplemented!() 202 | } 203 | } 204 | } -------------------------------------------------------------------------------- /thrust-examples/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate thrust; 2 | extern crate tangle; 3 | 4 | pub mod foobar1; 5 | use foobar1::{ 6 | BlizzardService, 7 | BlizzardClient, 8 | BlizzardServer 9 | }; 10 | 11 | use thrust::Reactor; 12 | use std::net::SocketAddr; 13 | use std::thread; 14 | use std::time::Duration; 15 | use tangle::{Async, Future}; 16 | 17 | struct Blizzard; 18 | 19 | impl BlizzardService for Blizzard { 20 | fn ack(&mut self, source_id: i64, tuple_id: i64) -> Future { 21 | println!("Received an ack from source[{}] and tuple[{}]", source_id, tuple_id); 22 | Future::unit("ack was successful!".to_string()) 23 | } 24 | } 25 | 26 | #[test] 27 | fn create_a_client() { 28 | let addr: SocketAddr = "127.0.0.1:2767".parse().unwrap(); 29 | let server = BlizzardServer::new(Blizzard, addr.clone()); 30 | 31 | thread::sleep(Duration::from_millis(25)); 32 | let mut rpc = BlizzardClient::new(addr.clone()); 33 | 34 | rpc.ack(45, 99).and_then(move |res| { 35 | println!("{:?}", res); 36 | Async::Ok(()) 37 | }); 38 | 39 | Reactor::run().join(); 40 | rpc.handle.join(); 41 | server.handle.join(); 42 | } 43 | -------------------------------------------------------------------------------- /thrust-macros-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "thrust_macros_test" 3 | version = "0.1.0" 4 | authors = ["Daniel Fagnan "] 5 | 6 | [dependencies] 7 | tangle = "*" 8 | 9 | [dependencies.thrust_macros] 10 | path = "../thrust-macros" 11 | 12 | [dependencies.thrust] 13 | path = ".." 14 | -------------------------------------------------------------------------------- /thrust-macros-test/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(plugin)] 2 | #![plugin(thrust_macros)] 3 | 4 | extern crate thrust; 5 | extern crate tangle; 6 | 7 | use thrust::reactor::Reactor; 8 | use thrust::binary_protocol::*; 9 | use thrust::protocol::*; 10 | use std::net::SocketAddr; 11 | use std::io::{Cursor, Read, Write}; 12 | 13 | thrust!(" 14 | namespace rust foobar1 15 | 16 | service FlockDb { 17 | string query(1: string voodoo, 2: i32 mission_control); 18 | } 19 | "); 20 | 21 | #[test] 22 | fn client() { 23 | // let addr = "127.0.0.1:5656".parse().unwrap(); 24 | // let rpc = foobar1::FlockDbClient::new(addr); 25 | // Reactor::run(); 26 | } 27 | 28 | #[test] 29 | fn args_deserialize_gen() { 30 | let mut buf = Vec::new(); 31 | 32 | { 33 | let mut se = BinarySerializer::new(&mut buf); 34 | let args = foobar1::FlockDb_query_Args { 35 | voodoo: "Hello".to_string(), 36 | mission_control: 500 37 | }; 38 | 39 | args.serialize(&mut se).unwrap(); 40 | } 41 | 42 | let mut rd = Cursor::new(buf); 43 | let mut de = BinaryDeserializer::new(rd); 44 | let args = foobar1::FlockDb_query_Args::deserialize(&mut de).unwrap(); 45 | assert_eq!(&*args.voodoo, "Hello"); 46 | assert_eq!(args.mission_control, 500); 47 | } 48 | 49 | #[test] 50 | fn manual_args_deserialize() { 51 | let mut buf = Vec::new(); 52 | 53 | { 54 | let mut se = BinarySerializer::new(&mut buf); 55 | se.write_struct_begin("FlockDb_query_Args").unwrap(); 56 | 57 | se.write_field_begin("voodoo", ThriftType::String, 1).unwrap(); 58 | "Hello".to_string().serialize(&mut se); 59 | se.write_field_stop(); 60 | se.write_field_end(); 61 | 62 | se.write_field_begin("mission_control", ThriftType::I32, 2).unwrap(); 63 | let i: i32 = 500; 64 | i.serialize(&mut se); 65 | se.write_field_stop(); 66 | se.write_field_end(); 67 | 68 | se.write_struct_end(); 69 | } 70 | 71 | let mut rd = Cursor::new(buf); 72 | let mut de = BinaryDeserializer::new(rd); 73 | let msg = de.read_struct_begin().unwrap(); 74 | let voodoo = de.read_field_begin().unwrap(); 75 | assert!(voodoo.name.is_none()); 76 | assert_eq!(voodoo.seq, 1); 77 | assert_eq!(voodoo.ty, ThriftType::String); 78 | assert_eq!(&*de.deserialize_str().unwrap(), "Hello"); 79 | de.read_field_begin().unwrap(); 80 | let mission = de.read_field_begin().unwrap(); 81 | assert_eq!(mission.seq, 2); 82 | assert_eq!(mission.ty, ThriftType::I32); 83 | assert_eq!(de.deserialize_i32().unwrap(), 500); 84 | } 85 | 86 | #[test] 87 | fn serialize() { 88 | let mut buf = Vec::new(); 89 | let mut comp = Vec::new(); 90 | 91 | { 92 | let mut se = BinarySerializer::new(&mut buf); 93 | let args = foobar1::FlockDb_query_Args { 94 | voodoo: "Hello".to_string(), 95 | mission_control: 500 96 | }; 97 | 98 | args.serialize(&mut se).unwrap(); 99 | } 100 | 101 | { 102 | let mut se = BinarySerializer::new(&mut comp); 103 | se.write_struct_begin("FlockDb_query_Args").unwrap(); 104 | 105 | se.write_field_begin("voodoo", ThriftType::String, 1).unwrap(); 106 | "Hello".to_string().serialize(&mut se); 107 | se.write_field_stop(); 108 | se.write_field_end(); 109 | 110 | se.write_field_begin("mission_control", ThriftType::I32, 2).unwrap(); 111 | let i: i32 = 500; 112 | i.serialize(&mut se); 113 | se.write_field_stop(); 114 | se.write_field_end(); 115 | 116 | se.write_struct_end(); 117 | } 118 | 119 | assert_eq!(buf.len(), comp.len()); 120 | 121 | for i in 0..buf.len() { 122 | assert_eq!(buf[i], comp[i]); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /thrust-macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "thrust_macros" 3 | version = "0.1.0" 4 | authors = ["Daniel Fagnan "] 5 | 6 | [lib] 7 | crate-type = ["dylib"] 8 | name = "thrust_macros" 9 | path = "src/lib.rs" 10 | plugin = true 11 | 12 | [dependencies.thrust_parser] 13 | path = "../thrust-parser" 14 | -------------------------------------------------------------------------------- /thrust-macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![crate_type="dylib"] 2 | #![feature(plugin_registrar, quote, rustc_private, question_mark, concat_idents)] 3 | 4 | extern crate thrust_parser; 5 | extern crate syntax; 6 | extern crate rustc; 7 | extern crate rustc_plugin; 8 | 9 | use thrust_parser::{Ast, Parser}; 10 | use syntax::util::small_vector::SmallVector; 11 | use std::iter::Iterator; 12 | use syntax::codemap::Span; 13 | use syntax::fold::Folder; 14 | use syntax::parse::{parser, token}; 15 | use syntax::print::pprust; 16 | use syntax::ast::{self, TokenTree}; 17 | use syntax::ptr::P; 18 | use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; 19 | use rustc_plugin::Registry; 20 | 21 | pub struct Compiler<'a: 'x, 'x> { 22 | inner: parser::Parser<'a>, 23 | cx: &'x mut ExtCtxt<'a> 24 | } 25 | 26 | impl<'a, 'x> Compiler<'a, 'x> { 27 | pub fn new(cx: &'x mut ExtCtxt<'a>, args: &[TokenTree]) -> Compiler<'a, 'x> { 28 | Compiler::<'a, 'x> { 29 | inner: cx.new_parser_from_tts::<'a>(args), 30 | cx: cx 31 | } 32 | } 33 | 34 | pub fn parse(&mut self) -> Option { 35 | if let Ok(expr) = self.inner.parse_expr() { 36 | let entry = self.cx.expander().fold_expr(expr); 37 | let th = match entry.node { 38 | ast::ExprKind::Lit(ref lit) => { 39 | match lit.node { 40 | ast::LitKind::Str(ref s, _) => s.to_string(), 41 | _ => { 42 | self.cx.span_err(entry.span, &format!( 43 | "expected string literal but got `{}`", 44 | pprust::lit_to_string(&**lit))); 45 | return None; 46 | } 47 | } 48 | }, 49 | _ => { 50 | self.cx.span_err(entry.span, &format!( 51 | "expected string literal but got `{}`", 52 | pprust::expr_to_string(&*entry))); 53 | return None 54 | } 55 | }; 56 | if !self.inner.eat(&token::Eof) { 57 | self.cx.span_err(self.inner.span, "only one string literal allowed"); 58 | return None; 59 | } 60 | 61 | Some(th) 62 | } else { 63 | self.cx.parse_sess().span_diagnostic.err("failure parsing token tree"); 64 | return None; 65 | } 66 | } 67 | 68 | pub fn code(&mut self, input: String) -> Result, thrust_parser::Error> { 69 | let mut parser = Parser::new(&input); 70 | let mut items = Vec::new(); 71 | 72 | // We expect a namespace to appear first. 73 | let ns = parser.parse_namespace()?; 74 | let module = token::str_to_ident(&ns.module); 75 | 76 | while let Ok(node) = parser.parse_item() { 77 | match node.ir(self.cx) { 78 | Some(item) => items.push(item), 79 | // The node didn't want to export an item. All good! 80 | None => {} 81 | } 82 | 83 | let v = node.second_ir(self.cx); 84 | 85 | for item in v.into_iter() { 86 | items.push(item); 87 | } 88 | } 89 | 90 | // pieces.push(parser.parse_enum()?.ir(self.cx)); 91 | // pieces.push(parser.parse_struct()?.ir(self.cx)); 92 | 93 | Ok(quote_item!(self.cx, pub mod $module { 94 | #![allow(dead_code, unused_imports)] 95 | use thrust::protocol::{Error, ThriftType}; 96 | use thrust::{ThrustResult, ThrustError}; 97 | use thrust::dispatcher::{self, Dispatcher, Incoming}; 98 | use thrust::reactor::Message; 99 | use std::thread::JoinHandle; 100 | use std::net::SocketAddr; 101 | use std::sync::mpsc::{Sender, Receiver}; 102 | use tangle::{Future, Async}; 103 | use std::collections::{HashMap, HashSet}; 104 | use thrust::protocol::{ThriftDeserializer, ThriftSerializer}; 105 | use thrust::protocol::{Serializer, Deserializer}; 106 | use thrust::protocol::{Deserialize, Serialize, ThriftMessage}; 107 | use thrust::binary_protocol::{BinarySerializer, BinaryDeserializer}; 108 | $items 109 | }).unwrap()) 110 | } 111 | } 112 | 113 | fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) -> Box { 114 | if args.len() == 0 { 115 | // XXX: Return an empty future. 116 | return DummyResult::any(sp); 117 | } 118 | 119 | let mut compiler = Compiler::new(cx, args); 120 | let input = match compiler.parse() { 121 | Some(s) => s, 122 | None => panic!("Expected a string") 123 | }; 124 | 125 | MacEager::items(SmallVector::one(compiler.code(input).unwrap())) 126 | } 127 | 128 | #[plugin_registrar] 129 | pub fn plugin_registrar(reg: &mut Registry) { 130 | reg.register_macro("thrust", expand_rn); 131 | } 132 | -------------------------------------------------------------------------------- /thrust-parser/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "thrust_parser" 3 | version = "0.1.0" 4 | authors = ["Daniel Fagnan "] 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /thrust-parser/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(question_mark, quote, rustc_private, associated_type_defaults)] 2 | 3 | use std::char; 4 | use std::io::{Read, Write}; 5 | 6 | #[derive(Debug, PartialEq, Eq, Clone)] 7 | pub enum Ty { 8 | String, 9 | Void, 10 | Byte, 11 | Bool, 12 | Binary, 13 | I16, 14 | I32, 15 | I64, 16 | Double, 17 | List(Box), 18 | Set(Box), 19 | Map(Box, Box), 20 | Option(Box), 21 | // User-defined type. 22 | Ident(String) 23 | } 24 | 25 | impl From for Ty { 26 | fn from(val: String) -> Ty { 27 | match &*val { 28 | "string" => Ty::String, 29 | "void" => Ty::Void, 30 | "byte" => Ty::Byte, 31 | "bool" => Ty::Bool, 32 | "binary" => Ty::Binary, 33 | "i16" => Ty::I16, 34 | "i32" => Ty::I32, 35 | "i64" => Ty::I64, 36 | "double" => Ty::Double, 37 | _ => Ty::Ident(val) 38 | } 39 | } 40 | } 41 | 42 | impl Ty { 43 | pub fn to_protocol(&self) -> &'static str { 44 | match self { 45 | &Ty::String => "ThriftType::String", 46 | &Ty::Void => "ThriftType::Void", 47 | &Ty::Bool => "ThriftType::Bool", 48 | &Ty::Byte => "ThriftType::Byte", 49 | &Ty::Double => "ThriftType::Double", 50 | &Ty::I16 => "ThriftType::I16", 51 | &Ty::I32 => "ThriftType::I32", 52 | &Ty::I64 => "ThriftType::I64", 53 | &Ty::Map(_, _) => "ThriftType::Map", 54 | &Ty::List(_) => "ThriftType::List", 55 | &Ty::Set(_) => "ThriftType::Set", 56 | &Ty::Binary => "ThriftType::List", 57 | _ => panic!("Not compatible with ThriftType") 58 | } 59 | } 60 | 61 | pub fn to_string(&self) -> String { 62 | match self { 63 | &Ty::String => "String".to_string(), 64 | &Ty::Void => "()".to_string(), 65 | &Ty::Byte => "i8".to_string(), 66 | &Ty::Bool => "bool".to_string(), 67 | &Ty::Binary => "Vec".to_string(), 68 | &Ty::I16 => "i16".to_string(), 69 | &Ty::I32 => "i32".to_string(), 70 | &Ty::I64 => "i64".to_string(), 71 | &Ty::Double => "double".to_string(), 72 | &Ty::Option(ref t) => { 73 | let inner = t.to_string(); 74 | format!("Option<{}>", inner) 75 | }, 76 | &Ty::List(ref s) => { 77 | let inner = s.to_string(); 78 | format!("Vec<{}>", inner) 79 | }, 80 | &Ty::Set(ref s) => { 81 | let inner = s.to_string(); 82 | format!("HashSet<{}>", inner) 83 | }, 84 | &Ty::Map(ref a, ref b) => { 85 | let a = a.to_string(); 86 | let b = b.to_string(); 87 | format!("HashMap<{}, {}>", a, b) 88 | }, 89 | &Ty::Ident(ref s) => { 90 | s.clone() 91 | } 92 | } 93 | } 94 | } 95 | 96 | #[derive(Debug, PartialEq, Eq)] 97 | pub struct Include { 98 | pub path: String 99 | } 100 | 101 | #[derive(Debug, PartialEq, Eq)] 102 | pub struct Service { 103 | pub ident: String, 104 | pub methods: Vec 105 | } 106 | 107 | #[derive(Debug, PartialEq, Eq)] 108 | pub struct ServiceMethod { 109 | pub ident: String, 110 | pub ty: Ty, 111 | pub attr: FieldAttribute, 112 | pub args: Vec 113 | } 114 | 115 | #[derive(Debug, PartialEq, Eq)] 116 | pub struct Enum { 117 | pub ident: String, 118 | pub variants: Vec 119 | } 120 | 121 | #[derive(Debug, PartialEq, Eq)] 122 | pub struct Struct { 123 | pub ident: String, 124 | pub fields: Vec 125 | } 126 | 127 | #[derive(Debug, PartialEq, Eq)] 128 | pub enum FieldAttribute { 129 | Optional, 130 | Required, 131 | Oneway 132 | } 133 | 134 | #[derive(Debug, PartialEq, Eq)] 135 | pub struct StructField { 136 | pub seq: i16, 137 | pub attr: FieldAttribute, 138 | pub ty: Ty, 139 | pub ident: String 140 | } 141 | 142 | #[derive(Debug, PartialEq, Eq)] 143 | pub struct Typedef(pub Ty, pub String); 144 | 145 | #[derive(Debug, PartialEq, Eq)] 146 | pub struct Namespace { 147 | pub lang: String, 148 | pub module: String 149 | } 150 | 151 | #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] 152 | pub enum Keyword { 153 | Struct, 154 | Service, 155 | Enum, 156 | Namespace, 157 | Required, 158 | Optional, 159 | Oneway, 160 | Typedef, 161 | Throws, 162 | Exception, 163 | Include, 164 | Const, 165 | } 166 | 167 | #[derive(Debug, PartialEq, Eq, Hash, Clone)] 168 | pub enum Token { 169 | Eq, 170 | Colon, 171 | SingleQuote, 172 | Dot, 173 | Semi, 174 | At, 175 | Comma, 176 | LCurly, 177 | RCurly, 178 | LAngle, 179 | RAngle, 180 | LParen, 181 | RParen, 182 | Number(i16), 183 | QuotedString(String), 184 | Ident(String), 185 | Keyword(Keyword), 186 | 187 | /// Useless comments. 188 | Comment, 189 | Whitespace, 190 | Eof, 191 | B, 192 | } 193 | 194 | #[derive(Debug, PartialEq, Eq)] 195 | pub enum Error { 196 | Expected, 197 | MissingFieldAttribute, 198 | ExpectedNumber, 199 | ExpectedString, 200 | ExpectedKeyword(Keyword), 201 | ExpectedIdent, 202 | ExpectedToken(Token), 203 | NoMoreItems 204 | } 205 | 206 | pub struct Parser<'a> { 207 | buffer: &'a str, 208 | pos: usize, 209 | pub token: Token, 210 | last_token_eof: bool 211 | } 212 | 213 | impl<'a> Parser<'a> { 214 | pub fn new(input: &'a str) -> Parser<'a> { 215 | Parser { 216 | buffer: input, 217 | pos: 0, 218 | token: Token::B, 219 | last_token_eof: false 220 | } 221 | } 222 | 223 | pub fn parse_struct(&mut self) -> Result { 224 | self.expect_keyword(Keyword::Struct)?; 225 | 226 | let ident = self.expect_ident()?; 227 | let mut fields = Vec::new(); 228 | 229 | self.expect(&Token::LCurly)?; 230 | 231 | loop { 232 | if self.eat(&Token::RCurly) { 233 | break; 234 | } 235 | 236 | fields.push(self.parse_struct_field()?); 237 | 238 | if self.eat(&Token::Semi) { 239 | continue; 240 | } else { 241 | break; 242 | } 243 | } 244 | 245 | Ok(Struct { 246 | ident: ident, 247 | fields: fields 248 | }) 249 | } 250 | 251 | pub fn parse_struct_field(&mut self) -> Result { 252 | let seq = self.parse_number()?; 253 | 254 | self.expect(&Token::Colon)?; 255 | 256 | let attr = if self.eat_keyword(Keyword::Optional) { 257 | FieldAttribute::Optional 258 | } else if self.eat_keyword(Keyword::Required) { 259 | FieldAttribute::Required 260 | } else { 261 | return Err(Error::MissingFieldAttribute); 262 | }; 263 | 264 | let ty = self.parse_ty()?; 265 | let ident = self.parse_ident()?; 266 | 267 | Ok(StructField { 268 | seq: seq, 269 | attr: attr, 270 | ty: ty, 271 | ident: ident 272 | }) 273 | } 274 | 275 | pub fn parse_number(&mut self) -> Result { 276 | self.skip_b(); 277 | 278 | let n = match self.token { 279 | Token::Number(n) => n, 280 | _ => return Err(Error::ExpectedNumber) 281 | }; 282 | 283 | self.bump(); 284 | Ok(n) 285 | } 286 | 287 | pub fn skip_b(&mut self) { 288 | if self.token == Token::B { 289 | self.bump(); 290 | } 291 | } 292 | 293 | pub fn parse_enum(&mut self) -> Result { 294 | self.expect_keyword(Keyword::Enum)?; 295 | 296 | let ident = self.expect_ident()?; 297 | let mut variants = Vec::new(); 298 | 299 | self.expect(&Token::LCurly)?; 300 | 301 | loop { 302 | if self.eat(&Token::RCurly) { 303 | break; 304 | } 305 | 306 | variants.push(self.parse_ident()?); 307 | 308 | if self.eat(&Token::Comma) { 309 | continue; 310 | } else { 311 | self.eat(&Token::RCurly); 312 | break; 313 | } 314 | } 315 | 316 | Ok(Enum { 317 | ident: ident, 318 | variants: variants 319 | }) 320 | } 321 | 322 | pub fn parse_include(&mut self) -> Result { 323 | self.expect_keyword(Keyword::Include)?; 324 | 325 | Ok(Include { 326 | path: self.expect_string()? 327 | }) 328 | } 329 | 330 | pub fn parse_typedef(&mut self) -> Result { 331 | self.expect_keyword(Keyword::Typedef)?; 332 | 333 | Ok(Typedef(self.parse_ty()?, self.expect_ident()?)) 334 | } 335 | 336 | pub fn parse_namespace(&mut self) -> Result { 337 | self.expect_keyword(Keyword::Namespace)?; 338 | 339 | let lang = self.expect_ident()?; 340 | let module = self.expect_ident()?; 341 | 342 | Ok(Namespace { 343 | lang: lang, 344 | module: module 345 | }) 346 | } 347 | 348 | pub fn parse_service(&mut self) -> Result { 349 | self.expect_keyword(Keyword::Service)?; 350 | 351 | let mut methods = Vec::new(); 352 | let ident = self.expect_ident()?; 353 | self.expect(&Token::LCurly)?; 354 | 355 | loop { 356 | if self.eat(&Token::RCurly) { 357 | break; 358 | } 359 | 360 | // Try and eat a keyword 361 | let method_attr = if self.eat_keyword(Keyword::Oneway) { 362 | FieldAttribute::Oneway 363 | } else { 364 | // This is mostly ignored, we just need some sort of value here. 365 | FieldAttribute::Required 366 | }; 367 | 368 | let method_ty = self.parse_ty()?; 369 | let method_ident = self.parse_ident()?; 370 | let mut method_fields = Vec::new(); 371 | 372 | self.expect(&Token::LParen)?; 373 | 374 | loop { 375 | if self.eat(&Token::RParen) { 376 | break; 377 | } 378 | 379 | let seq = self.parse_number()?; 380 | self.expect(&Token::Colon)?; 381 | let field_ty = self.parse_ty()?; 382 | let field_ident = self.parse_ident()?; 383 | 384 | method_fields.push(StructField { 385 | seq: seq, 386 | attr: FieldAttribute::Required, 387 | ty: field_ty, 388 | ident: field_ident 389 | }); 390 | 391 | if self.eat(&Token::Comma) { 392 | continue; 393 | } else if self.eat(&Token::RParen) { 394 | break; 395 | } else { 396 | panic!("failed to properly parse the service {:?}", ident); 397 | } 398 | } 399 | 400 | methods.push(ServiceMethod { 401 | ident: method_ident, 402 | ty: method_ty, 403 | attr: method_attr, 404 | args: method_fields 405 | }); 406 | 407 | if self.eat(&Token::Comma) || self.eat(&Token::Semi) { 408 | continue; 409 | } else { 410 | self.eat(&Token::RCurly); 411 | break; 412 | } 413 | } 414 | 415 | Ok(Service { 416 | ident: ident, 417 | methods: methods 418 | }) 419 | } 420 | 421 | pub fn expect_string(&mut self) -> Result { 422 | let val = match self.token { 423 | Token::QuotedString(ref s) => s.clone(), 424 | _ => return Err(Error::ExpectedString) 425 | }; 426 | 427 | self.bump(); 428 | Ok(val) 429 | } 430 | 431 | pub fn expect_keyword(&mut self, keyword: Keyword) -> Result<(), Error> { 432 | if !self.eat_keyword(keyword) { 433 | return Err(Error::ExpectedKeyword(keyword)); 434 | } 435 | 436 | Ok(()) 437 | } 438 | 439 | pub fn expect(&mut self, token: &Token) -> Result { 440 | if !self.eat(token) { 441 | return Err(Error::ExpectedToken(token.clone())); 442 | } else { 443 | Ok(self.token.clone()) 444 | } 445 | } 446 | 447 | pub fn parse_ident(&mut self) -> Result { 448 | if self.token == Token::B { 449 | self.bump(); 450 | } 451 | 452 | let i = match self.token { 453 | Token::Ident(ref s) => s.clone(), 454 | _ => return Err(Error::ExpectedIdent) 455 | }; 456 | 457 | self.bump(); 458 | Ok(i) 459 | } 460 | 461 | pub fn parse_ty(&mut self) -> Result { 462 | let ident = self.parse_ident()?; 463 | // map, set, list 464 | if self.eat(&Token::LAngle) { 465 | let ty = match &*ident { 466 | "map" => { 467 | let a = self.parse_ty()?; 468 | self.expect(&Token::Comma)?; 469 | let b = self.parse_ty()?; 470 | 471 | Ty::Map(Box::new(a), Box::new(b)) 472 | }, 473 | "set" => Ty::Set(Box::new(self.parse_ty()?)), 474 | "list" => Ty::List(Box::new(self.parse_ty()?)), 475 | _ => panic!("Error!") 476 | }; 477 | 478 | self.expect(&Token::RAngle)?; 479 | 480 | Ok(ty) 481 | } else { 482 | Ok(Ty::from(ident)) 483 | } 484 | } 485 | 486 | pub fn expect_ident(&mut self) -> Result { 487 | let ident = match self.token { 488 | Token::Ident(ref s) => s.clone(), 489 | _ => return Err(Error::Expected) 490 | }; 491 | 492 | self.bump(); 493 | Ok(ident) 494 | } 495 | 496 | pub fn lookahead_keyword(&mut self, keyword: Keyword) -> bool { 497 | self.lookahead(&Token::Keyword(keyword)) 498 | } 499 | 500 | pub fn lookahead(&mut self, token: &Token) -> bool { 501 | if self.token == Token::B { 502 | self.bump(); 503 | } 504 | 505 | if self.token == *token { 506 | true 507 | } else { 508 | false 509 | } 510 | } 511 | 512 | pub fn eat_keyword(&mut self, keyword: Keyword) -> bool { 513 | self.eat(&Token::Keyword(keyword)) 514 | } 515 | 516 | fn next_char(&self) -> char { 517 | self.buffer[self.pos..].chars().next().unwrap() 518 | } 519 | 520 | fn starts_with(&self, s: &str) -> bool { 521 | self.buffer[self.pos ..].starts_with(s) 522 | } 523 | 524 | fn eof(&self) -> bool { 525 | self.pos >= self.buffer.len() 526 | } 527 | 528 | fn consume_char(&mut self) -> char { 529 | let mut iter = self.buffer[self.pos..].char_indices(); 530 | let (_, cur_char) = iter.next().unwrap(); 531 | let (next_pos, _) = iter.next().unwrap_or((1, ' ')); 532 | self.pos += next_pos; 533 | return cur_char; 534 | } 535 | 536 | fn next_token(&mut self) -> Token { 537 | if self.eof() { 538 | return Token::Eof; 539 | } 540 | 541 | let ch = self.consume_char(); 542 | 543 | match ch { 544 | ':' => Token::Colon, 545 | '.' => Token::Dot, 546 | ';' => Token::Semi, 547 | ',' => Token::Comma, 548 | '"' => { 549 | let val = self.consume_while(|c| c != '"' || c != '\"'); 550 | self.consume_char(); 551 | Token::QuotedString(val) 552 | }, 553 | '=' => Token::Eq, 554 | '(' => Token::LParen, 555 | ')' => Token::RParen, 556 | '{' => Token::LCurly, 557 | '}' => Token::RCurly, 558 | '<' => Token::LAngle, 559 | '>' => Token::RAngle, 560 | '0'...'9' => { 561 | let mut val = self.consume_while(|c| match c { 562 | '0'...'9' => true, 563 | _ => false 564 | }); 565 | 566 | val = format!("{}{}", ch, val); 567 | 568 | Token::Number(val.parse().unwrap()) 569 | }, 570 | '/' | '#' => { 571 | if self.next_char() == '/' || ch == '#' { 572 | self.consume_while(|c| c != '\n' && c != '\r'); 573 | return Token::Comment 574 | } else if self.next_char() == '*' { 575 | self.consume_char(); 576 | loop { 577 | self.consume_while(|c| c != '*'); 578 | self.consume_char(); 579 | 580 | if self.next_char() == '/' { 581 | break; 582 | } 583 | } 584 | 585 | // Consume the following '/' because we just did a lookahead previously. 586 | self.consume_char(); 587 | return Token::Comment 588 | } 589 | 590 | Token::Eof 591 | }, 592 | c if c.is_whitespace() => { 593 | self.consume_whitespace(); 594 | self.next_token() 595 | }, 596 | // identifier 597 | 'a'...'z' | 'A'...'Z' | '_' => { 598 | let mut ident = self.consume_while(|c| match c { 599 | 'a'...'z' => true, 600 | 'A'...'Z' => true, 601 | '_' => true, 602 | '0'...'9' => true, 603 | _ => false 604 | }); 605 | 606 | ident = format!("{}{}", ch, ident); 607 | 608 | match &*ident { 609 | "namespace" => return Token::Keyword(Keyword::Namespace), 610 | "struct" => return Token::Keyword(Keyword::Struct), 611 | "enum" => return Token::Keyword(Keyword::Enum), 612 | "service" => return Token::Keyword(Keyword::Service), 613 | "optional" => return Token::Keyword(Keyword::Optional), 614 | "required" => return Token::Keyword(Keyword::Required), 615 | "throws" => return Token::Keyword(Keyword::Throws), 616 | "oneway" => return Token::Keyword(Keyword::Oneway), 617 | "typedef" => return Token::Keyword(Keyword::Typedef), 618 | "exception" => return Token::Keyword(Keyword::Exception), 619 | "include" => return Token::Keyword(Keyword::Include), 620 | "const" => return Token::Keyword(Keyword::Const), 621 | _ => Token::Ident(ident) 622 | } 623 | }, 624 | _ => Token::Eof 625 | } 626 | } 627 | 628 | pub fn eat(&mut self, token: &Token) -> bool { 629 | if self.token == Token::B { 630 | self.bump(); 631 | } 632 | 633 | if self.token == *token { 634 | self.bump(); 635 | true 636 | } else { 637 | false 638 | } 639 | } 640 | 641 | fn consume_while(&mut self, test: F) -> String 642 | where F: Fn(char) -> bool { 643 | let mut result = String::new(); 644 | while !self.eof() && test(self.next_char()) { 645 | result.push(self.consume_char()); 646 | } 647 | return result; 648 | } 649 | 650 | fn consume_whitespace(&mut self) { 651 | self.consume_while(char::is_whitespace); 652 | } 653 | 654 | pub fn bump(&mut self) { 655 | if self.last_token_eof { 656 | panic!("attempted to bump past eof."); 657 | } 658 | 659 | if self.token == Token::Eof { 660 | self.last_token_eof = true; 661 | } 662 | 663 | self.token = self.next_token(); 664 | } 665 | } 666 | 667 | #[cfg(test)] 668 | mod tests { 669 | use super::*; 670 | 671 | #[test] 672 | fn eof_token() { 673 | let mut parser = Parser::new(""); 674 | assert_eq!(parser.eof(), true); 675 | assert_eq!(parser.next_token(), Token::Eof); 676 | } 677 | 678 | #[test] 679 | fn colon_token() { 680 | let mut parser = Parser::new(":"); 681 | assert_eq!(parser.next_token(), Token::Colon); 682 | } 683 | 684 | #[test] 685 | fn dot_token() { 686 | let mut parser = Parser::new("."); 687 | assert_eq!(parser.next_token(), Token::Dot); 688 | } 689 | 690 | #[test] 691 | fn equal_token() { 692 | let mut parser = Parser::new("="); 693 | assert_eq!(parser.next_token(), Token::Eq); 694 | } 695 | 696 | #[test] 697 | fn comma_token() { 698 | let mut parser = Parser::new(","); 699 | assert_eq!(parser.next_token(), Token::Comma); 700 | } 701 | 702 | #[test] 703 | fn curly_token() { 704 | let mut parser = Parser::new("{}"); 705 | assert_eq!(parser.next_token(), Token::LCurly); 706 | assert_eq!(parser.next_token(), Token::RCurly); 707 | } 708 | 709 | #[test] 710 | fn angle_token() { 711 | let mut parser = Parser::new("<>"); 712 | assert_eq!(parser.next_token(), Token::LAngle); 713 | assert_eq!(parser.next_token(), Token::RAngle); 714 | } 715 | 716 | #[test] 717 | fn semi_token() { 718 | let mut parser = Parser::new(";"); 719 | assert_eq!(parser.next_token(), Token::Semi); 720 | } 721 | 722 | #[test] 723 | #[should_panic] 724 | fn whitespace_token() { 725 | let mut parser = Parser::new(" "); 726 | assert_eq!(parser.next_token(), Token::Whitespace); 727 | } 728 | 729 | #[test] 730 | fn whitespace_grab_token() { 731 | let mut parser = Parser::new(" >"); 732 | assert_eq!(parser.next_token(), Token::RAngle); 733 | } 734 | 735 | #[test] 736 | fn comment_token() { 737 | let mut parser = Parser::new(""); 747 | assert_eq!(parser.next_token(), Token::LAngle); 748 | assert_eq!(parser.next_token(), Token::Comment); 749 | assert_eq!(parser.next_token(), Token::RAngle); 750 | } 751 | 752 | #[test] 753 | fn parens_token() { 754 | let mut parser = Parser::new("()"); 755 | assert_eq!(parser.next_token(), Token::LParen); 756 | assert_eq!(parser.next_token(), Token::RParen); 757 | } 758 | 759 | #[test] 760 | fn hash_comment_token() { 761 | let mut parser = Parser::new("<#foobar\n:"); 762 | assert_eq!(parser.next_token(), Token::LAngle); 763 | assert_eq!(parser.next_token(), Token::Comment); 764 | assert_eq!(parser.next_token(), Token::Colon); 765 | } 766 | 767 | #[test] 768 | fn ident_token() { 769 | assert_eq!(Parser::new("foobar").next_token(), Token::Ident("foobar".to_string())); 770 | assert_eq!(Parser::new("foobar123").next_token(), Token::Ident("foobar123".to_string())); 771 | assert_eq!(Parser::new("foobar_123").next_token(), Token::Ident("foobar_123".to_string())); 772 | assert_eq!(Parser::new("_FFF").next_token(), Token::Ident("_FFF".to_string())); 773 | } 774 | 775 | #[test] 776 | fn quoted_string_token() { 777 | assert_eq!(Parser::new("\"hello world 12338383\"").next_token(), Token::QuotedString("hello world 12338383".to_string())); 778 | } 779 | 780 | #[test] 781 | #[should_panic] 782 | fn fail_ident_token() { 783 | assert_eq!(Parser::new("1foobar").next_token(), Token::Ident("1foobar".to_string())); 784 | } 785 | 786 | #[test] 787 | fn keywords_token() { 788 | assert_eq!(Parser::new("oneway").next_token(), Token::Keyword(Keyword::Oneway)); 789 | assert_eq!(Parser::new("exception").next_token(), Token::Keyword(Keyword::Exception)); 790 | assert_eq!(Parser::new("struct").next_token(), Token::Keyword(Keyword::Struct)); 791 | assert_eq!(Parser::new("enum").next_token(), Token::Keyword(Keyword::Enum)); 792 | assert_eq!(Parser::new("namespace").next_token(), Token::Keyword(Keyword::Namespace)); 793 | assert_eq!(Parser::new("service").next_token(), Token::Keyword(Keyword::Service)); 794 | assert_eq!(Parser::new("throws").next_token(), Token::Keyword(Keyword::Throws)); 795 | assert_eq!(Parser::new("typedef").next_token(), Token::Keyword(Keyword::Typedef)); 796 | assert_eq!(Parser::new("optional").next_token(), Token::Keyword(Keyword::Optional)); 797 | assert_eq!(Parser::new("required").next_token(), Token::Keyword(Keyword::Required)); 798 | assert_eq!(Parser::new("const").next_token(), Token::Keyword(Keyword::Const)); 799 | } 800 | 801 | #[test] 802 | fn eat_token() { 803 | let mut p = Parser::new(":"); 804 | assert_eq!(p.eat(&Token::Colon), true); 805 | } 806 | 807 | #[test] 808 | fn eat_keywords() { 809 | let mut p = Parser::new("oneway"); 810 | assert_eq!(p.eat_keyword(Keyword::Oneway), true); 811 | } 812 | 813 | #[test] 814 | fn parse_namespace() { 815 | let mut p = Parser::new("namespace rust foobar"); 816 | let ns = p.parse_namespace().unwrap(); 817 | assert_eq!(&*ns.lang, "rust"); 818 | assert_eq!(&*ns.module, "foobar"); 819 | } 820 | 821 | #[test] 822 | fn parse_namesp_ace() { 823 | let mut p = Parser::new("namespace rust foobar"); 824 | let ns = p.parse_namespace().unwrap(); 825 | assert_eq!(&*ns.lang, "rust"); 826 | assert_eq!(&*ns.module, "foobar"); 827 | } 828 | 829 | #[test] 830 | fn parse_include() { 831 | let mut p = Parser::new("include \"./../include.thrift\""); 832 | let ns = p.parse_include().unwrap(); 833 | assert_eq!(&*ns.path, "./../include.thrift"); 834 | } 835 | 836 | #[test] 837 | fn parse_bool_ty() { 838 | let mut p = Parser::new("bool"); 839 | assert_eq!(p.parse_ty().unwrap(), Ty::Bool); 840 | } 841 | 842 | #[test] 843 | fn parse_binary_ty() { 844 | let mut p = Parser::new("binary"); 845 | assert_eq!(p.parse_ty().unwrap(), Ty::Binary); 846 | } 847 | 848 | #[test] 849 | fn parse_byte_ty() { 850 | let mut p = Parser::new("byte"); 851 | assert_eq!(p.parse_ty().unwrap(), Ty::Byte); 852 | } 853 | 854 | #[test] 855 | fn parse_i16_ty() { 856 | let mut p = Parser::new("i16"); 857 | assert_eq!(p.parse_ty().unwrap(), Ty::I16); 858 | } 859 | 860 | #[test] 861 | fn parse_i32_ty() { 862 | let mut p = Parser::new("i32"); 863 | assert_eq!(p.parse_ty().unwrap(), Ty::I32); 864 | } 865 | 866 | #[test] 867 | fn parse_i64_ty() { 868 | let mut p = Parser::new("i64"); 869 | assert_eq!(p.parse_ty().unwrap(), Ty::I64); 870 | } 871 | 872 | #[test] 873 | fn parse_double_ty() { 874 | let mut p = Parser::new("double"); 875 | assert_eq!(p.parse_ty().unwrap(), Ty::Double); 876 | } 877 | 878 | #[test] 879 | fn parse_string_ty() { 880 | let mut p = Parser::new("string"); 881 | assert_eq!(p.parse_ty().unwrap(), Ty::String); 882 | } 883 | 884 | #[test] 885 | fn parse_list_string_ty() { 886 | let mut p = Parser::new("list"); 887 | assert_eq!(p.parse_ty().unwrap(), Ty::List(Box::new(Ty::String))); 888 | } 889 | 890 | #[test] 891 | fn parse_list_double_ty() { 892 | let mut p = Parser::new("list"); 893 | assert_eq!(p.parse_ty().unwrap(), Ty::List(Box::new(Ty::Double))); 894 | } 895 | 896 | #[test] 897 | fn parse_list_list_byte_ty() { 898 | let mut p = Parser::new("list>"); 899 | assert_eq!(p.parse_ty().unwrap(), Ty::List(Box::new(Ty::List(Box::new(Ty::Byte))))); 900 | } 901 | 902 | #[test] 903 | fn parse_set_byte_ty() { 904 | let mut p = Parser::new("set"); 905 | assert_eq!(p.parse_ty().unwrap(), Ty::Set(Box::new(Ty::Byte))); 906 | } 907 | 908 | #[test] 909 | fn parse_set_string_ty() { 910 | let mut p = Parser::new("set"); 911 | assert_eq!(p.parse_ty().unwrap(), Ty::Set(Box::new(Ty::String))); 912 | } 913 | 914 | #[test] 915 | fn parse_map_i32_string_ty() { 916 | let mut p = Parser::new("map"); 917 | assert_eq!(p.parse_ty().unwrap(), Ty::Map(Box::new(Ty::I32), Box::new(Ty::String))); 918 | } 919 | 920 | #[test] 921 | fn parse_map_i32_list_string_ty() { 922 | let mut p = Parser::new("map>"); 923 | assert_eq!(p.parse_ty().unwrap(), Ty::Map(Box::new(Ty::I32), Box::new(Ty::List(Box::new(Ty::String))))); 924 | } 925 | 926 | #[test] 927 | fn parse_typedef() { 928 | let mut p = Parser::new("typedef i32 MyInteger"); 929 | let def = p.parse_typedef().unwrap(); 930 | assert_eq!(def.0, Ty::I32); 931 | assert_eq!(&*def.1, "MyInteger"); 932 | } 933 | 934 | #[test] 935 | fn parse_empty_enum() { 936 | let mut p = Parser::new("enum FooBar {}"); 937 | let def = p.parse_enum().unwrap(); 938 | assert_eq!(&*def.ident, "FooBar"); 939 | assert_eq!(def.variants.len(), 0); 940 | } 941 | 942 | #[test] 943 | fn parse_one_variant_enum() { 944 | let mut p = Parser::new("enum Hello { ONE }"); 945 | let def = p.parse_enum().unwrap(); 946 | assert_eq!(&*def.ident, "Hello"); 947 | assert_eq!(def.variants.len(), 1); 948 | assert_eq!(&*def.variants[0], "ONE"); 949 | } 950 | 951 | #[test] 952 | fn parse_empty_service() { 953 | let mut p = Parser::new("service Flock {}"); 954 | let def = p.parse_service().unwrap(); 955 | assert_eq!(&*def.ident, "Flock"); 956 | assert_eq!(def.methods.len(), 0); 957 | } 958 | 959 | #[test] 960 | fn parse_method_service() { 961 | let mut p = Parser::new("service Flock { 962 | void ping(); 963 | }"); 964 | let def = p.parse_service().unwrap(); 965 | assert_eq!(&*def.ident, "Flock"); 966 | assert_eq!(def.methods.len(), 1); 967 | assert_eq!(&*def.methods[0].ident, "ping"); 968 | assert_eq!(def.methods[0].ty, Ty::Void); 969 | assert_eq!(def.methods[0].attr, FieldAttribute::Required); 970 | assert_eq!(def.methods[0].args.len(), 0); 971 | } 972 | 973 | #[test] 974 | fn parse_method_with_one_args_service() { 975 | let mut p = Parser::new("service Beans { 976 | void poutine(1: string firstName); 977 | }"); 978 | let def = p.parse_service().unwrap(); 979 | assert_eq!(&*def.ident, "Beans"); 980 | assert_eq!(def.methods.len(), 1); 981 | assert_eq!(&*def.methods[0].ident, "poutine"); 982 | assert_eq!(def.methods[0].ty, Ty::Void); 983 | assert_eq!(def.methods[0].attr, FieldAttribute::Required); 984 | assert_eq!(def.methods[0].args.len(), 1); 985 | assert_eq!(def.methods[0].args[0], StructField { 986 | seq: 1, 987 | attr: FieldAttribute::Required, 988 | ty: Ty::String, 989 | ident: "firstName".to_string() 990 | }); 991 | } 992 | 993 | #[test] 994 | fn parse_oneway_method_service() { 995 | let mut p = Parser::new("service Flock { 996 | oneway void ping(); 997 | }"); 998 | let def = p.parse_service().unwrap(); 999 | assert_eq!(&*def.ident, "Flock"); 1000 | assert_eq!(def.methods.len(), 1); 1001 | assert_eq!(&*def.methods[0].ident, "ping"); 1002 | assert!(def.methods[0].ty == Ty::Void); 1003 | assert_eq!(def.methods[0].attr, FieldAttribute::Oneway); 1004 | assert_eq!(def.methods[0].args.len(), 0); 1005 | } 1006 | 1007 | #[test] 1008 | fn parse_multi_variant_enum() { 1009 | let mut p = Parser::new("enum Hello { ONE, TWO }"); 1010 | let def = p.parse_enum().unwrap(); 1011 | assert_eq!(&*def.ident, "Hello"); 1012 | assert_eq!(def.variants.len(), 2); 1013 | assert_eq!(&*def.variants[0], "ONE"); 1014 | assert_eq!(&*def.variants[1], "TWO"); 1015 | } 1016 | 1017 | #[test] 1018 | fn parse_empty_struct() { 1019 | let mut p = Parser::new("struct FooBar {}"); 1020 | let def = p.parse_struct().unwrap(); 1021 | assert_eq!(&*def.ident, "FooBar"); 1022 | assert_eq!(def.fields.len(), 0); 1023 | } 1024 | 1025 | #[test] 1026 | fn parse_struct_w_field() { 1027 | let mut p = Parser::new("struct FooBar { 1: required i32 mycat }"); 1028 | let def = p.parse_struct().unwrap(); 1029 | assert_eq!(&*def.ident, "FooBar"); 1030 | assert_eq!(def.fields.len(), 1); 1031 | } 1032 | 1033 | #[test] 1034 | fn parse_struct_w_multi_field() { 1035 | let mut p = Parser::new("struct FooBar { 1: required i32 mycat; 2: required i32 two }"); 1036 | let def = p.parse_struct().unwrap(); 1037 | assert_eq!(&*def.ident, "FooBar"); 1038 | assert_eq!(def.fields.len(), 2); 1039 | } 1040 | 1041 | #[test] 1042 | fn parse_struct_field_optional() { 1043 | let mut p = Parser::new("1: optional i32 foobar"); 1044 | let def = p.parse_struct_field().unwrap(); 1045 | assert_eq!(&*def.ident, "foobar"); 1046 | assert_eq!(def.ty, Ty::I32); 1047 | assert_eq!(def.seq, 1); 1048 | assert_eq!(def.attr, FieldAttribute::Optional); 1049 | } 1050 | 1051 | #[test] 1052 | fn parse_struct_field_required() { 1053 | let mut p = Parser::new("1: required i32 foobar"); 1054 | let def = p.parse_struct_field().unwrap(); 1055 | assert_eq!(&*def.ident, "foobar"); 1056 | assert_eq!(def.ty, Ty::I32); 1057 | assert_eq!(def.seq, 1); 1058 | assert_eq!(def.attr, FieldAttribute::Required); 1059 | } 1060 | } 1061 | --------------------------------------------------------------------------------