<commit_before>#[macro_use]
extern crate clap;
extern crate osciemu;
extern crate byteorder;

use std::vec::Vec;
use std::fs::File;
use std::io;
use osciemu::memory::SliceMemory;
use osciemu::emulator::Emulator;

use byteorder::{NetworkEndian, ReadBytesExt};

fn read_file_into_slice(filename: &str) -> Result<Box<[i32]>, io::Error> {
    let mut file = File::open(filename)?;
    let file_meta = file.metadata()?;
    let size = file_meta.len() as usize;
    let mut vec = Vec::<i32>::with_capacity(size);
    vec.resize(size / 4, 0);
    let mut slice: Box<[i32]> = vec.into_boxed_slice();
    file.read_i32_into::<NetworkEndian>(slice.as_mut())?;
    Ok(slice)
}

fn main() {
    let matches = clap_app!(myapp =>
            (version: "0.1.0")
            (author: "Surma <surma@surma.link>")
            (about: "Emulates an osci CPU")
            (@arg IMAGE: -i --image +required +takes_value "Image to load into memory")
            (@arg BIOS: -b --bios +required +takes_value "BIOS to load")
            (@arg STEP: --step "Walk through in stepping mode")
            (@arg MAX_STEP: --maxstep +takes_value "Maximum number of CPU cycles (0 means infinite)")
        )
        .get_matches();

    let max_steps = matches.value_of("MAX_STEP")
                        .map(|s| {
                            s.parse::<usize>()
                                .expect("--max-step needs to be a number")
                        })
                        .unwrap_or(0);

    let image_buf = read_file_into_slice(matches.value_of("IMAGE").unwrap())
                            .expect("Could not load image");
    let bios_buf = read_file_into_slice(matches.value_of("BIOS").unwrap())
                            .expect("Could not load bios");

    let step_mode = matches.is_present("STEP");

    let img_mem = Box::new(SliceMemory(image_buf));
    let bios_mem = Box::new(SliceMemory(bios_buf));
    let mut emulator = Emulator::new(img_mem, bios_mem);

    println!("FLAGS_START_ADDRESS = 0x{:08X}", osciemu::memory::address::FLAGS_START_ADDRESS);
    println!("IVT_START_ADDRESS = 0x{:08X}", osciemu::memory::address::IVT_START_ADDRESS);
    println!("REGISTERS_START_ADDRESS = 0x{:08X}", osciemu::memory::address::REGISTERS_START_ADDRESS);
    println!("STACK_POINTER_ADDRESS = 0x{:08X}", osciemu::memory::address::STACK_POINTER_ADDRESS);

    for count in RangeIterator::new(0, max_steps) {
        if emulator.is_halted() {
            break;
        }
        println!("count: {:4}, ip: 0x{:08X}, r0: 0x{:08X}, r1: 0x{:08X}, r2: 0x{:08X}, r3: \
                  0x{:08X}",
                 count,
                 emulator.ip,
                 emulator.get_register(0),
                 emulator.get_register(1),
                 emulator.get_register(2),
                 emulator.get_register(3));
        emulator.step();
        if step_mode {
            let mut buffer = String::new();
            let _ = io::stdin().read_line(&mut buffer);
        }
    }
    if !emulator.is_halted() {
        std::process::exit(1);
    }
}

struct RangeIterator {
    count: usize,
    max: usize
}

impl RangeIterator {
    fn new(start: usize, max: usize) -> RangeIterator {
        RangeIterator {
            count: start,
            max,
        }
    }
}

impl Iterator for RangeIterator {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        if self.count == self.max && self.max != 0 {
            return None;
        }
        let result = Some(self.count);
        if self.count != std::usize::MAX {
            self.count = self.count + 1;
        }
        result
    }
}
<commit_msg>feat(osci-cli): Don’t show instruction counter<commit_after>#[macro_use]
extern crate clap;
extern crate osciemu;
extern crate byteorder;

use std::vec::Vec;
use std::fs::File;
use std::io;
use osciemu::memory::SliceMemory;
use osciemu::emulator::Emulator;

use byteorder::{NetworkEndian, ReadBytesExt};

fn read_file_into_slice(filename: &str) -> Result<Box<[i32]>, io::Error> {
    let mut file = File::open(filename)?;
    let file_meta = file.metadata()?;
    let size = file_meta.len() as usize;
    let mut vec = Vec::<i32>::with_capacity(size);
    vec.resize(size / 4, 0);
    let mut slice: Box<[i32]> = vec.into_boxed_slice();
    file.read_i32_into::<NetworkEndian>(slice.as_mut())?;
    Ok(slice)
}

fn main() {
    let matches = clap_app!(myapp =>
            (version: "0.1.0")
            (author: "Surma <surma@surma.link>")
            (about: "Emulates an osci CPU")
            (@arg IMAGE: -i --image +required +takes_value "Image to load into memory")
            (@arg BIOS: -b --bios +required +takes_value "BIOS to load")
            (@arg STEP: --step "Walk through in stepping mode")
            (@arg MAX_STEP: --maxstep +takes_value "Maximum number of CPU cycles (0 means infinite)")
        )
        .get_matches();

    let max_steps = matches.value_of("MAX_STEP")
                        .map(|s| {
                            s.parse::<usize>()
                                .expect("--max-step needs to be a number")
                        })
                        .unwrap_or(0);

    let image_buf = read_file_into_slice(matches.value_of("IMAGE").unwrap())
                            .expect("Could not load image");
    let bios_buf = read_file_into_slice(matches.value_of("BIOS").unwrap())
                            .expect("Could not load bios");

    let step_mode = matches.is_present("STEP");

    let img_mem = Box::new(SliceMemory(image_buf));
    let bios_mem = Box::new(SliceMemory(bios_buf));
    let mut emulator = Emulator::new(img_mem, bios_mem);

    println!("FLAGS_START_ADDRESS = 0x{:08X}", osciemu::memory::address::FLAGS_START_ADDRESS);
    println!("IVT_START_ADDRESS = 0x{:08X}", osciemu::memory::address::IVT_START_ADDRESS);
    println!("REGISTERS_START_ADDRESS = 0x{:08X}", osciemu::memory::address::REGISTERS_START_ADDRESS);
    println!("STACK_POINTER_ADDRESS = 0x{:08X}", osciemu::memory::address::STACK_POINTER_ADDRESS);

    for _count in RangeIterator::new(0, max_steps) {
        if emulator.is_halted() {
            break;
        }
        println!("ip: 0x{:08X}, r0: 0x{:08X}, r1: 0x{:08X}, r2: 0x{:08X}, r3: \
                  0x{:08X}",
                 emulator.ip,
                 emulator.get_register(0),
                 emulator.get_register(1),
                 emulator.get_register(2),
                 emulator.get_register(3));
        emulator.step();
        if step_mode {
            let mut buffer = String::new();
            let _ = io::stdin().read_line(&mut buffer);
        }
    }
    if !emulator.is_halted() {
        std::process::exit(1);
    }
}

struct RangeIterator {
    count: usize,
    max: usize
}

impl RangeIterator {
    fn new(start: usize, max: usize) -> RangeIterator {
        RangeIterator {
            count: start,
            max,
        }
    }
}

impl Iterator for RangeIterator {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        if self.count == self.max && self.max != 0 {
            return None;
        }
        let result = Some(self.count);
        if self.count != std::usize::MAX {
            self.count = self.count + 1;
        }
        result
    }
}
<|endoftext|>


<commit_before>use crate::{analysis, chunk::Chunk};

#[derive(Default)]
pub struct Builder {
    name: String,
    in_trait: bool,
    var_name: String,
    is_get: bool,
    is_child_property: bool,
    type_: String,
    is_ref: bool,
    is_nullable: bool,
}

#[allow(clippy::wrong_self_convention)]
impl Builder {
    pub fn new() -> Builder {
        Default::default()
    }

    pub fn new_for_child_property() -> Builder {
        Builder {
            is_child_property: true,
            ..Default::default()
        }
    }

    pub fn name(&mut self, name: &str) -> &mut Builder {
        self.name = name.into();
        self
    }

    pub fn in_trait(&mut self, value: bool) -> &mut Builder {
        self.in_trait = value;
        self
    }

    pub fn var_name(&mut self, name: &str) -> &mut Builder {
        self.var_name = name.into();
        self
    }

    pub fn is_get(&mut self, value: bool) -> &mut Builder {
        self.is_get = value;
        self
    }

    pub fn type_(&mut self, type_: &str) -> &mut Builder {
        self.type_ = type_.into();
        self
    }

    pub fn is_ref(&mut self, value: bool) -> &mut Builder {
        self.is_ref = value;
        self
    }

    pub fn is_nullable(&mut self, value: bool) -> &mut Builder {
        self.is_nullable = value;
        self
    }

    pub fn generate(&self) -> Chunk {
        let chunks = if self.is_get {
            self.chunks_for_get()
        } else {
            self.chunks_for_set()
        };
        Chunk::BlockHalf(chunks)
    }

    fn chunks_for_get(&self) -> Vec<Chunk> {
        let mut params = Vec::new();

        let cast_target = if self.is_child_property {
            "gtk_sys::GtkContainer"
        } else {
            "gobject_sys::GObject"
        };
        if self.in_trait {
            params.push(Chunk::Custom(format!(
                "self.to_glib_none().0 as *mut {}",
                cast_target
            )));
        } else {
            params.push(Chunk::Custom(format!(
                "self.as_ptr() as *mut {}",
                cast_target
            )));
        }

        if self.is_child_property {
            params.push(Chunk::Custom("item.to_glib_none().0 as *mut _".into()));
        }
        params.push(Chunk::Custom(format!(
            "b\"{}\\0\".as_ptr() as *const _",
            self.name
        )));
        params.push(Chunk::Custom("value.to_glib_none_mut().0".into()));

        let mut body = Vec::new();

        let return_info = analysis::return_value::Info {
            parameter: None,
            base_tid: None,
            commented: false,
            bool_return_is_error: None,
        };
        let ffi_call = Chunk::FfiCall {
            name: self.get_ffi_func(),
            params,
        };

        body.push(Chunk::Let {
            name: "value".into(),
            is_mut: true,
            value: Box::new(Chunk::Custom(format!(
                "Value::from_type(<{} as StaticType>::static_type())",
                self.type_
            ))),
            type_: None,
        });

        body.push(Chunk::FfiCallConversion {
            ret: return_info,
            array_length_name: None,
            call: Box::new(ffi_call),
        });

        let unwrap = if self.is_nullable {
            // This one is strictly speaking nullable, but
            // we represent that with an empty Vec instead
            if self.type_ == "Vec<GString>" {
                ".unwrap()"
            } else {
                ""
            }
        } else {
            ".unwrap()"
        };
        body.push(Chunk::Custom(format!("value.get(){}", unwrap)));

        let unsafe_ = Chunk::Unsafe(body);

        let mut chunks = Vec::new();
        chunks.push(unsafe_);

        chunks
    }

