<commit_before>#![allow(unused)]

extern crate websocket;
extern crate futures;
extern crate tokio_core;
#[macro_use]
extern crate tokio_io;
extern crate tokio_stdin_stdout;

#[cfg(unix)]
extern crate tokio_file_unix;
#[cfg(unix)]
extern crate tokio_signal;

use std::thread;
use std::io::stdin;
use tokio_core::reactor::Core;
use futures::future::Future;
use futures::sink::Sink;
use futures::stream::Stream;
use futures::sync::mpsc;
use websocket::result::WebSocketError;
use websocket::{ClientBuilder, OwnedMessage};
use tokio_io::{AsyncRead,AsyncWrite};
use std::io::{Read,Write};
use std::io::Result as IoResult;

use websocket::stream::async::Stream as WsStream;
use futures::Async::{Ready, NotReady};

use tokio_io::io::copy;

use tokio_io::codec::FramedRead;
use std::fs::File;

#[cfg(unix)]
use tokio_file_unix::{File as UnixFile, StdFile};
#[cfg(unix)]
use std::os::unix::io::FromRawFd;

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

type WaitingForImplTraitFeature0 = tokio_io::codec::Framed<std::boxed::Box<websocket::async::Stream + std::marker::Send>, websocket::async::MessageCodec<websocket::OwnedMessage>>;
type WaitingForImplTraitFeature1 = futures::stream::SplitStream<WaitingForImplTraitFeature0>;
type WaitingForImplTraitFeature2 = futures::stream::SplitSink<WaitingForImplTraitFeature0>;

fn wouldblock<T>() -> std::io::Result<T> {
    Err(std::io::Error::new(std::io::ErrorKind::WouldBlock, ""))
}
fn brokenpipe<T>() -> std::io::Result<T> {
    Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, ""))
}
fn io_other_error<E : std::error::Error + Send + Sync + 'static>(e:E) -> std::io::Error {
    std::io::Error::new(std::io::ErrorKind::Other,e)
}

mod my_copy;

struct WsReadWrapper {
    s: WaitingForImplTraitFeature1,
    debt: Option<Vec<u8>>,
}

impl AsyncRead for WsReadWrapper {

}

impl WsReadWrapper {
    fn process_message(&mut self, buf: &mut [u8], buf_in: &[u8]) -> std::result::Result<usize, std::io::Error> {
        let l = buf_in.len().min(buf.len());
        buf[..l].copy_from_slice(&buf_in[..l]);

        if l < buf_in.len() {
            self.debt = Some(buf_in[l..].to_vec());
        }

        Ok(l)
    }
}

impl Read for WsReadWrapper {
    fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
        if let Some(debt) = self.debt.take() {
            return self.process_message(buf, debt.as_slice())
        }
        match self.s.poll().map_err(io_other_error)? {
            Ready(Some(OwnedMessage::Close(_))) => {
                brokenpipe()
            },
            Ready(None) => {
                brokenpipe()
            }
            Ready(Some(OwnedMessage::Ping(_))) => {
                Ok(0)
                // TODO
            }
            Ready(Some(OwnedMessage::Pong(_))) => {
                Ok(0)
            }
            Ready(Some(OwnedMessage::Text(x))) => {
                self.process_message(buf, x.as_str().as_bytes())
            }
            Ready(Some(OwnedMessage::Binary(x))) => {
                self.process_message(buf, x.as_slice())
            }
            NotReady => {
                wouldblock()
            }
        }
    }
}

struct WsWriteWrapper(WaitingForImplTraitFeature2);

impl AsyncWrite for WsWriteWrapper {
    fn shutdown(&mut self) -> futures::Poll<(),std::io::Error> {
        // TODO: check this
        Ok(Ready(()))
    }
}

impl Write for WsWriteWrapper {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        let om = OwnedMessage::Binary(buf.to_vec());
        match self.0.start_send(om).map_err(io_other_error)? {
            futures::AsyncSink::NotReady(_) => {
                wouldblock()
            },
            futures::AsyncSink::Ready => {
                Ok(buf.len())
            }
        }
    }
    fn flush(&mut self) -> IoResult<()> {
        match self.0.poll_complete().map_err(io_other_error)? {
            NotReady => {
                wouldblock()
            },
            Ready(()) => {
                Ok(())
            }
        }
    }

}

fn run() -> Result<()> {
    let peeraddr = std::env::args().nth(1).ok_or("no arg")?;

    println!("Connecting to {}", peeraddr);
    let mut core = Core::new()?;
    let handle = core.handle();

    let si;
    let so;

    #[cfg(any(not(unix),feature="no_unix_stdio"))]
    {
        si = tokio_stdin_stdout::stdin(0);
        so = tokio_stdin_stdout::stdout(0);
    }

    #[cfg(all(unix,not(feature="no_unix_stdio")))]
    {
        let stdin  = UnixFile::new_nb(std::io::stdin())?;
        let stdout = UnixFile::new_nb(std::io::stdout())?;

        si = stdin.into_reader(&handle)?;
        so = stdout.into_io(&handle)?;

        let ctrl_c = tokio_signal::ctrl_c(&handle).flatten_stream();
        let prog = ctrl_c.for_each(|()| {
            UnixFile::raw_new(std::io::stdin()).set_nonblocking(false);
            UnixFile::raw_new(std::io::stdout()).set_nonblocking(false);
            ::std::process::exit(0);
            Ok(())
        });
        handle.spawn(prog.map_err(|_|()));
    }

    let runner = ClientBuilder::new(peeraddr.as_ref())?
        .add_protocol("rust-websocket")
        .async_connect(None, &core.handle())
        .and_then(|(duplex, _)| {
            let (sink, stream) = duplex.split();

            let ws_str = WsReadWrapper {
                s: stream,
                debt: None,
            };
            let ws_sin = WsWriteWrapper(sink);

            handle.spawn(my_copy::copy(si, ws_sin).map(|_|()).map_err(|_|()));
            my_copy::copy(ws_str, so).map_err(|e| WebSocketError::IoError(e))
        });
    core.run(runner)?;
    Ok(())
}

fn main() {
    let r = run();

    #[cfg(all(unix,not(feature="no_unix_stdio")))]
    {
        UnixFile::raw_new(std::io::stdin()).set_nonblocking(false);
        UnixFile::raw_new(std::io::stdout()).set_nonblocking(false);
    }

    if let Err(e) = r {
        eprintln!("websocat: {}", e);
        ::std::process::exit(1);
    }
}
<commit_msg>Implement, but not test replying to pings<commit_after>#![allow(unused)]

extern crate websocket;
extern crate futures;
extern crate tokio_core;
#[macro_use]
extern crate tokio_io;
extern crate tokio_stdin_stdout;

#[cfg(unix)]
extern crate tokio_file_unix;
#[cfg(unix)]
extern crate tokio_signal;

use std::thread;
use std::io::stdin;
use tokio_core::reactor::Core;
use futures::future::Future;
use futures::sink::Sink;
use futures::stream::Stream;
use futures::sync::mpsc;
use websocket::result::WebSocketError;
use websocket::{ClientBuilder, OwnedMessage};
use tokio_io::{AsyncRead,AsyncWrite};
use std::io::{Read,Write};
use std::io::Result as IoResult;

use std::rc::Rc;
use std::cell::RefCell;

use websocket::stream::async::Stream as WsStream;
use futures::Async::{Ready, NotReady};

use tokio_io::io::copy;

use tokio_io::codec::FramedRead;
use std::fs::File;

#[cfg(unix)]
use tokio_file_unix::{File as UnixFile, StdFile};
#[cfg(unix)]
use std::os::unix::io::FromRawFd;

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

type WaitingForImplTraitFeature0 = tokio_io::codec::Framed<std::boxed::Box<websocket::async::Stream + std::marker::Send>, websocket::async::MessageCodec<websocket::OwnedMessage>>;
type WaitingForImplTraitFeature2 = futures::stream::SplitSink<WaitingForImplTraitFeature0>;
type WsSource = futures::stream::SplitStream<WaitingForImplTraitFeature0>;
type MultiProducerWsSink = Rc<RefCell<WaitingForImplTraitFeature2>>;

fn wouldblock<T>() -> std::io::Result<T> {
    Err(std::io::Error::new(std::io::ErrorKind::WouldBlock, ""))
}
fn brokenpipe<T>() -> std::io::Result<T> {
    Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, ""))
}
fn io_other_error<E : std::error::Error + Send + Sync + 'static>(e:E) -> std::io::Error {
    std::io::Error::new(std::io::ErrorKind::Other,e)
}

mod my_copy;

struct WsReadWrapper {
    s: WsSource,
    pingreply : MultiProducerWsSink,
    debt: Option<Vec<u8>>,
}

impl AsyncRead for WsReadWrapper {

}

impl WsReadWrapper {
    fn process_message(&mut self, buf: &mut [u8], buf_in: &[u8]) -> std::result::Result<usize, std::io::Error> {
        let l = buf_in.len().min(buf.len());
        buf[..l].copy_from_slice(&buf_in[..l]);

        if l < buf_in.len() {
            self.debt = Some(buf_in[l..].to_vec());
        }

        Ok(l)
    }
}

impl Read for WsReadWrapper {
    fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
        if let Some(debt) = self.debt.take() {
            return self.process_message(buf, debt.as_slice())
        }
        match self.s.poll().map_err(io_other_error)? {
            Ready(Some(OwnedMessage::Close(_))) => {
                brokenpipe()
            },
            Ready(None) => {
                brokenpipe()
            }
            Ready(Some(OwnedMessage::Ping(x))) => {
                let om = OwnedMessage::Pong(x);
                let mut sink = self.pingreply.borrow_mut();
                let mut proceed = false;
                // I'm not sure this is safe enough, RefCell-wise and Futures-wise
                // And pings and their replies are not tested yet
                match sink.start_send(om).map_err(io_other_error)? {
                    futures::AsyncSink::NotReady(_) => {
                        // drop the ping
                    },
                    futures::AsyncSink::Ready => {
                        proceed = true;
                    }
                }
                if proceed {
                    let _ = sink.poll_complete().map_err(io_other_error)?;
                }

                Ok(0)
            }
            Ready(Some(OwnedMessage::Pong(_))) => {
                Ok(0)
            }
            Ready(Some(OwnedMessage::Text(x))) => {
                self.process_message(buf, x.as_str().as_bytes())
            }
            Ready(Some(OwnedMessage::Binary(x))) => {
                self.process_message(buf, x.as_slice())
            }
            NotReady => {
                wouldblock()
            }
        }
    }
}

struct WsWriteWrapper(MultiProducerWsSink);