    fn chunks_for_set(&self) -> Vec<Chunk> {
        let mut params = Vec::new();

        let cast_target = if self.is_child_property {
            "gtk_sys::GtkContainer"
        } else {
            "gobject_sys::GObject"
        };
        if self.in_trait {
            params.push(Chunk::Custom(format!(
                "self.to_glib_none().0 as *mut {}",
                cast_target
            )));
        } else {
            params.push(Chunk::Custom(format!(
                "self.as_ptr() as *mut {}",
                cast_target
            )));
        }

        if self.is_child_property {
            params.push(Chunk::Custom("item.to_glib_none().0 as *mut _".into()));
        }
        params.push(Chunk::Custom(format!(
            "b\"{}\\0\".as_ptr() as *const _",
            self.name
        )));
        let ref_str = if self.is_ref { "" } else { "&" };
        params.push(Chunk::Custom(format!(
            "Value::from({}{}).to_glib_none().0",
            ref_str, self.var_name
        )));

        let mut body = Vec::new();

        let ffi_call = Chunk::FfiCall {
            name: self.set_ffi_func(),
            params,
        };
        let return_info = analysis::return_value::Info {
            parameter: None,
            base_tid: None,
            commented: false,
            bool_return_is_error: None,
        };
        body.push(Chunk::FfiCallConversion {
            ret: return_info,
            array_length_name: None,
            call: Box::new(ffi_call),
        });

        vec![Chunk::Unsafe(body)]
    }

    fn get_ffi_func(&self) -> String {
        if self.is_child_property {
            "gtk_sys::gtk_container_child_get_property".to_owned()
        } else {
            "gobject_sys::g_object_get_property".to_owned()
        }
    }

    fn set_ffi_func(&self) -> String {
        if self.is_child_property {
            "gtk_sys::gtk_container_child_set_property".to_owned()
        } else {
            "gobject_sys::g_object_set_property".to_owned()
        }
    }
}
<commit_msg>Migrate property getters to new signature for `Value::get`<commit_after>use crate::{analysis, chunk::Chunk};

#[derive(Default)]
pub struct Builder {
    name: String,
    in_trait: bool,
    var_name: String,
    is_get: bool,
    is_child_property: bool,
    type_: String,
    is_ref: bool,
    is_nullable: bool,
}

#[allow(clippy::wrong_self_convention)]
impl Builder {
    pub fn new() -> Builder {
        Default::default()
    }

    pub fn new_for_child_property() -> Builder {
        Builder {
            is_child_property: true,
            ..Default::default()
        }
    }

    pub fn name(&mut self, name: &str) -> &mut Builder {
        self.name = name.into();
        self
    }

    pub fn in_trait(&mut self, value: bool) -> &mut Builder {
        self.in_trait = value;
        self
    }

    pub fn var_name(&mut self, name: &str) -> &mut Builder {
        self.var_name = name.into();
        self
    }

    pub fn is_get(&mut self, value: bool) -> &mut Builder {
        self.is_get = value;
        self
    }

    pub fn type_(&mut self, type_: &str) -> &mut Builder {
        self.type_ = type_.into();
        self
    }

    pub fn is_ref(&mut self, value: bool) -> &mut Builder {
        self.is_ref = value;
        self
    }

    pub fn is_nullable(&mut self, value: bool) -> &mut Builder {
        self.is_nullable = value;
        self
    }

    pub fn generate(&self) -> Chunk {
        let chunks = if self.is_get {
            self.chunks_for_get()
        } else {
            self.chunks_for_set()
        };
        Chunk::BlockHalf(chunks)
    }

    fn chunks_for_get(&self) -> Vec<Chunk> {
        let mut params = Vec::new();

        let cast_target = if self.is_child_property {
            "gtk_sys::GtkContainer"
        } else {
            "gobject_sys::GObject"
        };
        if self.in_trait {
            params.push(Chunk::Custom(format!(
                "self.to_glib_none().0 as *mut {}",
                cast_target
            )));
        } else {
            params.push(Chunk::Custom(format!(
                "self.as_ptr() as *mut {}",
                cast_target
            )));
        }

        if self.is_child_property {
            params.push(Chunk::Custom("item.to_glib_none().0 as *mut _".into()));
        }
        params.push(Chunk::Custom(format!(
            "b\"{}\\0\".as_ptr() as *const _",
            self.name
        )));
        params.push(Chunk::Custom("value.to_glib_none_mut().0".into()));

        let mut body = Vec::new();

        let return_info = analysis::return_value::Info {
            parameter: None,
            base_tid: None,
            commented: false,
            bool_return_is_error: None,
        };
        let ffi_call = Chunk::FfiCall {
            name: self.get_ffi_func(),
            params,
        };

        body.push(Chunk::Let {
            name: "value".into(),
            is_mut: true,
            value: Box::new(Chunk::Custom(format!(
                "Value::from_type(<{} as StaticType>::static_type())",
                self.type_
            ))),
            type_: None,
        });

        body.push(Chunk::FfiCallConversion {
            ret: return_info,
            array_length_name: None,
            call: Box::new(ffi_call),
        });

        let unwrap = if self.is_nullable {
            // This one is strictly speaking nullable, but
            // we represent that with an empty Vec instead
            if self.type_ == "Vec<GString>" {
                ".unwrap()"
            } else {
                ""
            }
        } else {
            ".unwrap()"
        };
        body.push(Chunk::Custom(format!(
            "value.get().expect(\"Return Value for property `{}` getter\"){}",
            self.name, unwrap,
        )));

        let unsafe_ = Chunk::Unsafe(body);

        let mut chunks = Vec::new();
        chunks.push(unsafe_);

        chunks
    }

    fn chunks_for_set(&self) -> Vec<Chunk> {
        let mut params = Vec::new();

        let cast_target = if self.is_child_property {
            "gtk_sys::GtkContainer"
        } else {
            "gobject_sys::GObject"
        };
        if self.in_trait {
            params.push(Chunk::Custom(format!(
                "self.to_glib_none().0 as *mut {}",
                cast_target
            )));
        } else {
            params.push(Chunk::Custom(format!(
                "self.as_ptr() as *mut {}",
                cast_target
            )));
        }

        if self.is_child_property {
            params.push(Chunk::Custom("item.to_glib_none().0 as *mut _".into()));
        }
        params.push(Chunk::Custom(format!(
            "b\"{}\\0\".as_ptr() as *const _",
            self.name
        )));
        let ref_str = if self.is_ref { "" } else { "&" };
        params.push(Chunk::Custom(format!(
            "Value::from({}{}).to_glib_none().0",
            ref_str, self.var_name
        )));

        let mut body = Vec::new();

        let ffi_call = Chunk::FfiCall {
            name: self.set_ffi_func(),
            params,
        };
        let return_info = analysis::return_value::Info {
            parameter: None,
            base_tid: None,
            commented: false,
            bool_return_is_error: None,
        };
        body.push(Chunk::FfiCallConversion {
            ret: return_info,
            array_length_name: None,
            call: Box::new(ffi_call),
        });

        vec![Chunk::Unsafe(body)]
    }

    fn get_ffi_func(&self) -> String {
        if self.is_child_property {
            "gtk_sys::gtk_container_child_get_property".to_owned()
        } else {
            "gobject_sys::g_object_get_property".to_owned()
        }
    }

    fn set_ffi_func(&self) -> String {
        if self.is_child_property {
            "gtk_sys::gtk_container_child_set_property".to_owned()
        } else {
            "gobject_sys::g_object_set_property".to_owned()
        }
    }
}
<|endoftext|>


<commit_before>#![feature(slice_patterns)]
#![feature(path_ext)]
extern crate eve;
extern crate hyper;
extern crate cookie;
extern crate mime;
extern crate url;
extern crate websocket;
extern crate rustc_serialize;
extern crate conduit_mime_types;

use std::io::Read;
use std::io::Write;
use std::fs::File;
use std::error::Error;
use hyper::net::Fresh;
use hyper::server::{Server, Request, Response};
use hyper::uri::RequestUri;
use hyper::Url;
use hyper::header::{Headers,ContentType,Location,SetCookie};
use cookie::Cookie;
use mime::Mime;
use url::SchemeData::Relative;
use rustc_serialize::json;
use websocket::{Message, Sender};
use std::path::Path;
use std::fs::PathExt;
use conduit_mime_types::Types;
use std::str::FromStr;