impl AsyncWrite for WsWriteWrapper {
    fn shutdown(&mut self) -> futures::Poll<(),std::io::Error> {
        // TODO: check this
        Ok(Ready(()))
    }
}

impl Write for WsWriteWrapper {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        let om = OwnedMessage::Binary(buf.to_vec());
        match self.0.borrow_mut().start_send(om).map_err(io_other_error)? {
            futures::AsyncSink::NotReady(_) => {
                wouldblock()
            },
            futures::AsyncSink::Ready => {
                Ok(buf.len())
            }
        }
    }
    fn flush(&mut self) -> IoResult<()> {
        match self.0.borrow_mut().poll_complete().map_err(io_other_error)? {
            NotReady => {
                wouldblock()
            },
            Ready(()) => {
                Ok(())
            }
        }
    }

}

fn run() -> Result<()> {
    let peeraddr = std::env::args().nth(1).ok_or("no arg")?;

    println!("Connecting to {}", peeraddr);
    let mut core = Core::new()?;
    let handle = core.handle();

    let si;
    let so;

    #[cfg(any(not(unix),feature="no_unix_stdio"))]
    {
        si = tokio_stdin_stdout::stdin(0);
        so = tokio_stdin_stdout::stdout(0);
    }

    #[cfg(all(unix,not(feature="no_unix_stdio")))]
    {
        let stdin  = UnixFile::new_nb(std::io::stdin())?;
        let stdout = UnixFile::new_nb(std::io::stdout())?;

        si = stdin.into_reader(&handle)?;
        so = stdout.into_io(&handle)?;

        let ctrl_c = tokio_signal::ctrl_c(&handle).flatten_stream();
        let prog = ctrl_c.for_each(|()| {
            UnixFile::raw_new(std::io::stdin()).set_nonblocking(false);
            UnixFile::raw_new(std::io::stdout()).set_nonblocking(false);
            ::std::process::exit(0);
            Ok(())
        });
        handle.spawn(prog.map_err(|_|()));
    }

    let runner = ClientBuilder::new(peeraddr.as_ref())?
        .add_protocol("rust-websocket")
        .async_connect(None, &core.handle())
        .and_then(|(duplex, _)| {
            let (sink, stream) = duplex.split();
            let mpsink = Rc::new(RefCell::new(sink));

            let ws_str = WsReadWrapper {
                s: stream,
                pingreply: mpsink.clone(),
                debt: None,
            };
            let ws_sin = WsWriteWrapper(mpsink);

            handle.spawn(my_copy::copy(si, ws_sin).map(|_|()).map_err(|_|()));
            my_copy::copy(ws_str, so).map_err(|e| WebSocketError::IoError(e))
        });
    core.run(runner)?;
    Ok(())
}

fn main() {
    let r = run();

    #[cfg(all(unix,not(feature="no_unix_stdio")))]
    {
        UnixFile::raw_new(std::io::stdin()).set_nonblocking(false);
        UnixFile::raw_new(std::io::stdout()).set_nonblocking(false);
    }

    if let Err(e) = r {
        eprintln!("websocat: {}", e);
        ::std::process::exit(1);
    }
}
<|endoftext|>


<commit_before>mod error;

// My IP address providers
mod myip;

// DNS providers
mod dns;

// Configuration
mod config;

mod gandi;

#[macro_use]
extern crate clap;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate xmlrpc;
extern crate rustc_serialize;
extern crate regex;
extern crate ip;
extern crate hyper;

use clap::{Arg, App};
use std::env;

use config::Config;
use dns::DNSProvider;
use dns::DNSProviderFactory;
use dns::Record;
use error::Result;
use myip::GetMyIpAddr;
use myip::IpProvider;
use std::process;

fn main() {
    let config = build_config();

    match main_with_errors(&config) {
        Ok(_) => info!("Process ends with success"),
        Err(err) => {
            error!("Process failed with result: {}", err);
            process::exit(-1);
        }
    }
}