use eve::client::*;
use eve::server;
use eve::value::Value;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Session {
	client: String,
	id: String,
	user_id: String,
	object: String,
	created_at: f64,
	expires_at: f64,
	ip: String,
	user: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct User {
	custom: Custom,
	id: String,
	realm_id: String,
	username: String,
	state: String,
	user_type: String,
	reference: Option<String>,
	name: String,
	email: String,
	object: String,
	last_login_at: f64,
	last_login_on: f64,
	created_at: f64,
	first_name: Option<String>,
	last_name: Option<String>,
	credentials: Vec<Credential>,
	membership_count: f64,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Custom;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Credential {
	id: String,
	credential_type: String,
	object: String,
}

fn main() {
	Server::http("0.0.0.0:8080").unwrap().handle(login).unwrap();
}

fn read_file_bytes(filename: &str) -> Vec<u8> {
    let mut file = File::open(&filename).unwrap();
    let mut contents: Vec<u8> = Vec::new();
	file.read_to_end(&mut contents).unwrap();
	contents
}

fn file_exists(path: &str) -> bool {
	let path_obj = Path::new(path);
	path_obj.is_file() && path_obj.exists()
}

fn serve_local_or_file(mut res: Response<Fresh>, path: &Vec<String>, default_file: &str) {
	let mime_types = Types::new().unwrap();
	let local_path = path[1..].iter().fold("../ui".to_owned(), |end, cur| end + "/" + cur);
	let file;
	let file_path: &str;
	if file_exists(&local_path) {
		file = read_file_bytes(&local_path);
		file_path = &local_path;
	} else {
		let content = read_file_bytes(default_file);
		//@HACK, @TODO: absolutize the html file so that it looks in the right place
		//this allows us to use file:/// locally, while still doing the right thing
		//when we're hooked up to the server
		let mut str = String::from_utf8(content).unwrap();
		str = str.replace("href=\"", "href=\"/app/");
		str = str.replace("src=\"", "src=\"/app/");
		str = str.replace("/app/http", "http");
		file = str.as_bytes().to_owned();
		file_path = default_file;
	}
	let mime: Mime = Mime::from_str(mime_types.mime_for_path(Path::new(&file_path))).unwrap();
	res.headers_mut().set(ContentType(mime));
	let mut res = res.start().unwrap();
	res.write_all(&file).unwrap();
	res.end().unwrap();
}

fn login(req: Request, mut res: Response<Fresh>) {

	match (&req.method.clone(), &req.uri.clone()) {
		(&hyper::Get, &RequestUri::AbsolutePath(ref relative_path)) => {

			// Form a url from the path
			let absolute_path = "http://localhost".to_string() + relative_path;
			let url = Url::parse(&*absolute_path).unwrap();

			// Get the file name
			let scheme_data = &url.scheme_data;

			let requested_file = match scheme_data {
				&Relative(ref rsd) => rsd.path[0].clone(),
				_ => panic!("Expected relative path"),
			};
			let path_info = match scheme_data {
				&Relative(ref rsd) => rsd,
				_ => panic!("Expected relative path"),
			};

			// Parse the query string
			let query_pairs = &url.query_pairs();

			// Handle login
			match &*requested_file {
				"app.html" | "app" => {
					serve_local_or_file(res, &path_info.path, "../ui/app.html");
				},
				"editor.html" | "editor" => {
					serve_local_or_file(res, &path_info.path, "../ui/editor.html");
				},
				"login.html" => {
					println!("Authenticating User");
					let pairs = query_pairs.clone().unwrap();
					match &pairs[..] {
						[(_ , ref page), (ref token_type, ref token), ..] if token_type.clone() == "token".to_string() => {

							// We have a login token, now to authenticate
							let client = hyper::client::Client::new();
							let api_call = "https://api-e1.authrocket.com/v1/sessions/".to_string() + token;
							let req = client.request(hyper::method::Method::Get,&*api_call);

							// Set the appropriate headers for authorocket
							let mut headers = Headers::new();
							let json: Mime = "application/json".parse().unwrap();
							let content_type = ContentType(json);
							headers.set_raw("X-Authrocket-Account",vec!["org_0vC7wPw9XphPGQnSqYB6bz".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Api-Key",vec!["key_jtnCRWxQvDD0p5HATR9RBIe4WnxnwV6pWNzwmZQLnSZ".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Realm",vec!["rl_0vC7wd03CqwhpK7kT8fvAc".to_string().into_bytes()]);
							headers.set_raw("Accept",vec!["application/json".to_string().into_bytes()]);
							headers.set(content_type);

							// Send the request and receive a response with session data
							let mut client_res = req.headers(headers).send().unwrap();

							match client_res.status_raw() {

								&hyper::http::RawStatus(200,_) => {

									let mut body = String::new();
									client_res.read_to_string(&mut body).unwrap();
									let session_data: Session = json::decode(&body).unwrap();
									println!("Welcome to Eve, {:?}!",session_data.user.username);
									println!("Login Successful. Redirecting to user area.");

									// Connect to the Eve runtime and add the user to the eveusers table
									let ws_result = open_websocket("ws://0.0.0.0:2794");
									match ws_result {
										// If things went okay, redirect to the Eve UI
										Ok(mut sender) => {
											// Form the response
											*res.status_mut() = hyper::status::StatusCode::PermanentRedirect;

											// Form the response headers
											let mut headers = Headers::new();
											let location = Location("/".to_string() + page);
											let user_cookie = Cookie::new("userid".to_string(),session_data.user.id.clone());
											let cookies = SetCookie(vec![user_cookie]);
											headers.set(location);
											headers.set(cookies);
											*res.headers_mut() = headers;

											// Create eveusers table and insert the new user
											let table_name = "eveusers";
											let table_fields = vec!["id","username"];

											let row_data = vec![
																Value::String(session_data.user.id.clone()),
																Value::String(session_data.user.username.clone())
														   	   ];
											let insert_user = insert_fact(&table_name,&table_fields,&row_data,None);
											send_event(&insert_user,&mut sender);
											let _ = sender.send_message(Message::Close(None));
										}
										// Otherwise, throw an error... maybe redirect to a special page.
										Err(e) => {
											println!("ERROR: Had trouble connecting to the Eve runtime: {}. Is the server running?",e);
											*res.status_mut() = hyper::status::StatusCode::NotFound;
											panic!("Oh no!");
											//serve_file("404.html",res);
										}
									}

									println!("Login complete.");
								}
								_ => {
									println!("ERROR: Could not authenticate user with token {}",token);
									*res.status_mut() = hyper::status::StatusCode::Forbidden;
									panic!("Oh no!");
									//serve_file("404.html",res);
								}
							};
						},
						_ => panic!("Oh no!"), //serve_file("404.html",res),
					}
				},
				"logout.html" => {
					println!("Logging out...");
					let user_id = server::get_user_id(req.headers.get::<hyper::header::Cookie>());
                	println!("{:?}",user_id);
				},
				"favicon.ico" => (),
				other => panic!("Cannot serve {}",other), //serve_file(&*requested_file,res),
			};
		}
		_ => panic!("Oh no!"),
	}
}<commit_msg>Workaround for blocking in login server<commit_after>#![feature(slice_patterns)]
#![feature(path_ext)]
extern crate eve;
extern crate hyper;
extern crate cookie;
extern crate mime;
extern crate url;
extern crate websocket;
extern crate rustc_serialize;
extern crate conduit_mime_types;

use std::io::Read;
use std::io::Write;
use std::fs::File;
use std::error::Error;
use hyper::net::Fresh;
use hyper::server::{Server, Request, Response};
use hyper::uri::RequestUri;
use hyper::Url;
use hyper::header::{Headers,ContentType,Location,SetCookie};
use cookie::Cookie;
use mime::Mime;
use url::SchemeData::Relative;
use rustc_serialize::json;
use websocket::{Message, Sender};
use std::path::Path;
use std::fs::PathExt;
use conduit_mime_types::Types;
use std::str::FromStr;

use eve::client::*;
use eve::server;
use eve::value::Value;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Session {
	client: String,
	id: String,
	user_id: String,
	object: String,
	created_at: f64,
	expires_at: f64,
	ip: String,
	user: User,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct User {
	custom: Custom,
	id: String,
	realm_id: String,
	username: String,
	state: String,
	user_type: String,
	reference: Option<String>,
	name: String,
	email: String,
	object: String,
	last_login_at: f64,
	last_login_on: f64,
	created_at: f64,
	first_name: Option<String>,
	last_name: Option<String>,
	credentials: Vec<Credential>,
	membership_count: f64,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Custom;

#[derive(RustcDecodable, RustcEncodable, Debug, Clone)]
struct Credential {
	id: String,
	credential_type: String,
	object: String,
}

fn main() {

    // TODO high thread-count is a workaround for https://github.com/hyperium/hyper/issues/368
	Server::http("0.0.0.0:8080").unwrap().handle_threads(login, 100).unwrap();
}

fn read_file_bytes(filename: &str) -> Vec<u8> {
    let mut file = File::open(&filename).unwrap();
    let mut contents: Vec<u8> = Vec::new();
	file.read_to_end(&mut contents).unwrap();
	contents
}

fn file_exists(path: &str) -> bool {
	let path_obj = Path::new(path);
	path_obj.is_file() && path_obj.exists()
}

fn serve_local_or_file(mut res: Response<Fresh>, path: &Vec<String>, default_file: &str) {
	let mime_types = Types::new().unwrap();
	let local_path = path[1..].iter().fold("../ui".to_owned(), |end, cur| end + "/" + cur);
	let file;
	let file_path: &str;
	if file_exists(&local_path) {
		file = read_file_bytes(&local_path);
		file_path = &local_path;
	} else {
		let content = read_file_bytes(default_file);
		//@HACK, @TODO: absolutize the html file so that it looks in the right place
		//this allows us to use file:/// locally, while still doing the right thing
		//when we're hooked up to the server
		let mut str = String::from_utf8(content).unwrap();
		str = str.replace("href=\"", "href=\"/app/");
		str = str.replace("src=\"", "src=\"/app/");
		str = str.replace("/app/http", "http");
		file = str.as_bytes().to_owned();
		file_path = default_file;
	}
	let mime: Mime = Mime::from_str(mime_types.mime_for_path(Path::new(&file_path))).unwrap();
	res.headers_mut().set(ContentType(mime));
	let mut res = res.start().unwrap();
	res.write_all(&file).unwrap();
	res.end().unwrap();
}

fn login(req: Request, mut res: Response<Fresh>) {

	match (&req.method.clone(), &req.uri.clone()) {
		(&hyper::Get, &RequestUri::AbsolutePath(ref relative_path)) => {

			// Form a url from the path
			let absolute_path = "http://localhost".to_string() + relative_path;
			let url = Url::parse(&*absolute_path).unwrap();

			// Get the file name
			let scheme_data = &url.scheme_data;

			let requested_file = match scheme_data {
				&Relative(ref rsd) => rsd.path[0].clone(),
				_ => panic!("Expected relative path"),
			};
			let path_info = match scheme_data {
				&Relative(ref rsd) => rsd,
				_ => panic!("Expected relative path"),
			};

			// Parse the query string
			let query_pairs = &url.query_pairs();

			// Handle login
			match &*requested_file {
				"app.html" | "app" => {
					serve_local_or_file(res, &path_info.path, "../ui/app.html");
				},
				"editor.html" | "editor" => {
					serve_local_or_file(res, &path_info.path, "../ui/editor.html");
				},
				"login.html" => {
					println!("Authenticating User");
					let pairs = query_pairs.clone().unwrap();
					match &pairs[..] {
						[(_ , ref page), (ref token_type, ref token), ..] if token_type.clone() == "token".to_string() => {

							// We have a login token, now to authenticate
							let client = hyper::client::Client::new();
							let api_call = "https://api-e1.authrocket.com/v1/sessions/".to_string() + token;
							let req = client.request(hyper::method::Method::Get,&*api_call);

							// Set the appropriate headers for authorocket
							let mut headers = Headers::new();
							let json: Mime = "application/json".parse().unwrap();
							let content_type = ContentType(json);
							headers.set_raw("X-Authrocket-Account",vec!["org_0vC7wPw9XphPGQnSqYB6bz".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Api-Key",vec!["key_jtnCRWxQvDD0p5HATR9RBIe4WnxnwV6pWNzwmZQLnSZ".to_string().into_bytes()]);
							headers.set_raw("X-Authrocket-Realm",vec!["rl_0vC7wd03CqwhpK7kT8fvAc".to_string().into_bytes()]);
							headers.set_raw("Accept",vec!["application/json".to_string().into_bytes()]);
							headers.set(content_type);

							// Send the request and receive a response with session data
							let mut client_res = req.headers(headers).send().unwrap();

							match client_res.status_raw() {

								&hyper::http::RawStatus(200,_) => {

									let mut body = String::new();
									client_res.read_to_string(&mut body).unwrap();
									let session_data: Session = json::decode(&body).unwrap();
									println!("Welcome to Eve, {:?}!",session_data.user.username);
									println!("Login Successful. Redirecting to user area.");

									// Connect to the Eve runtime and add the user to the eveusers table
									let ws_result = open_websocket("ws://0.0.0.0:2794");
									match ws_result {
										// If things went okay, redirect to the Eve UI
										Ok(mut sender) => {
											// Form the response
											*res.status_mut() = hyper::status::StatusCode::PermanentRedirect;

											// Form the response headers
											let mut headers = Headers::new();
											let location = Location("/".to_string() + page);
											let user_cookie = Cookie::new("userid".to_string(),session_data.user.id.clone());
											let cookies = SetCookie(vec![user_cookie]);
											headers.set(location);
											headers.set(cookies);
											*res.headers_mut() = headers;

											// Create eveusers table and insert the new user
											let table_name = "eveusers";
											let table_fields = vec!["id","username"];

											let row_data = vec![
																Value::String(session_data.user.id.clone()),
																Value::String(session_data.user.username.clone())
														   	   ];
											let insert_user = insert_fact(&table_name,&table_fields,&row_data,None);
											send_event(&insert_user,&mut sender);
											let _ = sender.send_message(Message::Close(None));
										}
										// Otherwise, throw an error... maybe redirect to a special page.
										Err(e) => {
											println!("ERROR: Had trouble connecting to the Eve runtime: {}. Is the server running?",e);
											*res.status_mut() = hyper::status::StatusCode::NotFound;
											panic!("Oh no!");
											//serve_file("404.html",res);
										}
									}

									println!("Login complete.");
								}
								_ => {
									println!("ERROR: Could not authenticate user with token {}",token);
									*res.status_mut() = hyper::status::StatusCode::Forbidden;
									panic!("Oh no!");
									//serve_file("404.html",res);
								}
							};
						},
						_ => panic!("Oh no!"), //serve_file("404.html",res),
					}
				},
				"logout.html" => {
					println!("Logging out...");
					let user_id = server::get_user_id(req.headers.get::<hyper::header::Cookie>());
                	println!("{:?}",user_id);
				},
				"favicon.ico" => (),
				other => panic!("Cannot serve {}",other), //serve_file(&*requested_file,res),
			};
		}
		_ => panic!("Oh no!"),
	}
}<|endoftext|>


<commit_before>extern mod std;

#[deriving(Eq)]
#[deriving(Clone)]
pub enum Value {
	List(~[Value]),
	Atom(~str),
	Str(~str),
	Num(float)
}

#[inline]
fn isws(c: char) -> bool {
	c == ' ' || c == '\t' || c == '\n'
}

/// Determines if the input begins a number
#[inline]
fn beginning_is_num(input: &str, i: uint) -> bool {
	let (c, c2) = (input[i] as char, input[i+1] as char);
	if c.is_digit() || c == '.' { true }
	else if c == '-' && (c2.is_digit() || c2 == '.') { true }
	else { false }
}

/// Reads a character after skipping whitespace
fn read_nows(input: &str, start: uint) -> Option<(uint, char)> {
	input.iter().enumerate().skip(start).skip_while(|&(_,c)| isws(c)).next()
}

/// Reads a numeric literal (integers or floats)
fn read_number(input: &str, start: uint) -> Option<(~Value, uint)> {
	let end = input.iter().skip(start).position(|c| isws(c) || c == ')');
	let pos = match end {
		Some(end) => start+end,
		None => input.len()
	};
	let acc = input.slice(start, pos);
	match std::float::from_str(acc) {
		Some(f) => Some((~Num(f), pos)),
		None => None
	}
}

/// Reads a string literal
fn read_string(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut acc = ~"";
	let mut was_escape = false;
	for i in range(start+1, input.len()) {
		match(input[i] as char) {
			'"' if !was_escape =>
				return Some((~Str(acc), i+1)), // got closing quote
			'\\' if !was_escape => {
				// escape codes
				was_escape = true;
				match input[i+1] as char {
					'\\' => acc.push_char('\\'),
					'"' => acc.push_char('"'),
					't' => acc.push_char('\t'),
					'n' => acc.push_char('\n'),
					c => fail!("unknown escape code: \\%c", c)
				}
			}
			c if !was_escape => acc.push_char(c),
			_ => { was_escape = false }
		}
	}

	// we didn't hit the end " so there must be a parse error
	None
}

/// Reads a list
fn read_list(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut list = ~[];
	let mut i = start;
	loop {
		match read_value(input, i) {
			Some((v,new_i)) => {
				list.push(*v);
				i = new_i;
			}
			None => {
				// probably a terminating ')' - if so, return the list and seek past it
				match read_nows(input, i) {
					Some((new_i, ')')) => return Some((~List(list), new_i+1)),
					_ => return None
				}
			}
		}
	}
}

/// Reads an atom (symbol/identifier)
fn read_atom(input: &str, start: uint) -> Option<(~Value, uint)> {
	let atom = std::str::from_chars(input.iter().skip(start).take_while(|&c| !isws(c) && c != ')').to_owned_vec());
	let len = atom.len();
	Some((~Atom(atom), start + len))
}

/// Reads any S-expression value
fn read_value(input: &str, start: uint) -> Option<(~Value, uint)> {
	if(start >= input.len()) {
		return None
	}

	match input[start] as char {
		c if isws(c) => read_value(input, start+1), // ignore whitespace
		'(' => read_list(input, start+1),
		')' => None,
		'"' => read_string(input, start),
		_ if beginning_is_num(input, start) => read_number(input, start),
		_ => read_atom(input, start)
	}
}

/// Public function for parsing a value from a string
pub fn from_str(input: &str) -> Option<Value> {
	match read_value(input, 0) {
		Some((v,_)) => Some(*v),
		None => None
	}
}

#[cfg(test)]
mod test {
	use super::*;

	fn parse_some(input: &str, expr: Value) {
		match from_str(input) {
			Some(ref p) if p == &expr => {}
			Some(ref p) => {
				if(p != &expr) {
					fail!("Expected %?, not %?, for %?", expr, *p, input)
				}
			}
			None => fail!("Got None for %?", input)
		}
	}

	#[test]
	fn test_sexpr() {
		assert_eq!(from_str(""), None);
		parse_some("123", Num(123.0));
		parse_some("-123", Num(-123.0));
		parse_some("()", List(~[]));
		parse_some("3.14159265358", Num(3.14159265358));
		parse_some("(hi)", List(~[Atom(~"hi")]));
		parse_some("(-hi)", List(~[Atom(~"-hi")]));
		parse_some("(-)", List(~[Atom(~"-")]));
		parse_some("(1)", List(~[Num(1.0)]));
		parse_some("(hi there)", List(~[Atom(~"hi"), Atom(~"there")]));
		parse_some("(hi (there))", List(~[Atom(~"hi"), List(~[Atom(~"there")])]));
		parse_some("(1 (2) 3)", List(~[Num(1f), List(~[Num(2f)]), Num(3f)]));
		parse_some("(hi (there) you!)", List(~[Atom(~"hi"), List(~[Atom(~"there")]), Atom(~"you!")]));
		parse_some("(hi 123456)", List(~[Atom(~"hi"), Num(123456.0)]));
		parse_some("(())", List(~[List(~[])]));
		parse_some("(hi (there (fellow (human-bot!))))",
			List(~[Atom(~"hi"),
				List(~[Atom(~"there"),
					List(~[Atom(~"fellow"),
						List(~[Atom(~"human-bot!")])])])])
		);
	}

	#[test]
	fn test_string() {
		parse_some("\"\"", Str(~""));
		parse_some("\"string\"", Str(~"string"));
		parse_some("\"hi\tthere\n\"", Str(~"hi\tthere\n"));
		parse_some("\"a\\\\b\"", Str(~"a\\b"));
		parse_some("(\"hello\" \"world\")", List(~[Str(~"hello"), Str(~"world")]));
	}

	#[test]
	fn test_whitespace() {
		// spaces
		parse_some("  (  1  )  ", List(~[Num(1.0)]));
		parse_some("  (  (  )  )  )", List(~[List(~[])]));

		// newlines
		parse_some("\n\n( \n\n )\n\n", List(~[]));
		parse_some("\n\n(\n\n123\n\n)\n\n", List(~[Num(123.0)]));
	}
}<commit_msg>sexpr: add tests for single char values and fix parser related to them<commit_after>extern mod std;

#[deriving(Eq)]
#[deriving(Clone)]
pub enum Value {
	List(~[Value]),
	Atom(~str),
	Str(~str),
	Num(float)
}

#[inline]
fn isws(c: char) -> bool {
	c == ' ' || c == '\t' || c == '\n'
}

/// Determines if the input begins a number
#[inline]
fn beginning_is_num(input: &str, i: uint) -> bool {
	let c = input[i] as char;
	if c.is_digit() || c == '.' { return true }

	if i+1 >= input.len() {
		return false
	}

	let c2 = input[i+1] as char;
	if c == '-' && (c2.is_digit() || c2 == '.') { return true }
	else { return false }
}

/// Reads a character after skipping whitespace
fn read_nows(input: &str, start: uint) -> Option<(uint, char)> {
	input.iter().enumerate().skip(start).skip_while(|&(_,c)| isws(c)).next()
}

/// Reads a numeric literal (integers or floats)
fn read_number(input: &str, start: uint) -> Option<(~Value, uint)> {
	let end = input.iter().skip(start).position(|c| isws(c) || c == ')');
	let pos = match end {
		Some(end) => start+end,
		None => input.len()
	};
	let acc = input.slice(start, pos);
	match std::float::from_str(acc) {
		Some(f) => Some((~Num(f), pos)),
		None => None
	}
}

/// Reads a string literal
fn read_string(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut acc = ~"";
	let mut was_escape = false;
	for i in range(start+1, input.len()) {
		match(input[i] as char) {
			'"' if !was_escape =>
				return Some((~Str(acc), i+1)), // got closing quote
			'\\' if !was_escape => {
				// escape codes
				was_escape = true;
				match input[i+1] as char {
					'\\' => acc.push_char('\\'),
					'"' => acc.push_char('"'),
					't' => acc.push_char('\t'),
					'n' => acc.push_char('\n'),
					c => fail!("unknown escape code: \\%c", c)
				}
			}
			c if !was_escape => acc.push_char(c),
			_ => { was_escape = false }
		}
	}

	// we didn't hit the end " so there must be a parse error
	None
}

/// Reads a list
fn read_list(input: &str, start: uint) -> Option<(~Value, uint)> {
	let mut list = ~[];
	let mut i = start;
	loop {
		match read_value(input, i) {
			Some((v,new_i)) => {
				list.push(*v);
				i = new_i;
			}
			None => {
				// probably a terminating ')' - if so, return the list and seek past it
				match read_nows(input, i) {
					Some((new_i, ')')) => return Some((~List(list), new_i+1)),
					_ => return None
				}
			}
		}
	}
}

/// Reads an atom (symbol/identifier)
fn read_atom(input: &str, start: uint) -> Option<(~Value, uint)> {
	let atom = std::str::from_chars(input.iter().skip(start).take_while(|&c| !isws(c) && c != ')').to_owned_vec());
	let len = atom.len();
	Some((~Atom(atom), start + len))
}

/// Reads any S-expression value
fn read_value(input: &str, start: uint) -> Option<(~Value, uint)> {
	if(start >= input.len()) {
		return None
	}

	match input[start] as char {
		c if isws(c) => read_value(input, start+1), // ignore whitespace
		'(' => read_list(input, start+1),
		')' => None,
		'"' => read_string(input, start),
		_ if beginning_is_num(input, start) => read_number(input, start),
		_ => read_atom(input, start)
	}
}

/// Public function for parsing a value from a string
pub fn from_str(input: &str) -> Option<Value> {
	match read_value(input, 0) {
		Some((v,_)) => Some(*v),
		None => None
	}
}

#[cfg(test)]
mod test {
	use super::*;

	fn parse_some(input: &str, expr: Value) {
		match from_str(input) {
			Some(ref p) if p == &expr => {}
			Some(ref p) => {
				if(p != &expr) {
					fail!("Expected %?, not %?, for %?", expr, *p, input)
				}
			}
			None => fail!("Got None for %?", input)
		}
	}

	#[test]
	fn test_sexpr() {
		assert_eq!(from_str(""), None);
		parse_some("123", Num(123.0));
		parse_some("-123", Num(-123.0));
		parse_some("1", Num(1f));
		parse_some("()", List(~[]));
		parse_some("3.14159265358", Num(3.14159265358));
		parse_some("(hi)", List(~[Atom(~"hi")]));
		parse_some("(-hi)", List(~[Atom(~"-hi")]));
		parse_some("(-)", List(~[Atom(~"-")]));
		parse_some("x", Atom(~"x"));
		parse_some("(1)", List(~[Num(1.0)]));
		parse_some("(hi there)", List(~[Atom(~"hi"), Atom(~"there")]));
		parse_some("(hi (there))", List(~[Atom(~"hi"), List(~[Atom(~"there")])]));
		parse_some("(1 (2) 3)", List(~[Num(1f), List(~[Num(2f)]), Num(3f)]));
		parse_some("(hi (there) you!)", List(~[Atom(~"hi"), List(~[Atom(~"there")]), Atom(~"you!")]));
		parse_some("(hi 123456)", List(~[Atom(~"hi"), Num(123456.0)]));
		parse_some("(())", List(~[List(~[])]));
		parse_some("(hi (there (fellow (human-bot!))))",
			List(~[Atom(~"hi"),
				List(~[Atom(~"there"),
					List(~[Atom(~"fellow"),
						List(~[Atom(~"human-bot!")])])])])
		);
	}

	#[test]
	fn test_string() {
		parse_some("\"\"", Str(~""));
		parse_some("\"string\"", Str(~"string"));
		parse_some("\"hi\tthere\n\"", Str(~"hi\tthere\n"));
		parse_some("\"a\\\\b\"", Str(~"a\\b"));
		parse_some("(\"hello\" \"world\")", List(~[Str(~"hello"), Str(~"world")]));
	}

	#[test]
	fn test_whitespace() {
		// spaces
		parse_some("  (  1  )  ", List(~[Num(1.0)]));
		parse_some("  (  (  )  )  )", List(~[List(~[])]));

		// newlines
		parse_some("\n\n( \n\n )\n\n", List(~[]));
		parse_some("\n\n(\n\n123\n\n)\n\n", List(~[Num(123.0)]));
	}
}<|endoftext|>


<commit_before>use clap::{App, Arg};
use futures::StreamExt;
use serde_json::json;

use cloudevents::{EventBuilder, EventBuilderV10};
use cloudevents_sdk_rdkafka::{FutureRecordExt, MessageExt, MessageRecord};

use rdkafka::config::{ClientConfig, RDKafkaLogLevel};
use rdkafka::consumer::stream_consumer::StreamConsumer;
use rdkafka::consumer::{CommitMode, Consumer, DefaultConsumerContext};
use rdkafka::producer::{FutureProducer, FutureRecord};
use std::time::Duration;

// You need a running Kafka cluster to try out this example.
// With docker: docker run --rm --net=host -e ADV_HOST=localhost -e SAMPLEDATA=0 lensesio/fast-data-dev

async fn consume(brokers: &str, group_id: &str, topics: &[&str]) {
    let consumer: StreamConsumer<DefaultConsumerContext> = ClientConfig::new()
        .set("group.id", group_id)
        .set("bootstrap.servers", brokers)
        .set("enable.partition.eof", "false")
        .set("session.timeout.ms", "6000")
        .set("enable.auto.commit", "true")
        //.set("statistics.interval.ms", "30000")
        //.set("auto.offset.reset", "smallest")
        .set_log_level(RDKafkaLogLevel::Debug)
        .create_with_context(DefaultConsumerContext)
        .expect("Consumer creation failed");

    consumer
        .subscribe(&topics.to_vec())
        .expect("Can't subscribe to specified topics");

    // consumer.start() returns a stream. The stream can be used ot chain together expensive steps,
    // such as complex computations on a thread pool or asynchronous IO.
    let mut message_stream = consumer.start();

    while let Some(message) = message_stream.next().await {
        match message {
            Err(e) => println!("Kafka error: {}", e),
            Ok(m) => {
                let event = m.to_event().unwrap();
                println!("Received Event: {:#?}", event);

                consumer.commit_message(&m, CommitMode::Async).unwrap();
            }
        };
    }
}

async fn produce(brokers: &str, topic_name: &str) {
    let producer: &FutureProducer = &ClientConfig::new()
        .set("bootstrap.servers", brokers)
        .set("message.timeout.ms", "5000")
        .create()
        .expect("Producer creation error");

    // This loop is non blocking: all messages will be sent one after the other, without waiting
    // for the results.
    let futures = (0..5)
        .map(|i| async move {
            // The send operation on the topic returns a future, which will be
            // completed once the result or failure from Kafka is received.
            let event = EventBuilderV10::new()
                .id(i.to_string())
                .ty("example.test")
                .source("http://localhost/")
                .data("application/json", json!({"hello": "world"}))
                .build()
                .unwrap();

            println!("Sending event: {:#?}", event);

            let message_record =
                MessageRecord::from_event(event).expect("error while serializing the event");

            let delivery_status = producer
                .send(
                    FutureRecord::to(topic_name)
                        .message_record(&message_record)
                        .key(&format!("Key {}", i)),
                    Duration::from_secs(10),
                )
                .await;

            // This will be executed when the result is received.
            println!("Delivery status for message {} received", i);
            delivery_status
        })
        .collect::<Vec<_>>();

    // This loop will wait until all delivery statuses have been received.
    for future in futures {
        println!("Future completed. Result: {:?}", future.await);
    }
}

#[tokio::main]
async fn main() {
    let selector = App::new("CloudEvents Kafka Example")
        .version(option_env!("CARGO_PKG_VERSION").unwrap_or(""))
        .about("select consumer or producer")
        .arg(
            Arg::with_name("mode")
                .long("mode")
                .help("enter \"consmer\" or \"producer\"")
                .takes_value(true)
                .possible_values(&["consumer", "producer"])
                .required(true),
        )
        .arg(
            Arg::with_name("topics")
                .long("topics")
                .help("Topic list")
                .takes_value(true)
                .multiple(true)
                .requires_if("consumer", "mode"),
        )
        .arg(
            Arg::with_name("topic")
                .long("topic")
                .help("Destination topic")
                .takes_value(true)
                .requires_if("producer", "mode"),
        )
        .arg(
            Arg::with_name("brokers")
                .short("b")
                .long("brokers")
                .help("Broker list in kafka format")
                .takes_value(true)
                .default_value("localhost:9092"),
        )
        .arg(
            Arg::with_name("group-id")
                .short("g")
                .long("group-id")
                .help("Consumer group id")
                .takes_value(true)
                .default_value("example_consumer_group_id"),
        )
        .get_matches();

    match selector.value_of("mode").unwrap() {
        "producer" => {
            produce(
                selector.value_of("brokers").unwrap(),
                selector.value_of("topic").unwrap(),
            )
            .await
        }
        "consumer" => {
            consume(
                selector.value_of("brokers").unwrap(),
                selector.value_of("group-id").unwrap(),
                &selector.values_of("topics").unwrap().collect::<Vec<&str>>(),
            )
            .await
        }
        _ => (),
    };
}
<commit_msg>:lipstick: Use stream() instead of deprecated start() (#126)<commit_after>use clap::{App, Arg};
use futures::StreamExt;
use serde_json::json;

use cloudevents::{EventBuilder, EventBuilderV10};
use cloudevents_sdk_rdkafka::{FutureRecordExt, MessageExt, MessageRecord};

use rdkafka::config::{ClientConfig, RDKafkaLogLevel};
use rdkafka::consumer::stream_consumer::StreamConsumer;
use rdkafka::consumer::{CommitMode, Consumer, DefaultConsumerContext};
use rdkafka::producer::{FutureProducer, FutureRecord};
use std::time::Duration;

// You need a running Kafka cluster to try out this example.
// With docker: docker run --rm --net=host -e ADV_HOST=localhost -e SAMPLEDATA=0 lensesio/fast-data-dev

async fn consume(brokers: &str, group_id: &str, topics: &[&str]) {
    let consumer: StreamConsumer<DefaultConsumerContext> = ClientConfig::new()
        .set("group.id", group_id)
        .set("bootstrap.servers", brokers)
        .set("enable.partition.eof", "false")
        .set("session.timeout.ms", "6000")
        .set("enable.auto.commit", "true")
        //.set("statistics.interval.ms", "30000")
        //.set("auto.offset.reset", "smallest")
        .set_log_level(RDKafkaLogLevel::Debug)
        .create_with_context(DefaultConsumerContext)
        .expect("Consumer creation failed");

    consumer
        .subscribe(&topics.to_vec())
        .expect("Can't subscribe to specified topics");

    // consumer.stream() returns a stream. The stream can be used ot chain together expensive steps,
    // such as complex computations on a thread pool or asynchronous IO.
    let mut message_stream = consumer.stream();

    while let Some(message) = message_stream.next().await {
        match message {
            Err(e) => println!("Kafka error: {}", e),
            Ok(m) => {
                let event = m.to_event().unwrap();
                println!("Received Event: {:#?}", event);

                consumer.commit_message(&m, CommitMode::Async).unwrap();
            }
        };
    }
}

async fn produce(brokers: &str, topic_name: &str) {
    let producer: &FutureProducer = &ClientConfig::new()
        .set("bootstrap.servers", brokers)
        .set("message.timeout.ms", "5000")
        .create()
        .expect("Producer creation error");

    // This loop is non blocking: all messages will be sent one after the other, without waiting
    // for the results.
    let futures = (0..5)
        .map(|i| async move {
            // The send operation on the topic returns a future, which will be
            // completed once the result or failure from Kafka is received.
            let event = EventBuilderV10::new()
                .id(i.to_string())
                .ty("example.test")
                .source("http://localhost/")
                .data("application/json", json!({"hello": "world"}))
                .build()
                .unwrap();

            println!("Sending event: {:#?}", event);

            let message_record =
                MessageRecord::from_event(event).expect("error while serializing the event");

            let delivery_status = producer
                .send(
                    FutureRecord::to(topic_name)
                        .message_record(&message_record)
                        .key(&format!("Key {}", i)),
                    Duration::from_secs(10),
                )
                .await;

            // This will be executed when the result is received.
            println!("Delivery status for message {} received", i);
            delivery_status
        })
        .collect::<Vec<_>>();

    // This loop will wait until all delivery statuses have been received.
    for future in futures {
        println!("Future completed. Result: {:?}", future.await);
    }
}

#[tokio::main]
async fn main() {
    let selector = App::new("CloudEvents Kafka Example")
        .version(option_env!("CARGO_PKG_VERSION").unwrap_or(""))
        .about("select consumer or producer")
        .arg(
            Arg::with_name("mode")
                .long("mode")
                .help("enter \"consmer\" or \"producer\"")
                .takes_value(true)
                .possible_values(&["consumer", "producer"])
                .required(true),
        )
        .arg(
            Arg::with_name("topics")
                .long("topics")
                .help("Topic list")
                .takes_value(true)
                .multiple(true)
                .requires_if("consumer", "mode"),
        )
        .arg(
            Arg::with_name("topic")
                .long("topic")
                .help("Destination topic")
                .takes_value(true)
                .requires_if("producer", "mode"),
        )
        .arg(
            Arg::with_name("brokers")
                .short("b")
                .long("brokers")
                .help("Broker list in kafka format")
                .takes_value(true)
                .default_value("localhost:9092"),
        )
        .arg(
            Arg::with_name("group-id")
                .short("g")
                .long("group-id")
                .help("Consumer group id")
                .takes_value(true)
                .default_value("example_consumer_group_id"),
        )
        .get_matches();

    match selector.value_of("mode").unwrap() {
        "producer" => {
            produce(
                selector.value_of("brokers").unwrap(),
                selector.value_of("topic").unwrap(),
            )
            .await
        }
        "consumer" => {
            consume(
                selector.value_of("brokers").unwrap(),
                selector.value_of("group-id").unwrap(),
                &selector.values_of("topics").unwrap().collect::<Vec<&str>>(),
            )
            .await
        }
        _ => (),
    };
}
<|endoftext|>


<commit_before>
use std::str::CharIndices;
use std::iter::Peekable;

#[derive(PartialEq, Debug)]
pub enum Token<'a> {
  Eof(usize, usize),
  Punctuator(Punctuator, usize),
  Name(&'a str, usize, usize),
  IntValue(&'a str, usize, usize),
  FloatValue(&'a str, usize, usize),
  StringValue(&'a str, usize, usize),
}

#[derive(PartialEq, Debug)]
pub enum Punctuator {
  Bang,
  Dollar,
  LeftParen,
  RightParen,
  Spread(usize),
  Colon,
  Equals,
  At,
  LeftBracket,
  RightBracket,
  LeftBrace,
  RightBrace,
  Pipe,
}

macro_rules! take {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    if let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.iter.next();
            $lexer.hi = p;
            is_taken = true;
          }
        )*
        _ => {}
      }
    }
    is_taken
  });
}

macro_rules! take_while {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    while let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.iter.next();
            is_taken = true;
          }
        )*
        _ => {
          $lexer.hi = p;
          break;
        }
      }
    }
    is_taken
  });
}