fn build_config() -> Config {
    let matches = App::new("gdu")
        .version(&crate_version!()[..])
        .author("Damien Lecan <dev@dlecan.com>")
        .about("Generic DNS update, useful to update your dynamic IP address into your DNS provider zone file, e.g. Gandi or Go Daddy.\n\
            IP address can be read from several HTTP providers or from stdin.\n\
            Only Gandi DNS provider is implemented in this version.")
        .args_from_usage(
            "-a --apikey=[apikey] 'Your API key provided by Gandi'
            -d --domain=[domain] 'The domain name whose active zonefile will be updated, e.g. \"domain.com\"'
            -n --dry-run 'Dry run, don't really update Gandi zone file'
            -f --force 'Force new zonefile creation even if IP address isn\'t modified'
            -r --record-name=[record_name] 'Name of the A record to update or create (without domain)'
            [verbose]... -v 'Verbose mode'")
        .arg(Arg::with_name("ip_provider")
            .help("IP address provider to use to get your own IP address.\n                                       \
                Available values for <ip-provider>:\n                                        \
                 opendns       : OpenDNS\n                                        \
                 -             : read IP address from stdin\n                                        \
                 sfrlaboxfibre : French 'SFR Labox Fibre' subscribers")
            .short("i")
            .long("ip-provider")
            .takes_value(true)
            .multiple(false))
        .get_matches();

    // Init logging to DEBUG only if user requires it
    match matches.occurrences_of("verbose") {
        0 => env::set_var("RUST_LOG", "INFO"),
        1 => {
            println!("Verbose mode");
            env::set_var("RUST_LOG", "DEBUG");
        }
        2 | _=> {
            println!("More verbose mode");
            env::set_var("RUST_LOG", "TRACE");
        }
    }
    env_logger::init().unwrap();

    let apikey = matches.value_of("apikey").unwrap();
    debug!("Using apikey: {}", apikey);

    let domain = matches.value_of("domain").unwrap();
    debug!("Using domain: {}", domain);

    let record_name = matches.value_of("record_name").unwrap();
    debug!("Using record name: {}", record_name);

    let dry_run = matches.is_present("dry-run");
    debug!("Dry run: {}", dry_run);

    let force = matches.is_present("force");
    debug!("Force: {}", force);

    let ip_provider = value_t_or_exit!(matches.value_of("ip_provider"), IpProvider);
    debug!("IP address provider: {:?}", ip_provider);

    Config {
        apikey: apikey.to_owned(),
        domain: domain.to_owned(),
        record_name: record_name.to_owned(),
        force: force,
        ip_provider: ip_provider,
    }
}

fn main_with_errors(config: &Config) -> Result<()> {

    let my_ip = try!(config.ip_provider.get_my_ip_addr());

    info!("My IP address: {}", my_ip);

    let mut dns_provider = dns::DNSProviderFactory::build(config);

    match my_ip {
        ip::IpAddr::V6(_)
            if !dns_provider.handle_ipv6_addr() => panic!("You cannot use IP v6 addresses with the selected DNS provider"),
        _ => (),
    }

    let record = Record::new(&config.record_name, &my_ip);

    try!(dns_provider.init(&config.domain));

    let maybe_checked = try!(dns_provider.is_record_already_declared(&record));

    match maybe_checked {
        Some(ip_addr) => {
            debug!("Record already declared, with IP address: {}", &ip_addr);

            if !config.force && (&ip_addr == &my_ip) {
                info!("IP address not modified, no record to update");
                Ok(())
            } else {
                info!("Update record '{:?}' with IP address '{}'", &record, &my_ip);
                Ok(try!(dns_provider.update_record(&record, &my_ip)))
            }
        }
        None => Ok(try!(dns_provider.create_record(&record, &my_ip)))
    }
}
<commit_msg>(main) Better CLI description<commit_after>mod error;

// My IP address providers
mod myip;

// DNS providers
mod dns;

// Configuration
mod config;

mod gandi;

#[macro_use]
extern crate clap;

#[macro_use]
extern crate log;
extern crate env_logger;

extern crate xmlrpc;
extern crate rustc_serialize;
extern crate regex;
extern crate ip;
extern crate hyper;

use clap::{Arg, App};
use std::env;

use config::Config;
use dns::DNSProvider;
use dns::DNSProviderFactory;
use dns::Record;
use error::Result;
use myip::GetMyIpAddr;
use myip::IpProvider;
use std::process;

fn main() {
    let config = build_config();

    match main_with_errors(&config) {
        Ok(_) => info!("Process ends with success"),
        Err(err) => {
            error!("Process failed with result: {}", err);
            process::exit(-1);
        }
    }
}

fn build_config() -> Config {
    let matches = App::new("gdu")
        .version(&crate_version!()[..])
        .author("Damien Lecan <dev@dlecan.com>")
        .about("Generic DNS update, useful to update your dynamic IP address into your DNS provider zone file, e.g. Gandi or Go Daddy.\n\
            GDU detects if your ip address is IPv4 or v6 and and will create a record with type 'A' or 'AAAA' accordingly.\n\n\
            IP address can be read from several HTTP providers or from stdin.\n\
            Only Gandi DNS provider is implemented in this version.")
        .args_from_usage(
            "-a --apikey=[apikey] 'Your API key provided by Gandi'
            -d --domain=[domain] 'The domain name whose active zonefile will be updated, e.g. \"domain.com\"'
            -n --dry-run 'Dry run, don't really update Gandi zone file'
            -f --force 'Force new zonefile creation even if IP address isn\'t modified'
            -r --record-name=[record_name] 'Name of the A or AAAA record to update or create (without domain)'
            [verbose]... -v 'Verbose mode'")
        .arg(Arg::with_name("ip_provider")
            .help("IP address provider to use to get your own IP address.\n                                       \
                Available values for <ip-provider>:\n                                        \
                 opendns       : OpenDNS\n                                        \
                 -             : read IP address from stdin\n                                        \
                 sfrlaboxfibre : French 'SFR Labox Fibre' subscribers")
            .short("i")
            .long("ip-provider")
            .takes_value(true)
            .multiple(false))
        .get_matches();

    // Init logging to DEBUG only if user requires it
    match matches.occurrences_of("verbose") {
        0 => env::set_var("RUST_LOG", "INFO"),
        1 => {
            println!("Verbose mode");
            env::set_var("RUST_LOG", "DEBUG");
        }
        2 | _=> {
            println!("More verbose mode");
            env::set_var("RUST_LOG", "TRACE");
        }
    }
    env_logger::init().unwrap();

    let apikey = matches.value_of("apikey").unwrap();
    debug!("Using apikey: {}", apikey);

    let domain = matches.value_of("domain").unwrap();
    debug!("Using domain: {}", domain);

    let record_name = matches.value_of("record_name").unwrap();
    debug!("Using record name: {}", record_name);

    let dry_run = matches.is_present("dry-run");
    debug!("Dry run: {}", dry_run);

    let force = matches.is_present("force");
    debug!("Force: {}", force);

    let ip_provider = value_t_or_exit!(matches.value_of("ip_provider"), IpProvider);
    debug!("IP address provider: {:?}", ip_provider);

    Config {
        apikey: apikey.to_owned(),
        domain: domain.to_owned(),
        record_name: record_name.to_owned(),
        force: force,
        ip_provider: ip_provider,
    }
}

fn main_with_errors(config: &Config) -> Result<()> {

    let my_ip = try!(config.ip_provider.get_my_ip_addr());

    info!("My IP address: {}", my_ip);

    let mut dns_provider = dns::DNSProviderFactory::build(config);

    match my_ip {
        ip::IpAddr::V6(_)
            if !dns_provider.handle_ipv6_addr() => panic!("You cannot use IP v6 addresses with the selected DNS provider"),
        _ => (),
    }

    let record = Record::new(&config.record_name, &my_ip);

    try!(dns_provider.init(&config.domain));

    let maybe_checked = try!(dns_provider.is_record_already_declared(&record));

    match maybe_checked {
        Some(ip_addr) => {
            debug!("Record already declared, with IP address: {}", &ip_addr);

            if !config.force && (&ip_addr == &my_ip) {
                info!("IP address not modified, no record to update");
                Ok(())
            } else {
                info!("Update record '{:?}' with IP address '{}'", &record, &my_ip);
                Ok(try!(dns_provider.update_record(&record, &my_ip)))
            }
        }
        None => Ok(try!(dns_provider.create_record(&record, &my_ip)))
    }
}
<|endoftext|>


<commit_before>extern crate regex;

fn main() {
	// Execute script from the command line
}

fn parse(code: &str) -> Vec<&str> {
	// code.to_string()
	let leftParenRe = regex::Regex::new(r"\s*\(\s*").unwrap();
	let rightParenRe = regex::Regex::new(r"\s*\)\s*").unwrap();
	let partialParsedCode = leftParenRe.replace_all(&code, " ( ");
	let parsedCode = rightParenRe.replace_all(&partialParsedCode," ) ");
	// let parsedCode = code.replace(" (", "(").replace("( ", "(").replace("(", " ( ").replace()
	parsedCode.as_slice().split(" ").collect()
}

fn tokenize() {

}

fn read_from_tokens() {

}

#[test]
fn it_works() {
	let input = "(begin (define r 10) (* pi (* r r)))";
	let parsedCode = parse(input);
	println!("{}", parsedCode);
}
<commit_msg>reformatting<commit_after>extern crate regex;

fn main() {
	// Execute script from the command line
}

fn parse(code: &str) -> Vec<&str> {
	// code.to_string()

	// let parsedCode = code.replace(" (", "(").replace("( ", "(").replace("(", " ( ").replace()
	parsedCode.as_slice().split(" ").collect()
}

fn format_code(code: &str) -> &str {
	let leftParenRe = regex::Regex::new(r"\s*\(\s*").unwrap();
	let rightParenRe = regex::Regex::new(r"\s*\)\s*").unwrap();
	let partialParsedCode = leftParenRe.replace_all(&code, " ( ");
	(rightParenRe.replace_all(&partialParsedCode," ) ")).as_slice()
}

fn tokenize() {

}

fn read_from_tokens() {

}

#[test]
fn it_works() {
	let input = "(begin (define r 10) (* pi (* r r)))";
	let parsedCode = parse(input);
	println!("{}", parsedCode);
}
<|endoftext|>


<commit_before>extern crate ast;

use ast::Evaluate;

use ast::Program::{If,Command};
use ast::Condition::Less;
use ast::Expression::{Sensor,Multiply,Constant};

fn main() {
	let program: ast::Program = If(
			Less(
			Box::new(Sensor(ast::Sensor::Vx)),
			Box::new(Multiply(
				Box::new(Constant(2.0)),
				Box::new(Constant(3.0))
			))
		),
		Box::new(Command(ast::Command::Left)),
		Box::new(Command(ast::Command::Right))
	);

	let data: ast::SensorData = ast::SensorData { x: 37.0, y: 51.0, vx: 6.0, vy: 0.0, o: 0.0, w: 0.0 };

	let command = program.evaluate(data);

	let message = match **command {
		ast::Command::Skip  => "skip",
		ast::Command::Left  => "turnLeft",
		ast::Command::Right => "turnRight",
		ast::Command::Up    => "thruster",
	};

	println!("action is {}", message);
}
<commit_msg>Introduce macros for program construction<commit_after>extern crate ast;

use ast::Evaluate;

use ast::Program::{If,Command};
use ast::Condition::{True,False,Not,Or,And,Less,LessEqual,Equal,GreaterEqual,Greater};
use ast::Expression::{Sensor,Multiply,Constant};

macro_rules! iff {
	($condition: expr, $left: expr, $right: expr) => (If($condition, Box::new($left), Box::new($right)))
}

macro_rules! T {
	() => (True)
}

macro_rules! F {
	() => (False)
}

macro_rules! not {
	($condition: expr) => (Not($condition))
}

macro_rules! or {
	($left: expr, $right: expr) => (Or(Box::new($left), Box::new($right)))
}

macro_rules! and {
	($left: expr, $right: expr) => (And(Box::new($left), Box::new($right)))
}

macro_rules! less {
	($left: expr, $right: expr) => (Less(Box::new($left), Box::new($right)))
}

macro_rules! less_equal {
	($left: expr, $right: expr) => (LessEqual(Box::new($left), Box::new($right)))
}

macro_rules! equal {
	($left: expr, $right: expr) => (Equal(Box::new($left), Box::new($right)))
}

macro_rules! greater_equal {
	($left: expr, $right: expr) => (GreaterEqual(Box::new($left), Box::new($right)))
}
macro_rules! greater {
	($left: expr, $right: expr) => (Greater(Box::new($left), Box::new($right)))
}

macro_rules! constant {
	($value: expr) => (Constant($value))
}

macro_rules! x {
	() => (Sensor(ast::Sensor::X))
}

macro_rules! y {
	() => (Sensor(ast::Sensor::Y))
}

macro_rules! vx {
	() => (Sensor(ast::Sensor::Vx))
}

macro_rules! vy {
	() => (Sensor(ast::Sensor::Vy))
}

macro_rules! o {
	() => (Sensor(ast::Sensor::O))
}

macro_rules! w {
	() => (Sensor(ast::Sensor::ws))
}

macro_rules! plus {
	($left: expr, $right: expr) => (Plus(Box::new($left), Box::new($right)))
}

macro_rules! minus {
	($left: expr, $right: expr) => (Minus(Box::new($left), Box::new($right)))
}

macro_rules! multiply {
	($left: expr, $right: expr) => (Multiply(Box::new($left), Box::new($right)))
}

macro_rules! divide {
	($left: expr, $right: expr) => (Divide(Box::new($left), Box::new($right)))
}

macro_rules! skip {
	() => (Command(ast::Command::Right));
}

macro_rules! left {
	() => (Command(ast::Command::Left))
}

macro_rules! right {
	() => (Command(ast::Command::Right))
}

macro_rules! up {
	() => (Command(ast::Command::Up))
}

fn main() {
	let program: ast::Program = iff!(less!(vx!(), multiply!(constant!(2.0), constant!(3.0))), left!(), right!());

	let data: ast::SensorData = ast::SensorData { x: 37.0, y: 51.0, vx: 1.0, vy: 0.0, o: 0.0, w: 0.0 };

	let command = program.evaluate(data);

	let message = match **command {
		ast::Command::Skip  => "skip",
		ast::Command::Left  => "turnLeft",
		ast::Command::Right => "turnRight",
		ast::Command::Up    => "thruster",
	};

	println!("action is {}", message);
}
<|endoftext|>


<commit_before>use std::net::UdpSocket;
use std::str;

struct Question {
    name: Vec<String>,
    rrtype: u16,
    class: u16,
}

struct Message {
    id: u16, // 2 bytes
    query_response: u16, // 1 bit
    operation_code: u16, // 4 bits
    authoritative_answer: u16, // 1 bit
    truncation_flag: u16, // 1 bit
    recursion_desired: u16, // 1 bit
    recursion_available: u16, // 1 bit
    unused: u16, // 3 bits
    error_code: u16, // 4 bits
    question_count: u16, // 2 bytes
    answer_count: u16, // 2 bytes
    ns_count: u16, // 2 bytes
    ar_count: u16, // 2 bytes

    questions: Vec<Question>,
}

fn unpack(buffer: &[u8]) -> Message {
    let id: u16 = (buffer[0] as u16) << 8 | buffer[1] as u16;
    let body: u16 = (buffer[2] as u16) << 8 | buffer[3] as u16;
    let question_count: u16 = (buffer[4] as u16) << 8 | buffer[5] as u16;
    let answer_count: u16 = (buffer[6] as u16) << 8 | buffer[7] as u16;
    let ns_count: u16 = (buffer[8] as u16) << 8 | buffer[9] as u16;
    let ar_count: u16 = (buffer[10] as u16) << 8 | buffer[11] as u16;

    let mut offset: usize = 12;

    let mut questions = Vec::with_capacity(question_count as usize);

    for _ in 0..question_count {
        let mut name = Vec::new();

        loop {
            let size: usize = buffer[offset] as usize;
            offset += 1;

            if size == 0 {
                break;
            }

            name.push(str::from_utf8(&buffer[offset .. offset + size]).unwrap().to_string());
            offset += size;
        }

        let rrtype: u16 = (buffer[offset] as u16) << 8 | buffer[offset+1] as u16;
        offset += 2;

        let class: u16 = (buffer[offset] as u16) << 8 | buffer[offset+1] as u16;
        offset += 2;

        questions.push(Question{
            name: name,
            rrtype: rrtype,
            class: class,
        })
    }

    Message {
        id: id,
        query_response: (body & (1 << 15)) >> 15,
        operation_code: (body & (15 << 11)) >> 11,
        authoritative_answer: (body & (1 >> 10)) >> 10,
        truncation_flag: (body & (1 >> 9)) >> 9,
        recursion_desired: (body & (1 >> 8)) >> 8,
        recursion_available: (body & (1 >> 7)) >> 7,
        unused: (body & (7 << 4)) >> 4,
        error_code: (body & (15 << 0)) >> 0,
        question_count: question_count,
        answer_count: answer_count,
        ns_count: ns_count,
        ar_count: ar_count,
        questions: questions,
    }
}

fn pack(message: &Message) -> Vec<u8> {
    let mut buffer: Vec<u8> = Vec::new();

    buffer.push((message.id >> 8) as u8);
    buffer.push(message.id as u8);

    let mut body: u16 = 0;

    body = body | message.query_response << 15;
    body = body | message.operation_code << 11;
    body = body | message.authoritative_answer << 10;
    body = body | message.truncation_flag << 9;
    body = body | message.recursion_desired << 8;
    body = body | message.recursion_available << 7;
    body = body | message.unused << 4;
    body = body | message.error_code;

    buffer.push((body >> 8) as u8);
    buffer.push(body as u8);

    buffer.push((message.question_count >> 8) as u8);
    buffer.push(message.question_count as u8);

    buffer.push((message.answer_count >> 8) as u8);
    buffer.push(message.answer_count as u8);

    buffer.push((message.ns_count >> 8) as u8);
    buffer.push(message.ns_count as u8);

    buffer.push((message.ar_count >> 8) as u8);
    buffer.push(message.ar_count as u8);

    for question in &message.questions {
        for part in &question.name {
            buffer.push(part.len() as u8);
            let bytes = part.to_owned().into_bytes();
            for byte in &bytes {
                buffer.push(*byte);
            }
        }

        buffer.push(0 as u8);

        buffer.push((question.rrtype >> 8) as u8);
        buffer.push(question.rrtype as u8);

        buffer.push((question.class >> 8) as u8);
        buffer.push(question.class as u8);
    }

    buffer
}

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:12043").unwrap();

    let mut buffer: [u8; 512] = [0; 512];
    let (size, source) = socket.recv_from(&mut buffer).unwrap();

    let query_message = unpack(&buffer[..size]);

    let answer_message = Message { query_response: 0, ..query_message };

    let result = pack(&answer_message);

    socket.send_to(&result, &source).unwrap();

    drop(socket);
}
<commit_msg>Send a hardcoded answer of a hardcoded domain<commit_after>use std::net::UdpSocket;
use std::str;

struct Question {
    name: Vec<String>,
    rrtype: u16,
    class: u16,
}

struct Answer {
    name: Vec<String>,
    rrtype: u16,
    class: u16,
    ttl: u32,
    length: u16,
    data: Vec<u8>,
}

struct Message {
    id: u16, // 2 bytes
    query_response: u16, // 1 bit
    operation_code: u16, // 4 bits
    authoritative_answer: u16, // 1 bit
    truncation_flag: u16, // 1 bit
    recursion_desired: u16, // 1 bit
    recursion_available: u16, // 1 bit
    unused: u16, // 3 bits
    error_code: u16, // 4 bits
    question_count: u16, // 2 bytes
    answer_count: u16, // 2 bytes
    ns_count: u16, // 2 bytes
    ar_count: u16, // 2 bytes

    questions: Vec<Question>,
    answers: Vec<Answer>,
}

fn unpack(buffer: &[u8]) -> Message {
    let id: u16 = (buffer[0] as u16) << 8 | buffer[1] as u16;
    let body: u16 = (buffer[2] as u16) << 8 | buffer[3] as u16;
    let question_count: u16 = (buffer[4] as u16) << 8 | buffer[5] as u16;
    let answer_count: u16 = (buffer[6] as u16) << 8 | buffer[7] as u16;
    let ns_count: u16 = (buffer[8] as u16) << 8 | buffer[9] as u16;
    let ar_count: u16 = (buffer[10] as u16) << 8 | buffer[11] as u16;

    let mut offset: usize = 12;

    let mut questions = Vec::with_capacity(question_count as usize);

    for _ in 0..question_count {
        let mut name = Vec::new();

        loop {
            let size: usize = buffer[offset] as usize;
            offset += 1;

            if size == 0 {
                break;
            }

            name.push(str::from_utf8(&buffer[offset .. offset + size]).unwrap().to_string());
            offset += size;
        }

        let rrtype: u16 = (buffer[offset] as u16) << 8 | buffer[offset+1] as u16;
        offset += 2;

        let class: u16 = (buffer[offset] as u16) << 8 | buffer[offset+1] as u16;
        offset += 2;

        questions.push(Question{
            name: name,
            rrtype: rrtype,
            class: class,
        })
    }

    Message {
        id: id,
        query_response: (body & (1 << 15)) >> 15,
        operation_code: (body & (15 << 11)) >> 11,
        authoritative_answer: (body & (1 >> 10)) >> 10,
        truncation_flag: (body & (1 >> 9)) >> 9,
        recursion_desired: (body & (1 >> 8)) >> 8,
        recursion_available: (body & (1 >> 7)) >> 7,
        unused: (body & (7 << 4)) >> 4,
        error_code: (body & (15 << 0)) >> 0,
        question_count: question_count,
        answer_count: answer_count,
        ns_count: ns_count,
        ar_count: ar_count,
        questions: questions,
        answers: Vec::new(), // TODO parse answers
    }
}

fn pack(message: &Message) -> Vec<u8> {
    let mut buffer: Vec<u8> = Vec::new();

    buffer.push((message.id >> 8) as u8);
    buffer.push(message.id as u8);

    let mut body: u16 = 0;

    body = body | message.query_response << 15;
    body = body | message.operation_code << 11;
    body = body | message.authoritative_answer << 10;
    body = body | message.truncation_flag << 9;
    body = body | message.recursion_desired << 8;
    body = body | message.recursion_available << 7;
    body = body | message.unused << 4;
    body = body | message.error_code;

    buffer.push((body >> 8) as u8);
    buffer.push(body as u8);

    buffer.push((message.question_count >> 8) as u8);
    buffer.push(message.question_count as u8);

    buffer.push((message.answer_count >> 8) as u8);
    buffer.push(message.answer_count as u8);

    buffer.push((message.ns_count >> 8) as u8);
    buffer.push(message.ns_count as u8);

    buffer.push((message.ar_count >> 8) as u8);
    buffer.push(message.ar_count as u8);

    for question in &message.questions {
        for part in &question.name {
            buffer.push(part.len() as u8);
            let bytes = part.to_owned().into_bytes();
            for byte in &bytes {
                buffer.push(*byte);
            }
        }

        buffer.push(0 as u8);

        buffer.push((question.rrtype >> 8) as u8);
        buffer.push(question.rrtype as u8);

        buffer.push((question.class >> 8) as u8);
        buffer.push(question.class as u8);
    }

    for answer in &message.answers {
        for part in &answer.name {
            buffer.push(part.len() as u8);
            let bytes = part.to_owned().into_bytes();
            for byte in &bytes {
                buffer.push(*byte);
            }
        }

        buffer.push(0 as u8);

        buffer.push((answer.rrtype >> 8) as u8);
        buffer.push(answer.rrtype as u8);

        buffer.push((answer.class >> 8) as u8);
        buffer.push(answer.class as u8);

        buffer.push(((answer.ttl & (256 << 24)) >> 24) as u8);
        buffer.push(((answer.ttl & (256 << 16)) >> 16) as u8);
        buffer.push(((answer.ttl & (256 << 8)) >> 8) as u8);
        buffer.push(((answer.ttl & (256 << 0)) >> 0) as u8);

        buffer.push((answer.length >> 8) as u8);
        buffer.push(answer.length as u8);

        for byte in &answer.data {
            buffer.push(*byte);
        }
    }

    buffer
}

fn main() {
    let socket = UdpSocket::bind("127.0.0.1:12043").unwrap();

    let mut buffer: [u8; 512] = [0; 512];
    let (size, source) = socket.recv_from(&mut buffer).unwrap();

    let query_message = unpack(&buffer[..size]);

    let mut answers = Vec::new();
    answers.push(Answer{
        name: vec!("app".to_string(), "dev".to_string()),
        rrtype: 1,
        class: 1,
        ttl: 0,
        length: 4,
        data: vec!(127, 0, 0, 1),
    });

    let answer_message = Message {
        query_response: 1,
        answer_count: 1,
        answers: answers,
        ..query_message
    };

    let result = pack(&answer_message);

    socket.send_to(&result, &source).unwrap();

    drop(socket);
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(rocket_codegen)]
extern crate diesel;
extern crate schani_store;
extern crate rocket;

use self::schani_store::routes::{tags, images, raw_images, collections};

fn main() {
    rocket::ignite()
        .mount(
            "/api",
            routes![
                tags::get_tags,
                tags::get_tag,
                tags::new,
                tags::update,
                images::new,
                images::update,
                images::get_images,
                images::get_image,
                images::new_image_file,
                images::new_sidecar_file,
                images::get_sidecar_file,
                images::get_image_file,
                images::get_tags_of_image,
                images::new_image_tag,
                raw_images::get_raw_images,
                raw_images::get_raw_image,
                raw_images::new,
                raw_images::new_raw_image_file,
                raw_images::update,
                raw_images::get_raw_image_file,
                collections::new,
                collections::update,
                collections::get_collections,
                collections::get_collection,
            ],
        )
        .launch();
}
<commit_msg>Add image to collection route in main<commit_after>#![feature(plugin)]
#![plugin(rocket_codegen)]
extern crate diesel;
extern crate schani_store;
extern crate rocket;

use self::schani_store::routes::{tags, images, raw_images, collections};

fn main() {
    rocket::ignite()
        .mount(
            "/api",
            routes![
                tags::get_tags,
                tags::get_tag,
                tags::new,
                tags::update,
                images::new,
                images::update,
                images::get_images,
                images::get_image,
                images::new_image_file,
                images::new_sidecar_file,
                images::get_sidecar_file,
                images::get_image_file,
                images::get_tags_of_image,
                images::new_image_tag,
                raw_images::get_raw_images,
                raw_images::get_raw_image,
                raw_images::new,
                raw_images::new_raw_image_file,
                raw_images::update,
                raw_images::get_raw_image_file,
                collections::new,
                collections::update,
                collections::get_collections,
                collections::get_collection,
                collections::new_image_collection,
            ],
        )
        .launch();
}
<|endoftext|>


<commit_before>extern crate getopts;

use getopts::Options;
use std::env;

fn main() {
    let args : Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("h", "help", "Print the help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if matches.opt_present("h") {
        println!("You've asked for help!");
    } else {
        println!("You just want to run the program!");
    }
}
<commit_msg>Makin progress<commit_after>extern crate getopts;

use getopts::Options;
use std::env;

const C1_DEFAULT: u8 = 12;

fn print_usage() {
    println!("cachesim [OPTIONS] < traces/file.trace");
    println!("L1 Parameters:");
    println!("  -c C1\t\tThe total size of the L1 cache is 2^C1 bytes");
    println!("  -b B1\t\tThe size of a block in the L1 cache is 2^B1 bytes");
    println!("  -s S1\t\tThe number of blocks per set in L1 is 2^S1");
    println!("Victim cache parameters:");
    println!("  -v V\t\tThe number of blocks in the Victim Cache");
    println!("L2 Parameters:");
    println!("  -C C2\t\tThe total size of the L2 cache is 2^C2 bytes");
    println!("  -B B2\t\tThe size of a block in the L2 cache is 2^B2 bytes");
    println!("  -S S2\t\tThe number of blocks per set in L2 is 2^S2");
}

fn main() {
    let args : Vec<String> = env::args().collect();
    //let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("h", "help", "Print the help menu");

    opts.optopt("c", "", "C parameter for L1 cache", "C1");
    opts.optopt("b", "", "B parameter for L1 cache", "B1");
    opts.optopt("s", "", "S parameter for L1 cache", "S1");
    opts.optopt("v", "", "v parameter for Victim cache", "V");
    opts.optopt("C", "", "C parameter for L2 cache", "C2");
    opts.optopt("B", "", "B parameter for L2 cache", "B2");
    opts.optopt("S", "", "S parameter for L2 cache", "S2");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) },
    };

    if matches.opt_present("h") {
        print_usage();
        return;
    }

    let c1 = match matches.opt_str("c") {
        Some(s) => s.parse::<u8>().unwrap(),
        None => C1_DEFAULT,
    };

    println!("The value of C1 is {}", c1);

}
<|endoftext|>