macro_rules! take_while_not {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    while let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.hi = p;
            break;
          }
        )*
        _ => {
            $lexer.iter.next();
            is_taken = true;
        }
      }
    }
    is_taken
  });
}

macro_rules! peek {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_match = false;
    if let Some(&(_, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            is_match = true;
          }
        )*
        _ => {}
      }
    }
    is_match
  });
}

macro_rules! take_eof {
  ($lexer: ident) => ({
    if $lexer.iter.peek().is_none() {
      $lexer.hi = $lexer.input_len;
      true
    } else {
      false
    }
  });
}

pub struct Lexer<'a> {
  input: &'a str,
  input_len: usize,
  iter: Peekable<CharIndices<'a>>,
  is_eof: bool,
  lo: usize,
  hi: usize,
}

impl<'a> Lexer<'a> {
  pub fn new(input: &'a str) -> Lexer<'a> {
    Lexer {
      input: input,
      input_len: input.len(),
      iter: input.char_indices().peekable(),
      is_eof: false,
      lo: 0,
      hi: 0,
    }
  }
}

fn skip_ignored_token(lexer: &mut Lexer) {
  loop {
    if take!(lexer, '#') {
      take_while_not!(lexer, '\r' | '\n');
    }
    if !take_while!(lexer, '\u{feff}' | ' ' | '\t' | '\r' | '\n' | ',') {
      break;
    }
  }
}

fn scan_spread(lexer: &mut Lexer) -> bool {
  if take!(lexer, '.') {
    if take!(lexer, '.') {
      if take!(lexer, '.') {
        return true;
      }
    }
  }
  return false;
}

fn scan_name(lexer: &mut Lexer) {
  take_while!(lexer, '_' | 'a'...'z' | 'A'...'Z' | '0'...'9');
  take_eof!(lexer);
}

// Return the raw string without unescape character
fn scan_string(lexer: &mut Lexer) -> (bool, bool) {
  let mut is_bad_escape = false;
  let mut is_terminated = false;
  if take!(lexer, '"') {
    lexer.lo = lexer.lo + 1;
  }
  loop {
    if take!(lexer, '\\') {
      if !take!(lexer, '\\' | '"' | 'b' | 'f' | 'n' | 'r' | 't' | '/' | 'u') {
        is_bad_escape = true;
        break;
      }
    }
    take_while_not!(lexer, '"' | '\\');
    if take!(lexer, '"') {
      is_terminated = true;
      break;
    }
  }
  (is_terminated, is_bad_escape)
}

// IntValue:   (+|-)?(0|[1-9][0-9]*)
// FloatValue: (+|-)?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)?
fn scan_number(lexer: &mut Lexer) -> (bool, bool) {
  let mut is_float = false;
  take!(lexer, '+' | '-');
  // Integer part
  if take!(lexer, '1'...'9') {
    take_while!(lexer, '0'...'9');
    if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
      return (true, is_float);
    }
  } else if take!(lexer, '0') {
    if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
      return (true, is_float);
    }
  }
  // Fractional part
  if take!(lexer, '.') {
    if !take_while!(lexer, '0'...'9') {
      return (false, is_float);
    }
    is_float = true;
  }
  // Exponent part
  if !is_float && peek!(lexer, 'E' | 'e') {
    return (false, is_float);
  }
  if take!(lexer, 'E' | 'e') {
    if take!(lexer, '+' | '-') {
      if !take_while!(lexer, '0'...'9') {
        return (false, is_float);
      }
    } else {
      take_while!(lexer, '0'...'9');
    }
  }

  if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
    return (true, is_float);
  }
  return (false, is_float);
}