<commit_before>extern crate iron;
extern crate router;
extern crate hyper;
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate hyper_rustls;
extern crate urlencoded;

use std::vec::Vec;
use hyper::Client as HyperClient;
use hyper::net::HttpsConnector;
use router::{Router, NoRoute};
use iron::prelude::*;
use iron::status;
use iron::AfterMiddleware;
use regex::Regex;
use std::io::Read;
use hyper_rustls::TlsClient as RustlsClient;
use urlencoded::{UrlEncodedQuery, UrlDecodingError};
use std::collections::HashMap;
use std::option::Option;
use std::error::Error;
use std::fmt;
use iron::headers::ContentType;
use std::ops::Deref;

#[derive(Debug, PartialEq, Eq)]
struct Md5ReCheckFailed;

impl fmt::Display for Md5ReCheckFailed {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("Not a vaild MD5 String!")
    }
}

impl Error for Md5ReCheckFailed {
    fn description(&self) -> &str {
        "Md5 Re Check Failed!"
    }
}

fn verify_md5(md5: &str) -> bool {
    lazy_static! {
        static ref MD5_RE: Regex = Regex::new("^[0-9a-f]{32}$").unwrap();
    }

    MD5_RE.is_match(md5)
}

struct AvatarError {
    pub status: Option<status::Status>,
}