impl<'a> Iterator for Lexer<'a> {
  type Item = Result<Token<'a>, &'a str>;
  fn next(&mut self) -> Option<Result<Token<'a>, &'a str>> {
    use self::Token::*;
    use self::Punctuator::*;

    if !self.is_eof && take_eof!(self) {
      self.is_eof = true;
      return Some(Ok(Token::Eof(self.lo, self.hi)));
    }
    if self.is_eof {
      return None;
    }
    skip_ignored_token(self);

    let mut item = None;
    if let Some(&(p, c)) = self.iter.peek() {
      self.lo = p;
      self.hi = p;
      item = match c {
        '!' => {
          self.iter.next();
          Some(Ok(Punctuator(Bang, self.lo)))
        }
        '$' => {
          self.iter.next();
          Some(Ok(Punctuator(Dollar, self.lo)))
        }
        '(' => {
          self.iter.next();
          Some(Ok(Punctuator(LeftParen, self.lo)))
        }
        ')' => {
          self.iter.next();
          Some(Ok(Punctuator(RightParen, self.lo)))
        }
        ':' => {
          self.iter.next();
          Some(Ok(Punctuator(Colon, self.lo)))
        }
        '=' => {
          self.iter.next();
          Some(Ok(Punctuator(Equals, self.lo)))
        }
        '@' => {
          self.iter.next();
          Some(Ok(Punctuator(At, self.lo)))
        }
        '[' => {
          self.iter.next();
          Some(Ok(Punctuator(LeftBracket, self.lo)))
        }
        ']' => {
          self.iter.next();
          Some(Ok(Punctuator(RightBracket, self.lo)))
        }
        '{' => {
          self.iter.next();
          Some(Ok(Punctuator(LeftBrace, self.lo)))
        }
        '}' => {
          self.iter.next();
          Some(Ok(Punctuator(RightBrace, self.lo)))
        }
        '|' => {
          self.iter.next();
          Some(Ok(Punctuator(Pipe, self.lo)))
        }
        '.' => {
          if scan_spread(self) {
            Some(Ok(Punctuator(Spread(self.lo), self.hi)))
          } else {
            Some(Err("Unexpected character."))
          }
        }
        '_' | 'a'...'z' | 'A'...'Z' => {
          scan_name(self);
          Some(Ok(Name(&self.input[self.lo..self.hi], self.lo, self.hi)))
        }
        '-' | '0'...'9' => {
          match scan_number(self) {
            (false, false) => Some(Err("Invalid integer number.")),
            (false, true) => Some(Err("Invalid float number.")),
            (true, false) => Some(Ok(IntValue(&self.input[self.lo..self.hi], self.lo, self.hi))),
            (true, true) => Some(Ok(FloatValue(&self.input[self.lo..self.hi], self.lo, self.hi))),
          }
        }
        '"' => {
          match scan_string(self) {
            (false, _) => Some(Err("Unterminated string.")),
            (_, true) => Some(Err("Bad character escape sequence.")),
            _ => Some(Ok(StringValue(&self.input[self.lo..self.hi], self.lo, self.hi))),
          }
        }
        _ => Some(Err("Unexpected character.")),
      }
    }
    item
  }
}