struct Avatar {
    pub email_md5: String,
    pub size: Option<i64>,
    pub content_type: ContentType,
    pub buf: Vec<u8>,
}

type AvatarResult = Result<Avatar, AvatarError>;

impl Avatar {
    fn make_origin_url(email_md5: &str, size: Option<i64>, default: Option<String>) -> String {
        let mut origin_url = format!("https://secure.gravatar.com/avatar/{}", email_md5);

        let mut params: Vec<String> = Vec::new();

        if let Some(m) = size {
            params.push(format!("s={}", m));
        }

        if let Some(m) = default {
            params.push(format!("d={}", m));
        }

        if params.len() > 0 {
            origin_url.push_str("?");
            origin_url.push_str(params.join("&").as_str());
        }

        origin_url
    }

    pub fn fetch(email_md5: &str, size: Option<i64>, default: Option<String>) -> AvatarResult {

        lazy_static! {
            static ref HYPER_CLIENT: HyperClient = HyperClient::with_connector(HttpsConnector::new(RustlsClient::new()));
        }

        let origin_url = Avatar::make_origin_url(email_md5, size.clone(), default.clone());

        let mut origin_res = try!(HYPER_CLIENT.get(origin_url.as_str())
            .send()
            .map_err(|_| AvatarError { status: None }));

        if origin_res.status != hyper::Ok {
            return Err(AvatarError { status: Some(origin_res.status) });
        }

        let mut avatar_body: Vec<u8> = Vec::new();

        try!(origin_res.read_to_end(&mut avatar_body)
            .map_err(|_| AvatarError { status: Some(status::BadGateway) }));

        let content_type = try!(origin_res.headers
                .get::<ContentType>()
                .ok_or(AvatarError { status: Some(status::BadGateway) }))
            .clone();

        Ok(Avatar {
            email_md5: email_md5.to_string(),
            size: size.clone(),
            content_type: content_type,
            buf: avatar_body,
        })
    }
}

fn handler(req: &mut Request) -> IronResult<Response> {
    let email_md5 = req.extensions
        .get::<Router>()
        .unwrap()
        .find("email_md5")
        .unwrap_or("")
        .to_lowercase();

    if !verify_md5(email_md5.as_str()) {
        return Ok(Response::with((status::NotFound)));
    }

    let maybe_query = req.get::<UrlEncodedQuery>()
        .map(|val| Some(val))
        .unwrap_or_else(|err: UrlDecodingError| {
            match err {
                UrlDecodingError::EmptyQuery => Some(HashMap::new()),
                _ => None,
            }
        });

    let query = match maybe_query {
        Some(m) => m,
        None => return Ok(Response::with((status::BadRequest))),
    };

    let size_str = query.get("s")
        .map(|s_vec| s_vec.clone())
        .map(|s_vec| { if s_vec.len() > 0 { Some(s_vec) } else { None } })
        .unwrap_or(None)
        .map(|s_vec| s_vec[0].clone());

    let default = query.get("d")
        .map(|d_vec| d_vec.clone())
        .map(|d_vec| { if d_vec.len() > 0 { Some(d_vec) } else { None } })
        .unwrap_or(None)
        .map(|d_vec| d_vec[0].clone());

    let size: Option<i64> = match size_str {
        Some(m) => {
            match m.parse::<i64>() {
                Ok(m) => Some(m),
                Err(_) => return Ok(Response::with((status::BadRequest))),
            }
        }
        None => None,
    };

    let avatar = match Avatar::fetch(email_md5.as_str(), size, default) {
        Ok(v) => v,
        Err(_) => return Ok(Response::with((status::BadGateway))),
    };

    Ok(Response::with((avatar.content_type.deref().clone(), status::Ok, avatar.buf.clone())))
}

struct CustomErrorMsg;

impl CustomErrorMsg {
    fn alter_response(&self, res: Response) -> Response {
        if res.status == Some(status::NotFound) {
            Response::with((status::NotFound, "HTTP 404: Not Found."))

        } else if res.status == Some(status::BadRequest) {
            Response::with((status::BadRequest, "HTTP 400: Bad Request."))

        } else if res.status == Some(status::BadGateway) {
            Response::with((status::BadGateway, "HTTP 502: Bad Gateway."))

        } else {
            res

        }
    }
}

impl AfterMiddleware for CustomErrorMsg {
    fn after(&self, _: &mut Request, res: Response) -> IronResult<Response> {
        Ok(self.alter_response(res))
    }

    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        let res = err.response;
        let res = self.alter_response(res);

        if let Some(_) = err.error.downcast::<NoRoute>() {
            return Ok(res);
        }

        if let Some(_) = err.error.downcast::<Md5ReCheckFailed>() {
            return Ok(res);
        }

        Err(IronError {
            error: err.error,
            response: res,
        })
    }
}

struct XPoweredBy;

impl XPoweredBy {
    fn add_header(&self, res: &mut Response) {
        res.headers.set_raw("X-Powered-By", vec![b"Rust".to_vec()]);
    }
}

impl AfterMiddleware for XPoweredBy {
    fn after(&self, _: &mut Request, mut res: Response) -> IronResult<Response> {
        self.add_header(&mut res);

        Ok(res)
    }

    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        let mut res = err.response;
        let inner_err = err.error;
        self.add_header(&mut res);

        Err(IronError {
            error: inner_err,
            response: res,
        })
    }
}

fn main() {
    let mut router = Router::new();

    router.get("/avatar/:email_md5", handler, "email_md5");

    let mut chain = Chain::new(router);
    chain.link_after(CustomErrorMsg);
    chain.link_after(XPoweredBy);

    Iron::new(chain).http("localhost:3000").unwrap();
}
<commit_msg>Remove Md5ReCheckFailed Error.<commit_after>extern crate iron;
extern crate router;
extern crate hyper;
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate hyper_rustls;
extern crate urlencoded;

use std::vec::Vec;
use hyper::Client as HyperClient;
use hyper::net::HttpsConnector;
use router::{Router, NoRoute};
use iron::prelude::*;
use iron::status;
use iron::AfterMiddleware;
use regex::Regex;
use std::io::Read;
use hyper_rustls::TlsClient as RustlsClient;
use urlencoded::{UrlEncodedQuery, UrlDecodingError};
use std::collections::HashMap;
use std::option::Option;
use std::error::Error;
use std::fmt;
use iron::headers::ContentType;
use std::ops::Deref;

fn verify_md5(md5: &str) -> bool {
    lazy_static! {
        static ref MD5_RE: Regex = Regex::new("^[0-9a-f]{32}$").unwrap();
    }

    MD5_RE.is_match(md5)
}

struct AvatarError {
    pub status: Option<status::Status>,
}

struct Avatar {
    pub email_md5: String,
    pub size: Option<i64>,
    pub content_type: ContentType,
    pub buf: Vec<u8>,
}

type AvatarResult = Result<Avatar, AvatarError>;

impl Avatar {
    fn make_origin_url(email_md5: &str, size: Option<i64>, default: Option<String>) -> String {
        let mut origin_url = format!("https://secure.gravatar.com/avatar/{}", email_md5);

        let mut params: Vec<String> = Vec::new();

        if let Some(m) = size {
            params.push(format!("s={}", m));
        }

        if let Some(m) = default {
            params.push(format!("d={}", m));
        }

        if params.len() > 0 {
            origin_url.push_str("?");
            origin_url.push_str(params.join("&").as_str());
        }

        origin_url
    }

    pub fn fetch(email_md5: &str, size: Option<i64>, default: Option<String>) -> AvatarResult {

        lazy_static! {
            static ref HYPER_CLIENT: HyperClient = HyperClient::with_connector(HttpsConnector::new(RustlsClient::new()));
        }

        let origin_url = Avatar::make_origin_url(email_md5, size.clone(), default.clone());

        let mut origin_res = try!(HYPER_CLIENT.get(origin_url.as_str())
            .send()
            .map_err(|_| AvatarError { status: None }));

        if origin_res.status != hyper::Ok {
            return Err(AvatarError { status: Some(origin_res.status) });
        }

        let mut avatar_body: Vec<u8> = Vec::new();

        try!(origin_res.read_to_end(&mut avatar_body)
            .map_err(|_| AvatarError { status: Some(status::BadGateway) }));

        let content_type = try!(origin_res.headers
                .get::<ContentType>()
                .ok_or(AvatarError { status: Some(status::BadGateway) }))
            .clone();

        Ok(Avatar {
            email_md5: email_md5.to_string(),
            size: size.clone(),
            content_type: content_type,
            buf: avatar_body,
        })
    }
}

fn handler(req: &mut Request) -> IronResult<Response> {
    let email_md5 = req.extensions
        .get::<Router>()
        .unwrap()
        .find("email_md5")
        .unwrap_or("")
        .to_lowercase();

    if !verify_md5(email_md5.as_str()) {
        return Ok(Response::with((status::NotFound)));
    }

    let maybe_query = req.get::<UrlEncodedQuery>()
        .map(|val| Some(val))
        .unwrap_or_else(|err: UrlDecodingError| {
            match err {
                UrlDecodingError::EmptyQuery => Some(HashMap::new()),
                _ => None,
            }
        });

    let query = match maybe_query {
        Some(m) => m,
        None => return Ok(Response::with((status::BadRequest))),
    };

    let size_str = query.get("s")
        .map(|s_vec| s_vec.clone())
        .map(|s_vec| { if s_vec.len() > 0 { Some(s_vec) } else { None } })
        .unwrap_or(None)
        .map(|s_vec| s_vec[0].clone());

    let default = query.get("d")
        .map(|d_vec| d_vec.clone())
        .map(|d_vec| { if d_vec.len() > 0 { Some(d_vec) } else { None } })
        .unwrap_or(None)
        .map(|d_vec| d_vec[0].clone());

    let size: Option<i64> = match size_str {
        Some(m) => {
            match m.parse::<i64>() {
                Ok(m) => Some(m),
                Err(_) => return Ok(Response::with((status::BadRequest))),
            }
        }
        None => None,
    };

    let avatar = match Avatar::fetch(email_md5.as_str(), size, default) {
        Ok(v) => v,
        Err(_) => return Ok(Response::with((status::BadGateway))),
    };

    Ok(Response::with((avatar.content_type.deref().clone(), status::Ok, avatar.buf.clone())))
}

struct CustomErrorMsg;

impl CustomErrorMsg {
    fn alter_response(&self, res: Response) -> Response {
        if res.status == Some(status::NotFound) {
            Response::with((status::NotFound, "HTTP 404: Not Found."))

        } else if res.status == Some(status::BadRequest) {
            Response::with((status::BadRequest, "HTTP 400: Bad Request."))

        } else if res.status == Some(status::BadGateway) {
            Response::with((status::BadGateway, "HTTP 502: Bad Gateway."))

        } else {
            res

        }
    }
}

impl AfterMiddleware for CustomErrorMsg {
    fn after(&self, _: &mut Request, res: Response) -> IronResult<Response> {
        Ok(self.alter_response(res))
    }

    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        let res = err.response;
        let res = self.alter_response(res);

        if let Some(_) = err.error.downcast::<NoRoute>() {
            return Ok(res);
        }

        Err(IronError {
            error: err.error,
            response: res,
        })
    }
}

struct XPoweredBy;

impl XPoweredBy {
    fn add_header(&self, res: &mut Response) {
        res.headers.set_raw("X-Powered-By", vec![b"Rust".to_vec()]);
    }
}

impl AfterMiddleware for XPoweredBy {
    fn after(&self, _: &mut Request, mut res: Response) -> IronResult<Response> {
        self.add_header(&mut res);

        Ok(res)
    }

    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        let mut res = err.response;
        let inner_err = err.error;
        self.add_header(&mut res);

        Err(IronError {
            error: inner_err,
            response: res,
        })
    }
}

fn main() {
    let mut router = Router::new();

    router.get("/avatar/:email_md5", handler, "email_md5");

    let mut chain = Chain::new(router);
    chain.link_after(CustomErrorMsg);
    chain.link_after(XPoweredBy);

    Iron::new(chain).http("localhost:3000").unwrap();
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # NDFA
//!
//! The acronym NDFA stands for 'Non-Deterministic Finite Automaton'. An NDFA is a state machine where each state can have
//! transitions for more than one target state - this allows it to be in more than one state at once, which is the property
//! that makes it non-deterministic.
//!
//! NDFAs can match patterns conforming to a regular language - that is, they match regular expressions. However, their
//! non-deterministic nature means that they are inconvenient to evaluate. Fortunately, for every NDFA there can be found
//! a DFA - a *Deterministic* Finite Automaton - which can be used to rapidly match strings of symbols against the expression.
//!
//! Every implementation of the `StateMachine` trait represents an NDFA. This particular implementation is useful because it
//! also implements `MutableStateMachine` so can be used as a means to build state machines that can be used to match patterns.
//!
//! An NDFA is created by calling the constructor:
//!
//! ```
//! # use ndfa::*;
//! let mut ndfa: Ndfa<u32, u32> = Ndfa::new();
//! ```
//!

use super::state_machine::*;
use std::collections::HashMap;

///
/// Represents a non-deterministic finite-state automata
///
#[derive(Clone)]
pub struct Ndfa<InputSymbol, OutputSymbol> where InputSymbol : Clone {
    /// Highest known state ID
    max_state: StateId,

    /// Transitions for each state
    transitions: Vec<Vec<(InputSymbol, StateId)>>,

    /// Output symbols for each state
    output_symbols: HashMap<StateId, OutputSymbol>
}

impl<InputSymbol : Clone, OutputSymbol> Ndfa<InputSymbol, OutputSymbol> {
    pub fn new() -> Ndfa<InputSymbol, OutputSymbol> {
        Ndfa { max_state: 0, transitions: vec![], output_symbols: HashMap::new() }
    }
}

impl<InputSymbol : Clone, OutputSymbol> StateMachine<InputSymbol, OutputSymbol> for Ndfa<InputSymbol, OutputSymbol> {
    fn count_states(&self) -> StateId {
        self.max_state + 1
    }

    fn get_transitions_for_state(&self, state: StateId) -> Vec<(InputSymbol, StateId)> {
        if (state as usize) >= self.transitions.len() {
            vec![]
        } else {
            self.transitions[state as usize].clone()
        }
    }

    fn output_symbol_for_state(&self, state: StateId) -> Option<&OutputSymbol> {
        self.output_symbols.get(&state)
    }
}

impl<InputSymbol : Clone, OutputSymbol> MutableStateMachine<InputSymbol, OutputSymbol> for Ndfa<InputSymbol, OutputSymbol> {
    fn add_transition(&mut self, state: StateId, for_symbol: InputSymbol, new_state: StateId) {
        // Make sure that max_state reflects the highest state added by the user
        if new_state > self.max_state {
            self.max_state = new_state;
        }

        if state > self.max_state {
            self.max_state = state;
        }

        // Expand the transitions vector so that the new state has somewhere to go
        while self.transitions.len() <= state as usize {
            self.transitions.push(vec![]);
        }

        self.transitions[state as usize].push((for_symbol, new_state));
    }

    fn set_output_symbol(&mut self, state: StateId, new_output_symbol: OutputSymbol) {
        // Output symbols update the max state too
        if state > self.max_state {
            self.max_state = state;
        }

        self.output_symbols.insert(state, new_output_symbol);
    }

    fn join_states(&mut self, first_state: StateId, second_state: StateId) {
        unimplemented!()
    }
}

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

    #[test]
    fn there_is_initially_one_state() {
        let ndfa: Ndfa<u32, u32> = Ndfa::new();

        assert!(ndfa.count_states() == 1);
    }

    #[test]
    fn adding_transition_updates_max_state_to_target() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn adding_output_symbol_updates_max_state() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.set_output_symbol(1, 128);
        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn adding_transition_updates_max_state_to_source() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(1, 42, 0);
        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn can_retrieve_transition() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(1, 42, 0);
        assert!(ndfa.get_transitions_for_state(1).len() == 1);
        assert!(ndfa.get_transitions_for_state(1)[0] == (42, 0));
    }

    #[test]
    fn can_add_multiple_transitions() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(1, 42, 0);
        ndfa.add_transition(1, 42, 2);

        assert!(ndfa.get_transitions_for_state(1).len() == 2);
        assert!(ndfa.get_transitions_for_state(1).contains(&(42, 0)));
        assert!(ndfa.get_transitions_for_state(1).contains(&(42, 2)));
    }

    #[test]
    fn output_symbol_is_none_by_default() {
        let ndfa: Ndfa<u32, u32> = Ndfa::new();

        assert!(ndfa.output_symbol_for_state(0) == None);
        assert!(ndfa.output_symbol_for_state(1) == None);
    }

    #[test]
    fn can_set_output_symbol() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.set_output_symbol(0, 64);

        assert!(ndfa.output_symbol_for_state(0) == Some(&64));
        assert!(ndfa.output_symbol_for_state(1) == None);
    }
}
<commit_msg>Add tests for joined states<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # NDFA
//!
//! The acronym NDFA stands for 'Non-Deterministic Finite Automaton'. An NDFA is a state machine where each state can have
//! transitions for more than one target state - this allows it to be in more than one state at once, which is the property
//! that makes it non-deterministic.
//!
//! NDFAs can match patterns conforming to a regular language - that is, they match regular expressions. However, their
//! non-deterministic nature means that they are inconvenient to evaluate. Fortunately, for every NDFA there can be found
//! a DFA - a *Deterministic* Finite Automaton - which can be used to rapidly match strings of symbols against the expression.
//!
//! Every implementation of the `StateMachine` trait represents an NDFA. This particular implementation is useful because it
//! also implements `MutableStateMachine` so can be used as a means to build state machines that can be used to match patterns.
//!
//! An NDFA is created by calling the constructor:
//!
//! ```
//! # use ndfa::*;
//! let mut ndfa: Ndfa<u32, u32> = Ndfa::new();
//! ```
//!

use super::state_machine::*;
use std::collections::HashMap;

///
/// Represents a non-deterministic finite-state automata
///
#[derive(Clone)]
pub struct Ndfa<InputSymbol, OutputSymbol> where InputSymbol : Clone {
    /// Highest known state ID
    max_state: StateId,

    /// Transitions for each state
    transitions: Vec<Vec<(InputSymbol, StateId)>>,

    /// Output symbols for each state
    output_symbols: HashMap<StateId, OutputSymbol>
}