#[cfg(test)]
mod tests {
  use super::Punctuator::*;
  use super::Token::*;
  use super::{Lexer, Token};

  fn test_next_token(lexer: &mut Lexer, expected: Token) {
    let next = lexer.next();
    assert_eq!(Some(Ok(expected)), next);
  }

  fn test_with_lex(input: &str, expeced: Token) {
    let mut lexer = Lexer::new(&input);
    test_next_token(&mut lexer, expeced);
  }

  fn test_str(input: &str, expeced: &str) {
    let len = expeced.len();
    test_with_lex(input, StringValue(expeced, 1, len + 1))
  }

  #[test]
  fn test_string() {
    test_str(r#""simple""#, r#"simple"#);
    test_str(r#"" white space ""#, r#" white space "#);
    test_str(r#""quote \"""#, r#"quote \""#);
    test_str(r#""slashes \\ \/""#, r#"slashes \\ \/"#);
    test_str(r#""unicode \u1234\u5678\u90AB\uCDEF""#,
             r#"unicode \u1234\u5678\u90AB\uCDEF"#);
  }

  #[test]
  fn test_name() {
    let mut lexer = Lexer::new("     name1    name2   \"simple\" \"  white space   \" other_name");
    test_next_token(&mut lexer, Name("name1", 5, 10));
    test_next_token(&mut lexer, Name("name2", 14, 19));
    test_next_token(&mut lexer, StringValue("simple", 23, 29));
    test_next_token(&mut lexer, StringValue("  white space   ", 32, 48));
    test_next_token(&mut lexer, Name("other_name", 50, 60));
    test_next_token(&mut lexer, Eof(50,60));
    assert_eq!(None, lexer.next());
  }

  #[test]
  fn test_number() {
    let mut lexer = Lexer::new("-9 0 9 -0 -9 1234 -1234 0.0 -0.0 1.0 -1.012 -0.101 1.0e2 -1.0E2 \
                                0.00e-002 -0.00E+002 9.1E+0");
    test_next_token(&mut lexer, IntValue("-9", 0, 2));
    test_next_token(&mut lexer, IntValue("0", 3, 4));
    test_next_token(&mut lexer, IntValue("9", 5, 6));
    test_next_token(&mut lexer, IntValue("-0", 7, 9));
    test_next_token(&mut lexer, IntValue("-9", 10, 12));
    test_next_token(&mut lexer, IntValue("1234", 13, 17));
    test_next_token(&mut lexer, IntValue("-1234", 18, 23));
    test_next_token(&mut lexer, FloatValue("0.0", 24, 27));
    test_next_token(&mut lexer, FloatValue("-0.0", 28, 32));
    test_next_token(&mut lexer, FloatValue("1.0", 33, 36));
    test_next_token(&mut lexer, FloatValue("-1.012", 37, 43));
    test_next_token(&mut lexer, FloatValue("-0.101", 44, 50));
    test_next_token(&mut lexer, FloatValue("1.0e2", 51, 56));
    test_next_token(&mut lexer, FloatValue("-1.0E2", 57, 63));
    test_next_token(&mut lexer, FloatValue("0.00e-002", 64, 73));
    test_next_token(&mut lexer, FloatValue("-0.00E+002", 74, 84));
    test_next_token(&mut lexer, FloatValue("9.1E+0", 85, 91));
    test_next_token(&mut lexer, Eof(85,91));
    assert_eq!(None, lexer.next());
  }

  #[test]
  fn test_symbol() {
    let mut lexer = Lexer::new("@ !  :$ =    [  {   (|] } )      ...");
    test_next_token(&mut lexer, Punctuator(At, 0));
    test_next_token(&mut lexer, Punctuator(Bang, 2));
    test_next_token(&mut lexer, Punctuator(Colon, 5));
    test_next_token(&mut lexer, Punctuator(Dollar, 6));
    test_next_token(&mut lexer, Punctuator(Equals, 8));
    test_next_token(&mut lexer, Punctuator(LeftBracket, 13));
    test_next_token(&mut lexer, Punctuator(LeftBrace, 16));
    test_next_token(&mut lexer, Punctuator(LeftParen, 20));
    test_next_token(&mut lexer, Punctuator(Pipe, 21));
    test_next_token(&mut lexer, Punctuator(RightBracket, 22));
    test_next_token(&mut lexer, Punctuator(RightBrace, 24));
    test_next_token(&mut lexer, Punctuator(RightParen, 26));
    test_next_token(&mut lexer, Punctuator(Spread(33), 35));
    test_next_token(&mut lexer, Eof(33,36));
    assert_eq!(None, lexer.next());
  }
}
<commit_msg>style: change eof to only take the hi bound as the lo one is completly ignored.<commit_after>
use std::str::CharIndices;
use std::iter::Peekable;

#[derive(PartialEq, Debug)]
pub enum Token<'a> {
  Eof(usize),
  Punctuator(Punctuator, usize),
  Name(&'a str, usize, usize),
  IntValue(&'a str, usize, usize),
  FloatValue(&'a str, usize, usize),
  StringValue(&'a str, usize, usize),
}

#[derive(PartialEq, Debug)]
pub enum Punctuator {
  Bang,
  Dollar,
  LeftParen,
  RightParen,
  Spread(usize),
  Colon,
  Equals,
  At,
  LeftBracket,
  RightBracket,
  LeftBrace,
  RightBrace,
  Pipe,
}

macro_rules! take {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    if let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.iter.next();
            $lexer.hi = p;
            is_taken = true;
          }
        )*
        _ => {}
      }
    }
    is_taken
  });
}

macro_rules! take_while {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    while let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.iter.next();
            is_taken = true;
          }
        )*
        _ => {
          $lexer.hi = p;
          break;
        }
      }
    }
    is_taken
  });
}

macro_rules! take_while_not {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_taken = false;
    while let Some(&(p, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            $lexer.hi = p;
            break;
          }
        )*
        _ => {
            $lexer.iter.next();
            is_taken = true;
        }
      }
    }
    is_taken
  });
}

macro_rules! peek {
  ($lexer: ident, $($p: pat)|*) => ({
    let mut is_match = false;
    if let Some(&(_, c)) = $lexer.iter.peek() {
      match c {
        $(
          $p => {
            is_match = true;
          }
        )*
        _ => {}
      }
    }
    is_match
  });
}

macro_rules! take_eof {
  ($lexer: ident) => ({
    if $lexer.iter.peek().is_none() {
      $lexer.hi = $lexer.input_len;
      true
    } else {
      false
    }
  });
}

pub struct Lexer<'a> {
  input: &'a str,
  input_len: usize,
  iter: Peekable<CharIndices<'a>>,
  is_eof: bool,
  lo: usize,
  hi: usize,
}

impl<'a> Lexer<'a> {
  pub fn new(input: &'a str) -> Lexer<'a> {
    Lexer {
      input: input,
      input_len: input.len(),
      iter: input.char_indices().peekable(),
      is_eof: false,
      lo: 0,
      hi: 0,
    }
  }
}

fn skip_ignored_token(lexer: &mut Lexer) {
  loop {
    if take!(lexer, '#') {
      take_while_not!(lexer, '\r' | '\n');
    }
    if !take_while!(lexer, '\u{feff}' | ' ' | '\t' | '\r' | '\n' | ',') {
      break;
    }
  }
}

fn scan_spread(lexer: &mut Lexer) -> bool {
  if take!(lexer, '.') {
    if take!(lexer, '.') {
      if take!(lexer, '.') {
        return true;
      }
    }
  }
  return false;
}

fn scan_name(lexer: &mut Lexer) {
  take_while!(lexer, '_' | 'a'...'z' | 'A'...'Z' | '0'...'9');
  take_eof!(lexer);
}

// Return the raw string without unescape character
fn scan_string(lexer: &mut Lexer) -> (bool, bool) {
  let mut is_bad_escape = false;
  let mut is_terminated = false;
  if take!(lexer, '"') {
    lexer.lo = lexer.lo + 1;
  }
  loop {
    if take!(lexer, '\\') {
      if !take!(lexer, '\\' | '"' | 'b' | 'f' | 'n' | 'r' | 't' | '/' | 'u') {
        is_bad_escape = true;
        break;
      }
    }
    take_while_not!(lexer, '"' | '\\');
    if take!(lexer, '"') {
      is_terminated = true;
      break;
    }
  }
  (is_terminated, is_bad_escape)
}

// IntValue:   (+|-)?(0|[1-9][0-9]*)
// FloatValue: (+|-)?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)?
fn scan_number(lexer: &mut Lexer) -> (bool, bool) {
  let mut is_float = false;
  take!(lexer, '+' | '-');
  // Integer part
  if take!(lexer, '1'...'9') {
    take_while!(lexer, '0'...'9');
    if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
      return (true, is_float);
    }
  } else if take!(lexer, '0') {
    if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
      return (true, is_float);
    }
  }
  // Fractional part
  if take!(lexer, '.') {
    if !take_while!(lexer, '0'...'9') {
      return (false, is_float);
    }
    is_float = true;
  }
  // Exponent part
  if !is_float && peek!(lexer, 'E' | 'e') {
    return (false, is_float);
  }
  if take!(lexer, 'E' | 'e') {
    if take!(lexer, '+' | '-') {
      if !take_while!(lexer, '0'...'9') {
        return (false, is_float);
      }
    } else {
      take_while!(lexer, '0'...'9');
    }
  }

  if take!(lexer, ' ' | '\t' | '\r' | '\n' | ',') || take_eof!(lexer) {
    return (true, is_float);
  }
  return (false, is_float);
}

impl<'a> Iterator for Lexer<'a> {
  type Item = Result<Token<'a>, &'a str>;
  fn next(&mut self) -> Option<Result<Token<'a>, &'a str>> {
    use self::Token::*;
    use self::Punctuator::*;

    if !self.is_eof && take_eof!(self) {
      self.is_eof = true;
      return Some(Ok(Token::Eof(self.hi)));
    }
    if self.is_eof {
      return None;
    }
    skip_ignored_token(self);

    let mut item = None;
    if let Some(&(p, c)) = self.iter.peek() {
      self.lo = p;
      self.hi = p;
      item = match c {
        '!' => {
          self.iter.next();
          Some(Ok(Punctuator(Bang, self.lo)))
        }
        '$' => {
          self.iter.next();
          Some(Ok(Punctuator(Dollar, self.lo)))
        }
        '(' => {
          self.iter.next();
          Some(Ok(Punctuator(LeftParen, self.lo)))
        }
        ')' => {
          self.iter.next();
          Some(Ok(Punctuator(RightParen, self.lo)))
        }
        ':' => {
          self.iter.next();
          Some(Ok(Punctuator(Colon, self.lo)))
        }
        '=' => {
          self.iter.next();
          Some(Ok(Punctuator(Equals, self.lo)))
        }
        '@' => {
          self.iter.next();
          Some(Ok(Punctuator(At, self.lo)))
        }
        '[' => {
          self.iter.next();
          Some(Ok(Punctuator(LeftBracket, self.lo)))
        }
        ']' => {
          self.iter.next();
          Some(Ok(Punctuator(RightBracket, self.lo)))
        }
        '{' => {
          self.iter.next();
          Some(Ok(Punctuator(LeftBrace, self.lo)))
        }
        '}' => {
          self.iter.next();
          Some(Ok(Punctuator(RightBrace, self.lo)))
        }
        '|' => {
          self.iter.next();
          Some(Ok(Punctuator(Pipe, self.lo)))
        }
        '.' => {
          if scan_spread(self) {
            Some(Ok(Punctuator(Spread(self.lo), self.hi)))
          } else {
            Some(Err("Unexpected character."))
          }
        }
        '_' | 'a'...'z' | 'A'...'Z' => {
          scan_name(self);
          Some(Ok(Name(&self.input[self.lo..self.hi], self.lo, self.hi)))
        }
        '-' | '0'...'9' => {
          match scan_number(self) {
            (false, false) => Some(Err("Invalid integer number.")),
            (false, true) => Some(Err("Invalid float number.")),
            (true, false) => Some(Ok(IntValue(&self.input[self.lo..self.hi], self.lo, self.hi))),
            (true, true) => Some(Ok(FloatValue(&self.input[self.lo..self.hi], self.lo, self.hi))),
          }
        }
        '"' => {
          match scan_string(self) {
            (false, _) => Some(Err("Unterminated string.")),
            (_, true) => Some(Err("Bad character escape sequence.")),
            _ => Some(Ok(StringValue(&self.input[self.lo..self.hi], self.lo, self.hi))),
          }
        }
        _ => Some(Err("Unexpected character.")),
      }
    }
    item
  }
}