impl<InputSymbol : Clone, OutputSymbol> Ndfa<InputSymbol, OutputSymbol> {
    pub fn new() -> Ndfa<InputSymbol, OutputSymbol> {
        Ndfa { max_state: 0, transitions: vec![], output_symbols: HashMap::new() }
    }
}

impl<InputSymbol : Clone, OutputSymbol> StateMachine<InputSymbol, OutputSymbol> for Ndfa<InputSymbol, OutputSymbol> {
    fn count_states(&self) -> StateId {
        self.max_state + 1
    }

    fn get_transitions_for_state(&self, state: StateId) -> Vec<(InputSymbol, StateId)> {
        if (state as usize) >= self.transitions.len() {
            vec![]
        } else {
            self.transitions[state as usize].clone()
        }
    }

    fn output_symbol_for_state(&self, state: StateId) -> Option<&OutputSymbol> {
        self.output_symbols.get(&state)
    }
}

impl<InputSymbol : Clone, OutputSymbol> MutableStateMachine<InputSymbol, OutputSymbol> for Ndfa<InputSymbol, OutputSymbol> {
    fn add_transition(&mut self, state: StateId, for_symbol: InputSymbol, new_state: StateId) {
        // Make sure that max_state reflects the highest state added by the user
        if new_state > self.max_state {
            self.max_state = new_state;
        }

        if state > self.max_state {
            self.max_state = state;
        }

        // Expand the transitions vector so that the new state has somewhere to go
        while self.transitions.len() <= state as usize {
            self.transitions.push(vec![]);
        }

        self.transitions[state as usize].push((for_symbol, new_state));
    }

    fn set_output_symbol(&mut self, state: StateId, new_output_symbol: OutputSymbol) {
        // Output symbols update the max state too
        if state > self.max_state {
            self.max_state = state;
        }

        self.output_symbols.insert(state, new_output_symbol);
    }

    fn join_states(&mut self, first_state: StateId, second_state: StateId) {
        unimplemented!()
    }
}

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

    #[test]
    fn there_is_initially_one_state() {
        let ndfa: Ndfa<u32, u32> = Ndfa::new();

        assert!(ndfa.count_states() == 1);
    }

    #[test]
    fn adding_transition_updates_max_state_to_target() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn adding_output_symbol_updates_max_state() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.set_output_symbol(1, 128);
        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn adding_transition_updates_max_state_to_source() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(1, 42, 0);
        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn can_retrieve_transition() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(1, 42, 0);
        assert!(ndfa.get_transitions_for_state(1).len() == 1);
        assert!(ndfa.get_transitions_for_state(1)[0] == (42, 0));
    }

    #[test]
    fn can_add_multiple_transitions() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(1, 42, 0);
        ndfa.add_transition(1, 42, 2);

        assert!(ndfa.get_transitions_for_state(1).len() == 2);
        assert!(ndfa.get_transitions_for_state(1).contains(&(42, 0)));
        assert!(ndfa.get_transitions_for_state(1).contains(&(42, 2)));
    }

    #[test]
    fn output_symbol_is_none_by_default() {
        let ndfa: Ndfa<u32, u32> = Ndfa::new();

        assert!(ndfa.output_symbol_for_state(0) == None);
        assert!(ndfa.output_symbol_for_state(1) == None);
    }

    #[test]
    fn can_set_output_symbol() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.set_output_symbol(0, 64);

        assert!(ndfa.output_symbol_for_state(0) == Some(&64));
        assert!(ndfa.output_symbol_for_state(1) == None);
    }

    #[test]
    fn join_states_attaches_transitions_to_first_state() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);
        ndfa.join_states(0, 1);

        assert!(ndfa.get_transitions_for_state(0).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(43, 2)));
    }

    #[test]
    fn adding_transition_after_join_updates_target() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.join_states(0, 1);
        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);

        assert!(ndfa.get_transitions_for_state(0).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(43, 2)));
    }

    #[test]
    fn join_updates_state_count() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.join_states(0, 1);

        assert!(ndfa.count_states() == 2);
    }

    #[test]
    fn join_states_does_not_attach_to_second_state() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);
        ndfa.join_states(0, 1);

        assert!(!ndfa.get_transitions_for_state(1).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(1).contains(&(43, 2)));
    }

    #[test]
    fn join_states_recurses_to_further_states() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);
        ndfa.add_transition(2, 44, 3);
        ndfa.join_states(0, 1);
        ndfa.join_states(1, 2);

        assert!(ndfa.get_transitions_for_state(0).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(43, 2)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(44, 3)));
    }

    #[test]
    fn join_loop_attaches_to_both_states() {
        let mut ndfa: Ndfa<u32, u32> = Ndfa::new();

        ndfa.add_transition(0, 42, 1);
        ndfa.add_transition(1, 43, 2);
        ndfa.join_states(0, 1);
        ndfa.join_states(1, 0);

        assert!(ndfa.get_transitions_for_state(0).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(0).contains(&(43, 2)));

        assert!(ndfa.get_transitions_for_state(1).contains(&(42, 1)));
        assert!(ndfa.get_transitions_for_state(1).contains(&(43, 2)));
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[doc(hidden)]; // FIXME #3538

use cast;
use cmp::Eq;
use libc;
use prelude::*;
use task::rt;
use task::local_data::LocalDataKey;

use super::rt::rust_task;
use rt::local_services::LocalStorage;

pub enum Handle {
    OldHandle(*rust_task),
    NewHandle(*mut LocalStorage)
}

impl Handle {
    pub fn new() -> Handle {
        use rt::{context, OldTaskContext};
        use rt::local_services::unsafe_borrow_local_services;
        unsafe {
            match context() {
                OldTaskContext => {
                    OldHandle(rt::rust_get_task())
                }
                _ => {
                    let local_services = unsafe_borrow_local_services();
                    NewHandle(&mut local_services.storage)
                }
            }
        }
    }
}

pub trait LocalData { }
impl<T:Durable> LocalData for @T { }

impl Eq for @LocalData {
    fn eq(&self, other: &@LocalData) -> bool {
        unsafe {
            let ptr_a: (uint, uint) = cast::reinterpret_cast(&(*self));
            let ptr_b: (uint, uint) = cast::reinterpret_cast(other);
            return ptr_a == ptr_b;
        }
    }
    fn ne(&self, other: &@LocalData) -> bool { !(*self).eq(other) }
}

// If TLS is used heavily in future, this could be made more efficient with a
// proper map.
type TaskLocalElement = (*libc::c_void, *libc::c_void, @LocalData);
// Has to be a pointer at outermost layer; the foreign call returns void *.
type TaskLocalMap = @mut ~[Option<TaskLocalElement>];

fn cleanup_task_local_map(map_ptr: *libc::c_void) {
    unsafe {
        assert!(!map_ptr.is_null());
        // Get and keep the single reference that was created at the
        // beginning.
        let _map: TaskLocalMap = cast::reinterpret_cast(&map_ptr);
        // All local_data will be destroyed along with the map.
    }
}

// Gets the map from the runtime. Lazily initialises if not done so already.
unsafe fn get_local_map(handle: Handle) -> TaskLocalMap {
    match handle {
        OldHandle(task) => get_task_local_map(task),
        NewHandle(local_storage) => get_newsched_local_map(local_storage)
    }
}

unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap {

    extern fn cleanup_task_local_map_(map_ptr: *libc::c_void) {
        cleanup_task_local_map(map_ptr);
    }

    // Relies on the runtime initialising the pointer to null.
    // Note: The map's box lives in TLS invisibly referenced once. Each time
    // we retrieve it for get/set, we make another reference, which get/set
    // drop when they finish. No "re-storing after modifying" is needed.
    let map_ptr = rt::rust_get_task_local_data(task);
    if map_ptr.is_null() {
        let map: TaskLocalMap = @mut ~[];
        // Use reinterpret_cast -- transmute would take map away from us also.
        rt::rust_set_task_local_data(
            task, cast::transmute(map));
        rt::rust_task_local_data_atexit(task, cleanup_task_local_map_);
        // Also need to reference it an extra time to keep it for now.
        let nonmut = cast::transmute::<TaskLocalMap,
                                       @~[Option<TaskLocalElement>]>(map);
        cast::bump_box_refcount(nonmut);
        map
    } else {
        let map = cast::transmute(map_ptr);
        let nonmut = cast::transmute::<TaskLocalMap,
                                       @~[Option<TaskLocalElement>]>(map);
        cast::bump_box_refcount(nonmut);
        map
    }
}

unsafe fn get_newsched_local_map(local: *mut LocalStorage) -> TaskLocalMap {
    match &mut *local {
        &LocalStorage(map_ptr, Some(_)) => {
            assert!(map_ptr.is_not_null());
            let map = cast::transmute(map_ptr);
            let nonmut = cast::transmute::<TaskLocalMap,
            @~[Option<TaskLocalElement>]>(map);
            cast::bump_box_refcount(nonmut);
            return map;
        }
        &LocalStorage(ref mut map_ptr, ref mut at_exit) => {
            assert!((*map_ptr).is_null());
            let map: TaskLocalMap = @mut ~[];
            // Use reinterpret_cast -- transmute would take map away from us also.
            *map_ptr = cast::reinterpret_cast(&map);
            let at_exit_fn: ~fn(*libc::c_void) = |p|cleanup_task_local_map(p);
            *at_exit = Some(at_exit_fn);
            // Also need to reference it an extra time to keep it for now.
            let nonmut = cast::transmute::<TaskLocalMap,
            @~[Option<TaskLocalElement>]>(map);
            cast::bump_box_refcount(nonmut);
            return map;
        }
    }
}

unsafe fn key_to_key_value<T:Durable>(
    key: LocalDataKey<T>) -> *libc::c_void {

    // Keys are closures, which are (fnptr,envptr) pairs. Use fnptr.
    // Use reintepret_cast -- transmute would leak (forget) the closure.
    let pair: (*libc::c_void, *libc::c_void) = cast::reinterpret_cast(&key);
    pair.first()
}

// If returning Some(..), returns with @T with the map's reference. Careful!
unsafe fn local_data_lookup<T:Durable>(
    map: TaskLocalMap, key: LocalDataKey<T>)
    -> Option<(uint, *libc::c_void)> {

    let key_value = key_to_key_value(key);
    let map_pos = (*map).position(|entry|
        match *entry {
            Some((k,_,_)) => k == key_value,
            None => false
        }
    );
    do map_pos.map |index| {
        // .get() is guaranteed because of "None { false }" above.
        let (_, data_ptr, _) = (*map)[*index].get();
        (*index, data_ptr)
    }
}

unsafe fn local_get_helper<T:Durable>(
    handle: Handle, key: LocalDataKey<T>,
    do_pop: bool) -> Option<@T> {

    let map = get_local_map(handle);
    // Interpreturn our findings from the map
    do local_data_lookup(map, key).map |result| {
        // A reference count magically appears on 'data' out of thin air. It
        // was referenced in the local_data box, though, not here, so before
        // overwriting the local_data_box we need to give an extra reference.
        // We must also give an extra reference when not removing.
        let (index, data_ptr) = *result;
        let data: @T = cast::transmute(data_ptr);
        cast::bump_box_refcount(data);
        if do_pop {
            map[index] = None;
        }
        data
    }
}

pub unsafe fn local_pop<T:Durable>(
    handle: Handle,
    key: LocalDataKey<T>) -> Option<@T> {

    local_get_helper(handle, key, true)
}

pub unsafe fn local_get<T:Durable>(
    handle: Handle,
    key: LocalDataKey<T>) -> Option<@T> {

    local_get_helper(handle, key, false)
}

pub unsafe fn local_set<T:Durable>(
    handle: Handle, key: LocalDataKey<T>, data: @T) {

    let map = get_local_map(handle);
    // Store key+data as *voids. Data is invisibly referenced once; key isn't.
    let keyval = key_to_key_value(key);
    // We keep the data in two forms: one as an unsafe pointer, so we can get
    // it back by casting; another in an existential box, so the reference we
    // own on it can be dropped when the box is destroyed. The unsafe pointer
    // does not have a reference associated with it, so it may become invalid
    // when the box is destroyed.
    let data_ptr = cast::reinterpret_cast(&data);
    let data_box = @data as @LocalData;
    // Construct new entry to store in the map.
    let new_entry = Some((keyval, data_ptr, data_box));
    // Find a place to put it.
    match local_data_lookup(map, key) {
        Some((index, _old_data_ptr)) => {
            // Key already had a value set, _old_data_ptr, whose reference
            // will get dropped when the local_data box is overwritten.
            map[index] = new_entry;
        }
        None => {
            // Find an empty slot. If not, grow the vector.
            match (*map).position(|x| x.is_none()) {
                Some(empty_index) => { map[empty_index] = new_entry; }
                None => { map.push(new_entry); }
            }
        }
    }
}

pub unsafe fn local_modify<T:Durable>(
    handle: Handle, key: LocalDataKey<T>,
    modify_fn: &fn(Option<@T>) -> Option<@T>) {

    // Could be more efficient by doing the lookup work, but this is easy.
    let newdata = modify_fn(local_pop(handle, key));
    if newdata.is_some() {
        local_set(handle, key, newdata.unwrap());
    }
}
<commit_msg>core: Convert reinterpret_cast to transmute in TLS. #6039<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[doc(hidden)]; // FIXME #3538

use cast;
use cmp::Eq;
use libc;
use prelude::*;
use task::rt;
use task::local_data::LocalDataKey;

use super::rt::rust_task;
use rt::local_services::LocalStorage;

pub enum Handle {
    OldHandle(*rust_task),
    NewHandle(*mut LocalStorage)
}

impl Handle {
    pub fn new() -> Handle {
        use rt::{context, OldTaskContext};
        use rt::local_services::unsafe_borrow_local_services;
        unsafe {
            match context() {
                OldTaskContext => {
                    OldHandle(rt::rust_get_task())
                }
                _ => {
                    let local_services = unsafe_borrow_local_services();
                    NewHandle(&mut local_services.storage)
                }
            }
        }
    }
}

pub trait LocalData { }
impl<T:Durable> LocalData for @T { }

impl Eq for @LocalData {
    fn eq(&self, other: &@LocalData) -> bool {
        unsafe {
            let ptr_a: &(uint, uint) = cast::transmute(self);
            let ptr_b: &(uint, uint) = cast::transmute(other);
            return ptr_a == ptr_b;
        }
    }
    fn ne(&self, other: &@LocalData) -> bool { !(*self).eq(other) }
}

// If TLS is used heavily in future, this could be made more efficient with a
// proper map.
type TaskLocalElement = (*libc::c_void, *libc::c_void, @LocalData);
// Has to be a pointer at outermost layer; the foreign call returns void *.
type TaskLocalMap = @mut ~[Option<TaskLocalElement>];

fn cleanup_task_local_map(map_ptr: *libc::c_void) {
    unsafe {
        assert!(!map_ptr.is_null());
        // Get and keep the single reference that was created at the
        // beginning.
        let _map: TaskLocalMap = cast::transmute(map_ptr);
        // All local_data will be destroyed along with the map.
    }
}

// Gets the map from the runtime. Lazily initialises if not done so already.
unsafe fn get_local_map(handle: Handle) -> TaskLocalMap {
    match handle {
        OldHandle(task) => get_task_local_map(task),
        NewHandle(local_storage) => get_newsched_local_map(local_storage)
    }
}

unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap {

    extern fn cleanup_task_local_map_(map_ptr: *libc::c_void) {
        cleanup_task_local_map(map_ptr);
    }

    // Relies on the runtime initialising the pointer to null.
    // Note: The map's box lives in TLS invisibly referenced once. Each time
    // we retrieve it for get/set, we make another reference, which get/set
    // drop when they finish. No "re-storing after modifying" is needed.
    let map_ptr = rt::rust_get_task_local_data(task);
    if map_ptr.is_null() {
        let map: TaskLocalMap = @mut ~[];
        // Use reinterpret_cast -- transmute would take map away from us also.
        rt::rust_set_task_local_data(
            task, cast::transmute(map));
        rt::rust_task_local_data_atexit(task, cleanup_task_local_map_);
        // Also need to reference it an extra time to keep it for now.
        let nonmut = cast::transmute::<TaskLocalMap,
                                       @~[Option<TaskLocalElement>]>(map);
        cast::bump_box_refcount(nonmut);
        map
    } else {
        let map = cast::transmute(map_ptr);
        let nonmut = cast::transmute::<TaskLocalMap,
                                       @~[Option<TaskLocalElement>]>(map);
        cast::bump_box_refcount(nonmut);
        map
    }
}

unsafe fn get_newsched_local_map(local: *mut LocalStorage) -> TaskLocalMap {
    match &mut *local {
        &LocalStorage(map_ptr, Some(_)) => {
            assert!(map_ptr.is_not_null());
            let map = cast::transmute(map_ptr);
            let nonmut = cast::transmute::<TaskLocalMap,
            @~[Option<TaskLocalElement>]>(map);
            cast::bump_box_refcount(nonmut);
            return map;
        }
        &LocalStorage(ref mut map_ptr, ref mut at_exit) => {
            assert!((*map_ptr).is_null());
            let map: TaskLocalMap = @mut ~[];
            *map_ptr = cast::transmute(map);
            let at_exit_fn: ~fn(*libc::c_void) = |p|cleanup_task_local_map(p);
            *at_exit = Some(at_exit_fn);
            return map;
        }
    }
}

unsafe fn key_to_key_value<T:Durable>(
    key: LocalDataKey<T>) -> *libc::c_void {

    // Keys are closures, which are (fnptr,envptr) pairs. Use fnptr.
    // Use reintepret_cast -- transmute would leak (forget) the closure.
    let pair: (*libc::c_void, *libc::c_void) = cast::transmute(key);
    pair.first()
}

// If returning Some(..), returns with @T with the map's reference. Careful!
unsafe fn local_data_lookup<T:Durable>(
    map: TaskLocalMap, key: LocalDataKey<T>)
    -> Option<(uint, *libc::c_void)> {

    let key_value = key_to_key_value(key);
    let map_pos = (*map).position(|entry|
        match *entry {
            Some((k,_,_)) => k == key_value,
            None => false
        }
    );
    do map_pos.map |index| {
        // .get() is guaranteed because of "None { false }" above.
        let (_, data_ptr, _) = (*map)[*index].get();
        (*index, data_ptr)
    }
}

unsafe fn local_get_helper<T:Durable>(
    handle: Handle, key: LocalDataKey<T>,
    do_pop: bool) -> Option<@T> {

    let map = get_local_map(handle);
    // Interpreturn our findings from the map
    do local_data_lookup(map, key).map |result| {
        // A reference count magically appears on 'data' out of thin air. It
        // was referenced in the local_data box, though, not here, so before
        // overwriting the local_data_box we need to give an extra reference.
        // We must also give an extra reference when not removing.
        let (index, data_ptr) = *result;
        let data: @T = cast::transmute(data_ptr);
        cast::bump_box_refcount(data);
        if do_pop {
            map[index] = None;
        }
        data
    }
}

pub unsafe fn local_pop<T:Durable>(
    handle: Handle,
    key: LocalDataKey<T>) -> Option<@T> {

    local_get_helper(handle, key, true)
}

pub unsafe fn local_get<T:Durable>(
    handle: Handle,
    key: LocalDataKey<T>) -> Option<@T> {

    local_get_helper(handle, key, false)
}

pub unsafe fn local_set<T:Durable>(
    handle: Handle, key: LocalDataKey<T>, data: @T) {

    let map = get_local_map(handle);
    // Store key+data as *voids. Data is invisibly referenced once; key isn't.
    let keyval = key_to_key_value(key);
    // We keep the data in two forms: one as an unsafe pointer, so we can get
    // it back by casting; another in an existential box, so the reference we
    // own on it can be dropped when the box is destroyed. The unsafe pointer
    // does not have a reference associated with it, so it may become invalid
    // when the box is destroyed.
    let data_ptr = *cast::transmute::<&@T, &*libc::c_void>(&data);
    let data_box = @data as @LocalData;
    // Construct new entry to store in the map.
    let new_entry = Some((keyval, data_ptr, data_box));
    // Find a place to put it.
    match local_data_lookup(map, key) {
        Some((index, _old_data_ptr)) => {
            // Key already had a value set, _old_data_ptr, whose reference
            // will get dropped when the local_data box is overwritten.
            map[index] = new_entry;
        }
        None => {
            // Find an empty slot. If not, grow the vector.
            match (*map).position(|x| x.is_none()) {
                Some(empty_index) => { map[empty_index] = new_entry; }
                None => { map.push(new_entry); }
            }
        }
    }
}

pub unsafe fn local_modify<T:Durable>(
    handle: Handle, key: LocalDataKey<T>,
    modify_fn: &fn(Option<@T>) -> Option<@T>) {

    // Could be more efficient by doing the lookup work, but this is easy.
    let newdata = modify_fn(local_pop(handle, key));
    if newdata.is_some() {
        local_set(handle, key, newdata.unwrap());
    }
}
<|endoftext|>