#[cfg(test)]
mod tests {
  use super::Punctuator::*;
  use super::Token::*;
  use super::{Lexer, Token};

  fn test_next_token(lexer: &mut Lexer, expected: Token) {
    let next = lexer.next();
    assert_eq!(Some(Ok(expected)), next);
  }

  fn test_with_lex(input: &str, expeced: Token) {
    let mut lexer = Lexer::new(&input);
    test_next_token(&mut lexer, expeced);
  }

  fn test_str(input: &str, expeced: &str) {
    let len = expeced.len();
    test_with_lex(input, StringValue(expeced, 1, len + 1))
  }

  #[test]
  fn test_string() {
    test_str(r#""simple""#, r#"simple"#);
    test_str(r#"" white space ""#, r#" white space "#);
    test_str(r#""quote \"""#, r#"quote \""#);
    test_str(r#""slashes \\ \/""#, r#"slashes \\ \/"#);
    test_str(r#""unicode \u1234\u5678\u90AB\uCDEF""#,
             r#"unicode \u1234\u5678\u90AB\uCDEF"#);
  }

  #[test]
  fn test_name() {
    let mut lexer = Lexer::new("     name1    name2   \"simple\" \"  white space   \" other_name");
    test_next_token(&mut lexer, Name("name1", 5, 10));
    test_next_token(&mut lexer, Name("name2", 14, 19));
    test_next_token(&mut lexer, StringValue("simple", 23, 29));
    test_next_token(&mut lexer, StringValue("  white space   ", 32, 48));
    test_next_token(&mut lexer, Name("other_name", 50, 60));
    test_next_token(&mut lexer, Eof(60));
    assert_eq!(None, lexer.next());
  }

  #[test]
  fn test_number() {
    let mut lexer = Lexer::new("-9 0 9 -0 -9 1234 -1234 0.0 -0.0 1.0 -1.012 -0.101 1.0e2 -1.0E2 \
                                0.00e-002 -0.00E+002 9.1E+0");
    test_next_token(&mut lexer, IntValue("-9", 0, 2));
    test_next_token(&mut lexer, IntValue("0", 3, 4));
    test_next_token(&mut lexer, IntValue("9", 5, 6));
    test_next_token(&mut lexer, IntValue("-0", 7, 9));
    test_next_token(&mut lexer, IntValue("-9", 10, 12));
    test_next_token(&mut lexer, IntValue("1234", 13, 17));
    test_next_token(&mut lexer, IntValue("-1234", 18, 23));
    test_next_token(&mut lexer, FloatValue("0.0", 24, 27));
    test_next_token(&mut lexer, FloatValue("-0.0", 28, 32));
    test_next_token(&mut lexer, FloatValue("1.0", 33, 36));
    test_next_token(&mut lexer, FloatValue("-1.012", 37, 43));
    test_next_token(&mut lexer, FloatValue("-0.101", 44, 50));
    test_next_token(&mut lexer, FloatValue("1.0e2", 51, 56));
    test_next_token(&mut lexer, FloatValue("-1.0E2", 57, 63));
    test_next_token(&mut lexer, FloatValue("0.00e-002", 64, 73));
    test_next_token(&mut lexer, FloatValue("-0.00E+002", 74, 84));
    test_next_token(&mut lexer, FloatValue("9.1E+0", 85, 91));
    test_next_token(&mut lexer, Eof(91));
    assert_eq!(None, lexer.next());
  }

  #[test]
  fn test_symbol() {
    let mut lexer = Lexer::new("@ !  :$ =    [  {   (|] } )      ...");
    test_next_token(&mut lexer, Punctuator(At, 0));
    test_next_token(&mut lexer, Punctuator(Bang, 2));
    test_next_token(&mut lexer, Punctuator(Colon, 5));
    test_next_token(&mut lexer, Punctuator(Dollar, 6));
    test_next_token(&mut lexer, Punctuator(Equals, 8));
    test_next_token(&mut lexer, Punctuator(LeftBracket, 13));
    test_next_token(&mut lexer, Punctuator(LeftBrace, 16));
    test_next_token(&mut lexer, Punctuator(LeftParen, 20));
    test_next_token(&mut lexer, Punctuator(Pipe, 21));
    test_next_token(&mut lexer, Punctuator(RightBracket, 22));
    test_next_token(&mut lexer, Punctuator(RightBrace, 24));
    test_next_token(&mut lexer, Punctuator(RightParen, 26));
    test_next_token(&mut lexer, Punctuator(Spread(33), 35));
    test_next_token(&mut lexer, Eof(36));
    assert_eq!(None, lexer.next());
  }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

/// Figure 11.14 Using reader–writer locks
///
/// - VecDeque resembles the doubled linked list best which also needs
///   a removal in the middle
///
/// Status: main() hangs on OSX, works on Linux. Couldn't find out why
/// there's something wrong with the _init function, upon first lock attempt (a1)
/// it always blocks as if the init funciton would already lock the resource.

extern crate libc;
extern crate apue;
extern crate errno;

use libc::{pthread_rwlock_t, pthread_t, PTHREAD_RWLOCK_INITIALIZER};
use apue::my_libc::{pthread_rwlock_init};
use libc::{pthread_rwlock_wrlock, pthread_rwlock_unlock, pthread_rwlock_rdlock};

use std::collections::VecDeque;
use std::ptr::null;

struct Queue {
    q: VecDeque<Job>,
    lock: pthread_rwlock_t,
}

struct Job {
    thread_id: pthread_t,
}

// only equals if pointers are equal
impl PartialEq for Job {
    fn eq(&self, other: &Job) -> bool {
        &self == &other
    }
}

impl Queue {
    // queue_init
    fn new() -> Queue {
        let mut q = Queue{q: VecDeque::new(), lock: PTHREAD_RWLOCK_INITIALIZER};
        println!("n1");
        unsafe{
            if pthread_rwlock_init(&mut q.lock, null()) != 0 {
                println!("fail!");
            }
        };
        println!("n2");
        q
    }

    fn job_insert(&mut self, job:Job) {
        unsafe{pthread_rwlock_wrlock(&mut self.lock)};
        self.q.push_front(job);
        unsafe{pthread_rwlock_unlock(&mut self.lock)};
    }

    fn job_append(&mut self, job:Job) {
        println!("a1");
        unsafe{pthread_rwlock_wrlock(&mut self.lock)};
        println!("a2");
        self.q.push_back(job);
        unsafe{pthread_rwlock_unlock(&mut self.lock)};
        println!("a3");
    }

    fn job_remove(&mut self, job:&Job) {
        unsafe{pthread_rwlock_wrlock(&mut self.lock)};
        if Some(job) == self.q.front() {
            self.q.pop_front();
        } else if Some(job) == self.q.back() {
            self.q.pop_back();
        } else {
            self.q.retain(|ref x| *x != job);
        }
    }

    fn job_find(&mut self, id:pthread_t) -> Option<&Job> {
        println!("f1");
        if unsafe{pthread_rwlock_rdlock(&mut self.lock)} != 0 {
            return None;
        }
        println!("f2");
        let res = if let Some(pos) = self.q.iter().position(|ref x| x.thread_id == id) {
            self.q.get(pos)
        } else {
            None
        };
        unsafe{pthread_rwlock_unlock(&mut self.lock)};
        res
    }
}

fn main() {
    let mut q = Queue::new();
    q.job_append(Job{thread_id:1});
    assert!(q.job_find(1).expect("expected to find 1").thread_id == 1);
}<commit_msg>well, I forgot an unlock..<commit_after>#![allow(dead_code)]

/// Figure 11.14 Using reader–writer locks
///
/// - VecDeque resembles the doubled linked list best which also needs
///   a removal in the middle
///
/// Status: main() hangs on OSX, works on Linux. Couldn't find out why
/// there's something wrong with the _init function, upon first lock attempt (a1)
/// it always blocks as if the init funciton would already lock the resource.

extern crate libc;
extern crate apue;
extern crate errno;

use libc::{pthread_rwlock_t, pthread_t, PTHREAD_RWLOCK_INITIALIZER};
use apue::my_libc::{pthread_rwlock_init};
use libc::{pthread_rwlock_wrlock, pthread_rwlock_unlock, pthread_rwlock_rdlock};

use std::collections::VecDeque;
use std::ptr::null;

struct Queue {
    q: VecDeque<Job>,
    lock: pthread_rwlock_t,
}

struct Job {
    thread_id: pthread_t,
}

// only equals if pointers are equal
impl PartialEq for Job {
    fn eq(&self, other: &Job) -> bool {
        &self == &other
    }
}

impl Queue {
    // queue_init
    fn new() -> Queue {
        let mut q = Queue{q: VecDeque::new(), lock: PTHREAD_RWLOCK_INITIALIZER};
        println!("n1");
        unsafe{
            if pthread_rwlock_init(&mut q.lock, null()) != 0 {
                println!("fail!");
            }
        };
        println!("n2");
        q
    }

    fn job_insert(&mut self, job:Job) {
        unsafe{pthread_rwlock_wrlock(&mut self.lock)};
        self.q.push_front(job);
        unsafe{pthread_rwlock_unlock(&mut self.lock)};
    }

    fn job_append(&mut self, job:Job) {
        println!("a1");
        unsafe{pthread_rwlock_wrlock(&mut self.lock)};
        println!("a2");
        self.q.push_back(job);
        unsafe{pthread_rwlock_unlock(&mut self.lock)};
        println!("a3");
    }

    fn job_remove(&mut self, job:&Job) {
        unsafe{pthread_rwlock_wrlock(&mut self.lock)};
        if Some(job) == self.q.front() {
            self.q.pop_front();
        } else if Some(job) == self.q.back() {
            self.q.pop_back();
        } else {
            self.q.retain(|ref x| *x != job);
        }
        unsafe{pthread_rwlock_unlock(&mut self.lock)};
    }

    fn job_find(&mut self, id:pthread_t) -> Option<&Job> {
        println!("f1");
        if unsafe{pthread_rwlock_rdlock(&mut self.lock)} != 0 {
            return None;
        }
        println!("f2");
        let res = if let Some(pos) = self.q.iter().position(|ref x| x.thread_id == id) {
            self.q.get(pos)
        } else {
            None
        };
        unsafe{pthread_rwlock_unlock(&mut self.lock)};
        res
    }
}

fn main() {
    let mut q = Queue::new();
    q.job_append(Job{thread_id:1});
    assert!(q.job_find(1).expect("expected to find 1").thread_id == 1);
}<|endoftext|>