<commit_before>use std::io:: { Error as IOError };
use std::convert::From;
use std::result:: { Result };
use std::collections:: { HashMap };
use std::default::Default;
use lcov_parser::parser:: { LCOVParser, RecordParseError };
use lcov_parser::record:: { LCOVRecord };

pub enum ParseError {
    IOError(IOError),
    RecordParseError(RecordParseError)
}

impl From<IOError> for ParseError {
    fn from(error: IOError) -> Self {
        ParseError::IOError(error)
    }
}

impl From<RecordParseError> for ParseError {
    fn from(error: RecordParseError) -> Self {
        ParseError::RecordParseError(error)
    }
}

pub fn records_from_file(file: &str) -> Result<Vec<LCOVRecord>, ParseError> {
    let parser = try!(LCOVParser::from_file(file));
    Ok(try!(parser.parse()))
}

//
// $testcount = $testdata->{$testname};
// $testfnccount = $testfncdata->{$testname};
// $testbrcount = $testbrdata->{$testname};
//

#[derive(Clone)]
struct Test {
    test_count: HashMap<u32, u32>, // key: line number, value: test count
    test_fn_count: HashMap<String, u32>, // key: function name, value: line number
    test_br_count: u32 // FIXME br data structure
}

impl Default for Test {
    fn default() -> Self {
        Test {
            test_count: HashMap::new(),
            test_fn_count: HashMap::new(),
            test_br_count: 0
        }
    }
}

// my $sumcount
// my $sumbrcount
// my $sumfnccount
struct SumCount {
    sum_count: HashMap<i32, i32>, // key: line number, value: count
    sum_br_count: HashMap<String, i32>, // key: function name, value: execution count
    sum_fn_count: i32 // FIXME br data structure
}

struct ReportParser {
    test_name: Option<String>,
    source_name: Option<String>,
    test: Option<Test>,
    tests: HashMap<String, Test>,
    sum: SumCount
}

impl ReportParser {
    fn parse(&mut self, file: &str) -> Result<(), ParseError> {
        let records = try!(records_from_file(file));

        for record in records.iter() {
            match record {
                &LCOVRecord::TestName(ref name) => self.on_test_name(name),
                &LCOVRecord::SourceFile(ref name) => self.on_source_file(name),
                _ => { continue; }
            };
        }
        Ok(())
    }
    fn on_test_name(&mut self, test_name: &Option<String>) {
        self.test_name = test_name.clone();
    }
    fn on_source_file(&mut self, source_name: &String) {
        self.source_name = Some(source_name.clone());

        match self.test_name {
            Some(ref current_test_name) => {
                if !self.tests.contains_key(current_test_name) {
                    self.tests.insert(current_test_name.to_string(), Test::default());
                }
                let test = self.tests.get(current_test_name);
                self.test = Some(test.unwrap().clone());
            },
            None => self.test = Some(Test::default())
        }
    }
}
<commit_msg>parse data record<commit_after>use std::io:: { Error as IOError };
use std::convert::From;
use std::result:: { Result };
use std::collections:: { HashMap };
use std::default::Default;
use lcov_parser::parser:: { LCOVParser, RecordParseError };
use lcov_parser::record:: { LCOVRecord };

pub enum ParseError {
    IOError(IOError),
    RecordParseError(RecordParseError)
}

impl From<IOError> for ParseError {
    fn from(error: IOError) -> Self {
        ParseError::IOError(error)
    }
}

impl From<RecordParseError> for ParseError {
    fn from(error: RecordParseError) -> Self {
        ParseError::RecordParseError(error)
    }
}

pub fn records_from_file(file: &str) -> Result<Vec<LCOVRecord>, ParseError> {
    let parser = try!(LCOVParser::from_file(file));
    Ok(try!(parser.parse()))
}

//
// $testcount = $testdata->{$testname};
// $testfnccount = $testfncdata->{$testname};
// $testbrcount = $testbrdata->{$testname};
//

#[derive(Clone)]
struct Test {
    test_count: HashMap<u32, u32>, // key: line number, value: test count
    test_fn_count: HashMap<String, u32>, // key: function name, value: line number
    test_br_count: u32 // FIXME br data structure
}

impl Default for Test {
    fn default() -> Self {
        Test {
            test_count: HashMap::new(),
            test_fn_count: HashMap::new(),
            test_br_count: 0
        }
    }
}

// my $sumcount
// my $sumbrcount
// my $sumfnccount
struct SumCount {
    sum_count: HashMap<u32, u32>, // key: line number, value: count
    sum_br_count: HashMap<String, u32>, // key: function name, value: execution count
    sum_fn_count: u32 // FIXME br data structure
}

// key: line_number, value: checksum value
type CheckSum = HashMap<u32, String>;

struct ReportParser {
    test_name: Option<String>,
    source_name: Option<String>,
    test: Option<Test>,
    tests: HashMap<String, Test>,
    sum: SumCount,
    checksum: CheckSum
}

impl ReportParser {
    fn parse(&mut self, file: &str) -> Result<(), ParseError> {
        let records = try!(records_from_file(file));

        for record in records.iter() {
            match record {
                &LCOVRecord::TestName(ref name) => self.on_test_name(name),
                &LCOVRecord::SourceFile(ref name) => self.on_source_file(name),
                &LCOVRecord::Data(ref line_number, ref execution_count, ref checksum) => self.on_data(
                    line_number,
                    execution_count,
                    checksum,
                ),
                _ => { continue; }
            };
        }
        Ok(())
    }
    fn on_test_name(&mut self, test_name: &Option<String>) {
        self.test_name = test_name.clone();
    }
    fn on_source_file(&mut self, source_name: &String) {
        self.source_name = Some(source_name.clone());

        match self.test_name {
            Some(ref current_test_name) => {
                // $testcount = $testdata->{$testname};
                // $testfnccount = $testfncdata->{$testname};
                // $testbrcount = $testbrdata->{$testname};
                if !self.tests.contains_key(current_test_name) {
                    self.tests.insert(current_test_name.to_string(), Test::default());
                }
                let test = self.tests.get(current_test_name);
                self.test = Some(test.unwrap().clone());
            },
            None => self.test = Some(Test::default())
        }
    }
    fn on_data(&mut self, line_number: &u32, execution_count: &u32, checksum: &Option<String>) {
        let mut sum_count = self.sum.sum_count.entry(line_number.clone()).or_insert(0);
        *sum_count += *execution_count;

        if self.test_name.is_some() {
            if self.test.is_some() {
                let mut test = self.test.as_mut().unwrap();
                let mut test_count = test.test_count.entry(line_number.clone()).or_insert(0);
                *test_count += *execution_count;
            }
        }

        if checksum.is_none() {
            return;
        }

        if !self.checksum.contains_key(line_number) {
            let checksum_value = checksum.clone().unwrap();
            self.checksum.insert(line_number.clone(), checksum_value);
            return;
        }

        let checksum_value = checksum.clone().unwrap();
        let current_checksum = self.checksum.get(line_number).unwrap();
        if current_checksum != &checksum_value {
            println!("{} {}", current_checksum, checksum_value);
        }
    }
}
<|endoftext|>


<commit_before>use crate::exception::Exception;
use alloc::boxed::Box;
use alloc::string::{String, ToString};
use core::fmt::Display;
use core::ptr::{self, NonNull};
use core::result::Result as StdResult;
use core::slice;
use core::str;

#[repr(C)]
#[derive(Copy, Clone)]
struct PtrLen {
    ptr: NonNull<u8>,
    len: usize,
}

#[repr(C)]
pub union Result {
    err: PtrLen,
    ok: *const u8, // null
}

pub unsafe fn r#try<T, E>(ret: *mut T, result: StdResult<T, E>) -> Result
where
    E: Display,
{
    match result {
        Ok(ok) => {
            ptr::write(ret, ok);
            Result { ok: ptr::null() }
        }
        Err(err) => to_c_error(err.to_string()),
    }
}

unsafe fn to_c_error(msg: String) -> Result {
    let mut msg = msg;
    msg.as_mut_vec().push(b'\0');
    let ptr = msg.as_ptr();
    let len = msg.len();

    extern "C" {
        #[link_name = "cxxbridge1$error"]
        fn error(ptr: *const u8, len: usize) -> *const u8;
    }

    let copy = error(ptr, len);
    let slice = slice::from_raw_parts(copy, len);
    let string = str::from_utf8_unchecked(slice);
    let err = PtrLen {
        ptr: NonNull::from(string).cast::<u8>(),
        len: string.len(),
    };
    Result { err }
}

impl Result {
    pub unsafe fn exception(self) -> StdResult<(), Exception> {
        if self.ok.is_null() {
            Ok(())
        } else {
            let err = self.err;
            let slice = slice::from_raw_parts_mut(err.ptr.as_ptr(), err.len);
            let s = str::from_utf8_unchecked_mut(slice);
            Err(Exception {
                what: Box::from_raw(s),
            })
        }
    }
}
<commit_msg>Clean some unneeded string manipulation from exception conversion<commit_after>use crate::exception::Exception;
use alloc::boxed::Box;
use alloc::string::{String, ToString};
use core::fmt::Display;
use core::ptr::{self, NonNull};
use core::result::Result as StdResult;
use core::slice;
use core::str;

#[repr(C)]
#[derive(Copy, Clone)]
struct PtrLen {
    ptr: NonNull<u8>,
    len: usize,
}

#[repr(C)]
pub union Result {
    err: PtrLen,
    ok: *const u8, // null
}

pub unsafe fn r#try<T, E>(ret: *mut T, result: StdResult<T, E>) -> Result
where
    E: Display,
{
    match result {
        Ok(ok) => {
            ptr::write(ret, ok);
            Result { ok: ptr::null() }
        }
        Err(err) => to_c_error(err.to_string()),
    }
}

unsafe fn to_c_error(msg: String) -> Result {
    let mut msg = msg;
    msg.as_mut_vec().push(b'\0');
    let ptr = msg.as_ptr();
    let len = msg.len();

    extern "C" {
        #[link_name = "cxxbridge1$error"]
        fn error(ptr: *const u8, len: usize) -> *const u8;
    }

    let copy = error(ptr, len);
    let err = PtrLen {
        ptr: NonNull::new_unchecked(copy as *mut u8),
        len,
    };
    Result { err }
}

impl Result {
    pub unsafe fn exception(self) -> StdResult<(), Exception> {
        if self.ok.is_null() {
            Ok(())
        } else {
            let err = self.err;
            let slice = slice::from_raw_parts_mut(err.ptr.as_ptr(), err.len);
            let s = str::from_utf8_unchecked_mut(slice);
            Err(Exception {
                what: Box::from_raw(s),
            })
        }
    }
}
<|endoftext|>


<commit_before>//!Server configuration and instance.

#![stable]

use std;
use std::collections::HashMap;
use std::sync::RwLock;
use std::old_io::net::ip::{IpAddr, Ipv4Addr, Port};
use std::borrow::ToOwned;

use time::{self, Timespec};

use url::percent_encoding::lossy_utf8_percent_decode;

use hyper;
use hyper::server::Handler as HyperHandler;
use hyper::header::{Headers, Date, ContentType, ContentLength};
use hyper::mime::Mime;
use hyper::uri::RequestUri;

pub use hyper::server::Listening;

use StatusCode;

use context::{self, Context};
use plugin::{ContextPlugin, ContextAction, ResponsePlugin};
use router::Router;
use cache::Cache;
use handler::Handler;
use response::Response;
use log::{Log, StdOut};
use Protocol;

use utils;

///Used to build and run a server.
///
///Each field has a corresponding modifier method and
///calls to these methods can be chained for quick setup.
///
///```no_run
///# use std::error::Error;
///# use rustful::{Server, Handler, Context, Response};
///# struct R;
///# impl Handler for R {
///#     type Cache = ();
///#     fn handle_request(&self, _context: Context, _response: Response) {}
///# }
///# let router = R;
///let server_result = Server::new().port(8080).handlers(router).run();
///
///match server_result {
///    Ok(_server) => {},
///    Err(e) => println!("could not start server: {}", e.description())
///}
///```
pub struct Server<R, C> {
    ///One or several response handlers.
    pub handlers: R,

    ///The port where the server will listen for requests.
    pub port: Port,

    ///The host address where the server will listen for requests.
    pub host: IpAddr,

    ///The type of HTTP protocol.
    pub protocol: Protocol,

    ///The number of threads to be used in the server task pool.
    ///The default (`None`) is based on recommendations from the system.
    pub threads: Option<usize>,

    ///The content of the server header.
    pub server: String,

    ///The default media type.
    pub content_type: Mime,

    ///A structure where resources are cached.
    pub cache: C,

    ///How often the cache should be cleaned. Measured in seconds.
    pub cache_clean_interval: Option<i64>,

    ///Tool for printing to a log.
    pub log: Box<Log + Send + Sync>,

    ///The context plugin stack.
    #[unstable]
    pub context_plugins: Vec<Box<ContextPlugin<Cache=C> + Send + Sync>>,

    ///The response plugin stack.
    #[unstable]
    pub response_plugins: Vec<Box<ResponsePlugin + Send + Sync>>
}

impl Server<(), ()> {
    ///Create a new empty server which will listen on host address `0.0.0.0` and port `80`.
    pub fn new() -> Server<(), ()> {
        Server::with_cache(())
    }
}

impl<C: Cache> Server<(), C> {
    ///Create a new empty server with a cache.
    pub fn with_cache(cache: C) -> Server<(), C> {
        Server {
            handlers: (),
            port: 80,
            host: Ipv4Addr(0, 0, 0, 0),
            protocol: Protocol::Http,
            threads: None,
            server: "rustful".to_owned(),
            content_type: Mime(
                hyper::mime::TopLevel::Text,
                hyper::mime::SubLevel::Plain,
                vec![(hyper::mime::Attr::Charset, hyper::mime::Value::Utf8)]
            ),
            cache: cache,
            cache_clean_interval: None,
            log: Box::new(StdOut) as Box<Log + Send + Sync>,
            context_plugins: Vec::new(),
            response_plugins: Vec::new()
        }
    }
}

impl<R, C> Server<R, C> {
    ///Set request handlers.
    pub fn handlers<NewRouter: Router<Handler=H>, H: Handler<Cache=C>>(self, handlers: NewRouter) -> Server<NewRouter, C> {
        Server {
            handlers: handlers,
            port: self.port,
            host: self.host,
            protocol: self.protocol,
            threads: self.threads,
            server: self.server,
            content_type: self.content_type,
            cache: self.cache,
            cache_clean_interval: self.cache_clean_interval,
            log: self.log,
            context_plugins: self.context_plugins,
            response_plugins: self.response_plugins,
        }
    }

    ///Change the port. Default is `80`.
    pub fn port(mut self, port: Port) -> Server<R, C> {
        self.port = port;
        self
    }

    ///Change the host address. Default is `0.0.0.0`.
    pub fn host(mut self, host: IpAddr) -> Server<R, C> {
        self.host = host;
        self
    }

    ///Change the protocol to HTTPS.
    pub fn https(mut self, cert: Path, key: Path) -> Server<R, C> {
        self.protocol = Protocol::Https {
            cert: cert,
            key: key
        };
        self
    }

    ///Set the number of threads to be used in the server task pool.
    ///
    ///Passing `None` will set it to the default number of threads,
    ///based on recommendations from the system.
    pub fn threads(mut self, threads: Option<usize>) -> Server<R, C> {
        self.threads = threads;
        self
    }

    ///Set the minimal number of seconds between each cache clean.
    ///
    ///Passing `None` disables cache cleaning.
    pub fn cache_clean_interval(mut self, interval: Option<u32>) -> Server<R, C> {
        self.cache_clean_interval = interval.map(|i| i as i64);
        self
    }

    ///Change the server response header. Default is `rustful`.
    pub fn server_name(mut self, name: String) -> Server<R, C> {
        self.server = name;
        self
    }

    ///Change the default content type. Default is `text/plain`.
    pub fn content_type(mut self, content_type: Mime) -> Server<R, C> {
        self.content_type = content_type;
        self
    }

    ///Change log tool. Default is to print to standard output.
    pub fn log<L: Log + Send + Sync>(mut self, log: L) -> Server<R, C> {
        self.log = Box::new(log) as Box<Log + Send + Sync>;
        self
    }

    ///Add a context plugin to the plugin stack.
    #[unstable]
    pub fn with_context_plugin<P: ContextPlugin<Cache=C> + Send + Sync>(mut self, plugin: P) ->  Server<R, C> {
        self.context_plugins.push(Box::new(plugin) as Box<ContextPlugin<Cache=C> + Send + Sync>);
        self
    }

    ///Add a response plugin to the plugin stack.
    #[unstable]
    pub fn with_response_plugin<P: ResponsePlugin + Send + Sync>(mut self, plugin: P) ->  Server<R, C> {
        self.response_plugins.push(Box::new(plugin) as Box<ResponsePlugin + Send + Sync>);
        self
    }
}

impl<R, H, C> Server<R, C>
    where
    R: Router<Handler=H> + Send + Sync,
    H: Handler<Cache=C> + Send + Sync,
    C: Cache + Send + Sync
{
    ///Start the server.
    pub fn run(self) -> hyper::HttpResult<Listening> {
        let threads = self.threads;
        let (server, protocol) = self.build();
        let http = match protocol {
            Protocol::Http => hyper::server::Server::http(server.host, server.port),
            Protocol::Https {cert, key} => hyper::server::Server::https(server.host, server.port, cert, key)
        };

        match threads {
            Some(threads) => http.listen_threads(server, threads),
            None => http.listen(server)
        }
    }

    ///Build a runnable instance of the server.
    pub fn build(self) -> (ServerInstance<R, C>, Protocol) {
        (ServerInstance {
            handlers: self.handlers,
            port: self.port,
            host: self.host,
            server: self.server,
            content_type: self.content_type,
            cache: self.cache,
            cache_clean_interval: self.cache_clean_interval,
            last_cache_clean: RwLock::new(Timespec::new(0, 0)),
            log: self.log,
            context_plugins: self.context_plugins,
            response_plugins: self.response_plugins,
        },
        self.protocol)
    }
}

///A runnable instance of a server.
///
///It's not meant to be used directly,
///unless additional control is required.
///
///```no_run
///# use rustful::{Server, Handler, Context, Response};
///# struct R;
///# impl Handler for R {
///#     type Cache = ();
///#     fn handle_request(&self, _context: Context, _response: Response) {}
///# }
///# let router = R;
///let (server_instance, protocol) = Server::new().port(8080).handlers(router).build();
///```
pub struct ServerInstance<R, C> {
    handlers: R,

    port: Port,
    host: IpAddr,

    server: String,
    content_type: Mime,

    cache: C,
    cache_clean_interval: Option<i64>,
    last_cache_clean: RwLock<Timespec>,

    log: Box<Log + Send + Sync>,

    context_plugins: Vec<Box<ContextPlugin<Cache=C> + Send + Sync>>,
    response_plugins: Vec<Box<ResponsePlugin + Send + Sync>>
}

impl<R, C: Cache> ServerInstance<R, C> {

    fn modify_context(&self, context: &mut Context<C>) -> ContextAction {
        let mut result = ContextAction::Continue;

        for plugin in &self.context_plugins {
            result = match result {
                ContextAction::Continue => plugin.modify(&*self.log, context),
                _ => return result
            };
        }

        result
    }

}

impl<R, H, C> HyperHandler for ServerInstance<R, C>
    where
    R: Router<Handler=H> + Send + Sync,
    H: Handler<Cache=C> + Send + Sync,
    C: Cache + Send + Sync,
{
    fn handle(&self, mut request: hyper::server::request::Request, writer: hyper::server::response::Response) {
        let request_uri = request.uri.clone();
        let request_method = request.method.clone();
        let mut request_headers = Headers::new();
        std::mem::swap(&mut request_headers, &mut request.headers);

        let mut response = Response::new(writer, &self.response_plugins, &*self.log);
        response.set_header(Date(time::now_utc()));
        response.set_header(ContentType(self.content_type.clone()));
        response.set_header(hyper::header::Server(self.server.clone()));

        let path_components = match request_uri {
            RequestUri::AbsoluteUri(url) => {
                Some((
                    url.serialize_path().map(|p| p.into_bytes()).unwrap_or_else(|| vec!['/' as u8]),
                    url.query_pairs().unwrap_or_else(|| Vec::new()).into_iter().collect(),
                    url.fragment
                ))
            },
            RequestUri::AbsolutePath(path) => {
                let (path, query, fragment) = parse_path(path);
                Some((path.into_bytes(), query, fragment))
            },
            _ => None //TODO: Handle *
        };

        match path_components {
            Some((path, query, fragment)) => {

                let mut context = Context {
                    headers: request_headers,
                    method: request_method,
                    path: lossy_utf8_percent_decode(&path),
                    variables: HashMap::new(),
                    query: query,
                    fragment: fragment,
                    cache: &self.cache,
                    log: &*self.log,
                    body_reader: context::BodyReader::from_request(request)
                };

                match self.modify_context(&mut context) {
                    ContextAction::Continue => {
                        match self.handlers.find(&context.method, &context.path) {
                            Some((handler, variables)) => {
                                context.variables = variables;
                                handler.handle_request(context, response);
                            },
                            None => {
                                response.set_header(ContentLength(0));
                                response.set_status(StatusCode::NotFound);
                            }
                        }
                    },
                    ContextAction::Abort(status) => {
                        response.set_header(ContentLength(0));
                        response.set_status(status);
                    }
                }
            },
            None => {
                response.set_header(ContentLength(0));
                response.set_status(StatusCode::BadRequest);
            }
        }

        self.cache_clean_interval.map(|t| {
            let clean_time = {
                let last_cache_clean = self.last_cache_clean.read().unwrap();
                Timespec::new(last_cache_clean.sec + t, last_cache_clean.nsec)
            };

            if time::get_time() > clean_time {
                *self.last_cache_clean.write().unwrap() = time::get_time();
                self.cache.free_unused(&*self.log);
            }
        });
    }
}

fn parse_path(path: String) -> (String, HashMap<String, String>, Option<String>) {
    match path.find('?') {
        Some(index) => {
            let (query, fragment) = parse_fragment(&path[index+1..]);
            (path[..index].to_owned(), utils::parse_parameters(query.as_bytes()), fragment.map(|f| f.to_owned()))
        },
        None => {
            let (path, fragment) = parse_fragment(&path);
            (path.to_owned(), HashMap::new(), fragment.map(|f| f.to_owned()))
        }
    }
}

fn parse_fragment<'a>(path: &'a str) -> (&'a str, Option<&'a str>) {
    match path.find('#') {
        Some(index) => (&path[..index], Some(&path[index+1..])),
        None => (path, None)
    }
}

#[test]
fn parse_path_parts() {
    let with = "this".to_owned();
    let and = "that".to_owned();
    let (path, query, fragment) = parse_path(String::from_str("/path/to/something?with=this&and=that#lol"));
    assert_eq!(path, String::from_str("/path/to/something"));
    assert_eq!(query.get("with"), Some(&with));
    assert_eq!(query.get("and"), Some(&and));
    assert_eq!(fragment, Some(String::from_str("lol")));
}

#[test]
fn parse_strange_path() {
    let with = "this".to_owned();
    let and = "what?".to_owned();
    let (path, query, fragment) = parse_path(String::from_str("/path/to/something?with=this&and=what?#"));
    assert_eq!(path, String::from_str("/path/to/something"));
    assert_eq!(query.get("with"), Some(&with));
    assert_eq!(query.get("and"), Some(&and));
    assert_eq!(fragment, Some(String::from_str("")));
}

#[test]
fn parse_missing_path_parts() {
    let with = "this".to_owned();
    let and = "that".to_owned();
    let (path, query, fragment) = parse_path(String::from_str("/path/to/something?with=this&and=that"));
    assert_eq!(path, String::from_str("/path/to/something"));
    assert_eq!(query.get("with"), Some(&with));
    assert_eq!(query.get("and"), Some(&and));
    assert_eq!(fragment, None);

    let (path, query, fragment) = parse_path(String::from_str("/path/to/something#lol"));
    assert_eq!(path, String::from_str("/path/to/something"));
    assert_eq!(query.len(), 0);
    assert_eq!(fragment, Some(String::from_str("lol")));

    let (path, query, fragment) = parse_path(String::from_str("?with=this&and=that#lol"));
    assert_eq!(path, String::from_str(""));
    assert_eq!(query.get("with"), Some(&with));
    assert_eq!(query.get("and"), Some(&and));
    assert_eq!(fragment, Some(String::from_str("lol")));
}<commit_msg>Update lifetimes for Send changes<commit_after>//!Server configuration and instance.

#![stable]

use std;
use std::collections::HashMap;
use std::sync::RwLock;
use std::old_io::net::ip::{IpAddr, Ipv4Addr, Port};
use std::borrow::ToOwned;

use time::{self, Timespec};

use url::percent_encoding::lossy_utf8_percent_decode;

use hyper;
use hyper::server::Handler as HyperHandler;
use hyper::header::{Headers, Date, ContentType, ContentLength};
use hyper::mime::Mime;
use hyper::uri::RequestUri;

pub use hyper::server::Listening;

use StatusCode;

use context::{self, Context};
use plugin::{ContextPlugin, ContextAction, ResponsePlugin};
use router::Router;
use cache::Cache;
use handler::Handler;
use response::Response;
use log::{Log, StdOut};
use Protocol;

use utils;

///Used to build and run a server.
///
///Each field has a corresponding modifier method and
///calls to these methods can be chained for quick setup.
///
///```no_run
///# use std::error::Error;
///# use rustful::{Server, Handler, Context, Response};
///# struct R;
///# impl Handler for R {
///#     type Cache = ();
///#     fn handle_request(&self, _context: Context, _response: Response) {}
///# }
///# let router = R;
///let server_result = Server::new().port(8080).handlers(router).run();
///
///match server_result {
///    Ok(_server) => {},
///    Err(e) => println!("could not start server: {}", e.description())
///}
///```
pub struct Server<R, C> {
    ///One or several response handlers.
    pub handlers: R,

    ///The port where the server will listen for requests.
    pub port: Port,

    ///The host address where the server will listen for requests.
    pub host: IpAddr,

    ///The type of HTTP protocol.
    pub protocol: Protocol,

    ///The number of threads to be used in the server task pool.
    ///The default (`None`) is based on recommendations from the system.
    pub threads: Option<usize>,

    ///The content of the server header.
    pub server: String,

    ///The default media type.
    pub content_type: Mime,

    ///A structure where resources are cached.
    pub cache: C,

    ///How often the cache should be cleaned. Measured in seconds.
    pub cache_clean_interval: Option<i64>,

    ///Tool for printing to a log.
    pub log: Box<Log + Send + Sync>,

    ///The context plugin stack.
    #[unstable]
    pub context_plugins: Vec<Box<ContextPlugin<Cache=C> + Send + Sync>>,

    ///The response plugin stack.
    #[unstable]
    pub response_plugins: Vec<Box<ResponsePlugin + Send + Sync>>
}

impl Server<(), ()> {
    ///Create a new empty server which will listen on host address `0.0.0.0` and port `80`.
    pub fn new() -> Server<(), ()> {
        Server::with_cache(())
    }
}

impl<C: Cache> Server<(), C> {
    ///Create a new empty server with a cache.
    pub fn with_cache(cache: C) -> Server<(), C> {
        Server {
            handlers: (),
            port: 80,
            host: Ipv4Addr(0, 0, 0, 0),
            protocol: Protocol::Http,
            threads: None,
            server: "rustful".to_owned(),
            content_type: Mime(
                hyper::mime::TopLevel::Text,
                hyper::mime::SubLevel::Plain,
                vec![(hyper::mime::Attr::Charset, hyper::mime::Value::Utf8)]
            ),
            cache: cache,
            cache_clean_interval: None,
            log: Box::new(StdOut) as Box<Log + Send + Sync>,
            context_plugins: Vec::new(),
            response_plugins: Vec::new()
        }
    }
}

impl<R, C> Server<R, C> {
    ///Set request handlers.
    pub fn handlers<NewRouter: Router<Handler=H>, H: Handler<Cache=C>>(self, handlers: NewRouter) -> Server<NewRouter, C> {
        Server {
            handlers: handlers,
            port: self.port,
            host: self.host,
            protocol: self.protocol,
            threads: self.threads,
            server: self.server,
            content_type: self.content_type,
            cache: self.cache,
            cache_clean_interval: self.cache_clean_interval,
            log: self.log,
            context_plugins: self.context_plugins,
            response_plugins: self.response_plugins,
        }
    }

    ///Change the port. Default is `80`.
    pub fn port(mut self, port: Port) -> Server<R, C> {
        self.port = port;
        self
    }

    ///Change the host address. Default is `0.0.0.0`.
    pub fn host(mut self, host: IpAddr) -> Server<R, C> {
        self.host = host;
        self
    }

    ///Change the protocol to HTTPS.
    pub fn https(mut self, cert: Path, key: Path) -> Server<R, C> {
        self.protocol = Protocol::Https {
            cert: cert,
            key: key
        };
        self
    }

    ///Set the number of threads to be used in the server task pool.
    ///
    ///Passing `None` will set it to the default number of threads,
    ///based on recommendations from the system.
    pub fn threads(mut self, threads: Option<usize>) -> Server<R, C> {
        self.threads = threads;
        self
    }

    ///Set the minimal number of seconds between each cache clean.
    ///
    ///Passing `None` disables cache cleaning.
    pub fn cache_clean_interval(mut self, interval: Option<u32>) -> Server<R, C> {
        self.cache_clean_interval = interval.map(|i| i as i64);
        self
    }

    ///Change the server response header. Default is `rustful`.
    pub fn server_name(mut self, name: String) -> Server<R, C> {
        self.server = name;
        self
    }

    ///Change the default content type. Default is `text/plain`.
    pub fn content_type(mut self, content_type: Mime) -> Server<R, C> {
        self.content_type = content_type;
        self
    }

    ///Change log tool. Default is to print to standard output.
    pub fn log<L: Log + Send + Sync + 'static>(mut self, log: L) -> Server<R, C> {
        self.log = Box::new(log) as Box<Log + Send + Sync>;
        self
    }

    ///Add a context plugin to the plugin stack.
    #[unstable]
    pub fn with_context_plugin<P: ContextPlugin<Cache=C> + Send + Sync + 'static>(mut self, plugin: P) ->  Server<R, C> {
        self.context_plugins.push(Box::new(plugin) as Box<ContextPlugin<Cache=C> + Send + Sync>);
        self
    }

    ///Add a response plugin to the plugin stack.
    #[unstable]
    pub fn with_response_plugin<P: ResponsePlugin + Send + Sync + 'static>(mut self, plugin: P) ->  Server<R, C> {
        self.response_plugins.push(Box::new(plugin) as Box<ResponsePlugin + Send + Sync>);
        self
    }
}

impl<R, H, C> Server<R, C>
    where
    R: Router<Handler=H> + Send + Sync + 'static,
    H: Handler<Cache=C> + Send + Sync + 'static,
    C: Cache + Send + Sync + 'static
{
    ///Start the server.
    pub fn run(self) -> hyper::HttpResult<Listening> {
        let threads = self.threads;
        let (server, protocol) = self.build();
        let http = match protocol {
            Protocol::Http => hyper::server::Server::http(server.host, server.port),
            Protocol::Https {cert, key} => hyper::server::Server::https(server.host, server.port, cert, key)
        };

        match threads {
            Some(threads) => http.listen_threads(server, threads),
            None => http.listen(server)
        }
    }

    ///Build a runnable instance of the server.
    pub fn build(self) -> (ServerInstance<R, C>, Protocol) {
        (ServerInstance {
            handlers: self.handlers,
            port: self.port,
            host: self.host,
            server: self.server,
            content_type: self.content_type,
            cache: self.cache,
            cache_clean_interval: self.cache_clean_interval,
            last_cache_clean: RwLock::new(Timespec::new(0, 0)),
            log: self.log,
            context_plugins: self.context_plugins,
            response_plugins: self.response_plugins,
        },
        self.protocol)
    }
}

///A runnable instance of a server.
///
///It's not meant to be used directly,
///unless additional control is required.
///
///```no_run
///# use rustful::{Server, Handler, Context, Response};
///# struct R;
///# impl Handler for R {
///#     type Cache = ();
///#     fn handle_request(&self, _context: Context, _response: Response) {}
///# }
///# let router = R;
///let (server_instance, protocol) = Server::new().port(8080).handlers(router).build();
///```
pub struct ServerInstance<R, C> {
    handlers: R,

    port: Port,
    host: IpAddr,

    server: String,
    content_type: Mime,

    cache: C,
    cache_clean_interval: Option<i64>,
    last_cache_clean: RwLock<Timespec>,

    log: Box<Log + Send + Sync>,

    context_plugins: Vec<Box<ContextPlugin<Cache=C> + Send + Sync>>,
    response_plugins: Vec<Box<ResponsePlugin + Send + Sync>>
}

impl<R, C: Cache> ServerInstance<R, C> {

    fn modify_context(&self, context: &mut Context<C>) -> ContextAction {
        let mut result = ContextAction::Continue;

        for plugin in &self.context_plugins {
            result = match result {
                ContextAction::Continue => plugin.modify(&*self.log, context),
                _ => return result
            };
        }

        result
    }

}

impl<R, H, C> HyperHandler for ServerInstance<R, C>
    where
    R: Router<Handler=H> + Send + Sync,
    H: Handler<Cache=C> + Send + Sync,
    C: Cache + Send + Sync,
{
    fn handle(&self, mut request: hyper::server::request::Request, writer: hyper::server::response::Response) {
        let request_uri = request.uri.clone();
        let request_method = request.method.clone();
        let mut request_headers = Headers::new();
        std::mem::swap(&mut request_headers, &mut request.headers);

        let mut response = Response::new(writer, &self.response_plugins, &*self.log);
        response.set_header(Date(time::now_utc()));
        response.set_header(ContentType(self.content_type.clone()));
        response.set_header(hyper::header::Server(self.server.clone()));

        let path_components = match request_uri {
            RequestUri::AbsoluteUri(url) => {
                Some((
                    url.serialize_path().map(|p| p.into_bytes()).unwrap_or_else(|| vec!['/' as u8]),
                    url.query_pairs().unwrap_or_else(|| Vec::new()).into_iter().collect(),
                    url.fragment
                ))
            },
            RequestUri::AbsolutePath(path) => {
                let (path, query, fragment) = parse_path(path);
                Some((path.into_bytes(), query, fragment))
            },
            _ => None //TODO: Handle *
        };

        match path_components {
            Some((path, query, fragment)) => {

                let mut context = Context {
                    headers: request_headers,
                    method: request_method,
                    path: lossy_utf8_percent_decode(&path),
                    variables: HashMap::new(),
                    query: query,
                    fragment: fragment,
                    cache: &self.cache,
                    log: &*self.log,
                    body_reader: context::BodyReader::from_request(request)
                };

                match self.modify_context(&mut context) {
                    ContextAction::Continue => {
                        match self.handlers.find(&context.method, &context.path) {
                            Some((handler, variables)) => {
                                context.variables = variables;
                                handler.handle_request(context, response);
                            },
                            None => {
                                response.set_header(ContentLength(0));
                                response.set_status(StatusCode::NotFound);
                            }
                        }
                    },
                    ContextAction::Abort(status) => {
                        response.set_header(ContentLength(0));
                        response.set_status(status);
                    }
                }
            },
            None => {
                response.set_header(ContentLength(0));
                response.set_status(StatusCode::BadRequest);
            }
        }

        self.cache_clean_interval.map(|t| {
            let clean_time = {
                let last_cache_clean = self.last_cache_clean.read().unwrap();
                Timespec::new(last_cache_clean.sec + t, last_cache_clean.nsec)
            };

            if time::get_time() > clean_time {
                *self.last_cache_clean.write().unwrap() = time::get_time();
                self.cache.free_unused(&*self.log);
            }
        });
    }
}

fn parse_path(path: String) -> (String, HashMap<String, String>, Option<String>) {
    match path.find('?') {
        Some(index) => {
            let (query, fragment) = parse_fragment(&path[index+1..]);
            (path[..index].to_owned(), utils::parse_parameters(query.as_bytes()), fragment.map(|f| f.to_owned()))
        },
        None => {
            let (path, fragment) = parse_fragment(&path);
            (path.to_owned(), HashMap::new(), fragment.map(|f| f.to_owned()))
        }
    }
}

fn parse_fragment<'a>(path: &'a str) -> (&'a str, Option<&'a str>) {
    match path.find('#') {
        Some(index) => (&path[..index], Some(&path[index+1..])),
        None => (path, None)
    }
}

#[test]
fn parse_path_parts() {
    let with = "this".to_owned();
    let and = "that".to_owned();
    let (path, query, fragment) = parse_path(String::from_str("/path/to/something?with=this&and=that#lol"));
    assert_eq!(path, String::from_str("/path/to/something"));
    assert_eq!(query.get("with"), Some(&with));
    assert_eq!(query.get("and"), Some(&and));
    assert_eq!(fragment, Some(String::from_str("lol")));
}

#[test]
fn parse_strange_path() {
    let with = "this".to_owned();
    let and = "what?".to_owned();
    let (path, query, fragment) = parse_path(String::from_str("/path/to/something?with=this&and=what?#"));
    assert_eq!(path, String::from_str("/path/to/something"));
    assert_eq!(query.get("with"), Some(&with));
    assert_eq!(query.get("and"), Some(&and));
    assert_eq!(fragment, Some(String::from_str("")));
}

#[test]
fn parse_missing_path_parts() {
    let with = "this".to_owned();
    let and = "that".to_owned();
    let (path, query, fragment) = parse_path(String::from_str("/path/to/something?with=this&and=that"));
    assert_eq!(path, String::from_str("/path/to/something"));
    assert_eq!(query.get("with"), Some(&with));
    assert_eq!(query.get("and"), Some(&and));
    assert_eq!(fragment, None);

    let (path, query, fragment) = parse_path(String::from_str("/path/to/something#lol"));
    assert_eq!(path, String::from_str("/path/to/something"));
    assert_eq!(query.len(), 0);
    assert_eq!(fragment, Some(String::from_str("lol")));

    let (path, query, fragment) = parse_path(String::from_str("?with=this&and=that#lol"));
    assert_eq!(path, String::from_str(""));
    assert_eq!(query.get("with"), Some(&with));
    assert_eq!(query.get("and"), Some(&and));
    assert_eq!(fragment, Some(String::from_str("lol")));
}<|endoftext|>


<commit_before>use std::result;

use futures::sync::oneshot;
use hyper::{Response, StatusCode};

use request::ParsedRequest;
use http_service::{empty_response, json_fault_message, json_response};
use super::{DeviceState, GenerateResponse, SyncRequest};

// This struct represents the strongly typed equivalent of the json body from drive
// related requests.
#[derive(Debug, Deserialize, Serialize)]
pub struct DriveDescription {
    pub drive_id: String,
    pub path_on_host: String,
    pub state: DeviceState,
    pub is_root_device: bool,
}

#[derive(Debug)]
pub enum DriveError {
    RootBlockDeviceAlreadyAdded,
    InvalidBlockDevicePath,
    BlockDevicePathAlreadyExists,
    NotImplemented,
}

impl GenerateResponse for DriveError {
    fn generate_response(&self) -> Response {
        use self::DriveError::*;
        match *self {
            RootBlockDeviceAlreadyAdded => json_response(
                StatusCode::BadRequest,
                json_fault_message("A root block device already exists!"),
            ),
            InvalidBlockDevicePath => json_response(
                StatusCode::BadRequest,
                json_fault_message("Invalid block device path!"),
            ),
            BlockDevicePathAlreadyExists => json_response(
                StatusCode::BadRequest,
                json_fault_message("The block device path was already added to a different drive!")
            ),
            NotImplemented => json_response(
                StatusCode::InternalServerError,
                json_fault_message("The update operation is not implemented!")
            ),
        }
    }
}

pub enum PutDriveOutcome {
    Created,
    Updated,
    Error(DriveError),
}

impl GenerateResponse for PutDriveOutcome {
    fn generate_response(&self) -> Response {
        use self::PutDriveOutcome::*;
        use self::DriveError::*;
        match *self {
            Created => empty_response(StatusCode::Created),
            Updated => empty_response(StatusCode::NoContent),
            Error(ref e) => e.generate_response(),
        }
    }
}

impl DriveDescription {
    pub fn into_parsed_request(self, _id_from_path: &str) -> result::Result<ParsedRequest, String> {
        // todo: any validation?
        let (sender, receiver) = oneshot::channel();
        Ok(ParsedRequest::Sync(
            SyncRequest::PutDrive(self, sender),
            receiver,
        ))
    }
}
<commit_msg>api server: error checking on PUT drive request<commit_after>use std::result;

use futures::sync::oneshot;
use hyper::{Response, StatusCode};

use request::ParsedRequest;
use http_service::{empty_response, json_fault_message, json_response};
use super::{DeviceState, GenerateResponse, SyncRequest};

// This struct represents the strongly typed equivalent of the json body from drive
// related requests.
#[derive(Debug, Deserialize, Serialize)]
pub struct DriveDescription {
    pub drive_id: String,
    pub path_on_host: String,
    pub state: DeviceState,
    pub is_root_device: bool,
}

#[derive(Debug)]
pub enum DriveError {
    RootBlockDeviceAlreadyAdded,
    InvalidBlockDevicePath,
    BlockDevicePathAlreadyExists,
    NotImplemented,
}

impl GenerateResponse for DriveError {
    fn generate_response(&self) -> Response {
        use self::DriveError::*;
        match *self {
            RootBlockDeviceAlreadyAdded => json_response(
                StatusCode::BadRequest,
                json_fault_message("A root block device already exists!"),
            ),
            InvalidBlockDevicePath => json_response(
                StatusCode::BadRequest,
                json_fault_message("Invalid block device path!"),
            ),
            BlockDevicePathAlreadyExists => json_response(
                StatusCode::BadRequest,
                json_fault_message("The block device path was already added to a different drive!")
            ),
            NotImplemented => json_response(
                StatusCode::InternalServerError,
                json_fault_message("The update operation is not implemented!")
            ),
        }
    }
}

pub enum PutDriveOutcome {
    Created,
    Updated,
    Error(DriveError),
}

impl GenerateResponse for PutDriveOutcome {
    fn generate_response(&self) -> Response {
        use self::PutDriveOutcome::*;
        use self::DriveError::*;
        match *self {
            Created => empty_response(StatusCode::Created),
            Updated => empty_response(StatusCode::NoContent),
            Error(ref e) => e.generate_response(),
        }
    }
}

impl DriveDescription {
    pub fn into_parsed_request(self, id_from_path: &str) -> result::Result<ParsedRequest, String> {
        if id_from_path != self.drive_id {
            return Err(String::from("The id from the path does not match the id from the path!"));
        }

        let (sender, receiver) = oneshot::channel();
        Ok(ParsedRequest::Sync(
            SyncRequest::PutDrive(self, sender),
            receiver,
        ))
    }
}
<|endoftext|>


<commit_before>use rustc::lint::{Context, LintPass, LintArray};
use std::cmp::Ordering;
use syntax::ast::{Mod, Item, Item_, Lit_, PathListItem_, ViewPath_, Visibility, MetaItem_};
use syntax::codemap::Span;
use syntax::print::pprust::path_to_string;

declare_lint!(UNSORTED_DECLARATIONS, Warn,
              "Warn when the declarations of crates or modules are not in alphabetical order");

pub struct Sorter;

impl LintPass for Sorter {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNSORTED_DECLARATIONS)
    }

    fn check_mod(&mut self, cx: &Context, module: &Mod, _span: Span, _id: u32) {
        let session_codemap = cx.tcx.sess.codemap();
        let mut extern_crates = Vec::new();
        let mut uses = Vec::new();
        let mut mods = Vec::new();
        for item in &module.items {
            let item_name = format!("{}", item.ident.name.as_str());
            let item_span = item.span;
            match item.node.clone() {
                Item_::ItemExternCrate(_) if item_name != "std" => {
                    let item_attrs = get_item_attrs(&item, false);
                    extern_crates.push((item_name, item_attrs, item_span, false));
                },
                Item_::ItemMod(module) => {
                    let mod_invoked_file = session_codemap.span_to_filename(item.span);
                    let mod_declared_file = session_codemap.span_to_filename(module.inner);
                    if mod_declared_file != mod_invoked_file {      // ignores inline modules
                        let item_attrs = get_item_attrs(&item, true);
                        mods.push((item_name, item_attrs, item_span, false));
                    }
                },
                Item_::ItemUse(spanned) => {
                    let item_attrs = get_item_attrs(&item, true);
                    match spanned.node {
                        ViewPath_::ViewPathSimple(ref ident, ref path) => {
                            let path_str = path_to_string(&path);
                            let name = ident.name.as_str();
                            let renamed = match path_str.ends_with(&*name) {
                                true => path_str,   // for checking `use foo as bar`
                                false => format!("{} as {}", &path_str, &name),
                            };
                            uses.push((renamed, item_attrs, item_span, false));
                        },
                        ViewPath_::ViewPathList(ref path, ref list) => {
                            let old_list = list
                                           .iter()
                                           .map(|&list_item| {
                                                match list_item.node {
                                                    PathListItem_::PathListMod { .. } =>
                                                        "self".to_owned(),
                                                    PathListItem_::PathListIdent { name, .. } => {
                                                        let interned = name.name.as_str();
                                                        let string = &*interned;
                                                        string.to_owned()
                                                    },
                                                }
                                            }).collect::<Vec<String>>();
                            let mut new_list = old_list.clone();
                            new_list.sort_by(|a, b| {
                                match (&**a, &**b) {    // `self` should be first in an use list
                                    ("self", _) => Ordering::Less,
                                    (_, "self") => Ordering::Greater,
                                    _ => a.cmp(b),
                                }
                            });
                            let mut warn = false;
                            for i in 0..old_list.len() {
                                if old_list[i] != new_list[i] {
                                    warn = true;
                                    break;
                                }
                            }
                            let use_list = format!("{}::{{{}}}", path_to_string(&path), new_list.connect(", "));
                            uses.push((use_list, item_attrs, path.span, warn));
                        },
                        ViewPath_::ViewPathGlob(ref path) => {
                            let path_str = path_to_string(&path) + "::*";
                            // we don't have any use statements like `use std::prelude::*`
                            // since it's done only by rustc, we can safely neglect those here
                            if !path_str.starts_with("std::") {
                                uses.push((path_str, item_attrs, item_span, false));
                            }
                        },
                    }
                },
                _ => (),
            }
        }

        check_sort(&extern_crates, cx, "crate declarations", "extern crate");
        check_sort(&mods, cx, "module declarations (ignoring the inline modules)", "mod");
        check_sort(&uses, cx, "use statements", "use");

        // for collecting, formatting & filtering the meta items, and checking the visibility
        fn get_item_attrs(item: &Item, pub_check: bool) -> String {
            let attr_vec = item.attrs
                           .iter()
                           .filter_map(|attr| {
                                let meta_item = attr.node.value.node.clone();
                                let meta_string = get_meta_as_string(&meta_item);
                                match meta_string.starts_with("doc = ") {
                                    true => None,
                                    false => Some(format!("#[{}]", meta_string)),
                                }
                           }).collect::<Vec<String>>();
            let attr_string = attr_vec.connect("\n");
            match item.vis {
                Visibility::Public if pub_check => {
                    match attr_string.is_empty() {
                        true => "pub ".to_owned(),
                        false => attr_string + "\npub ",    // `pub` for mods and uses
                    }
                },
                _ => {
                    match attr_string.is_empty() {
                        true => attr_string,
                        false => attr_string + "\n",
                    }
                },
            }
        }

        // recursively collect the information from meta items into Strings
        fn get_meta_as_string(meta_item: &MetaItem_) -> String {
            match *meta_item {
                MetaItem_::MetaWord(ref string) => format!("{}", string),
                MetaItem_::MetaList(ref string, ref meta_items) => {
                    let stuff = meta_items
                                .iter()
                                .map(|meta_item| {
                                    get_meta_as_string(&meta_item.node)
                                }).collect::<Vec<String>>();
                    format!("{}({})", string, stuff.connect(", "))
                },
                MetaItem_::MetaNameValue(ref string, ref literal) => {
                    let value = match literal.node {
                        Lit_::LitStr(ref inner_str, _style) => inner_str,
                        _ => panic!("unexpected literal found for meta item!"),
                    }; format!("{} = \"{}\"", string, value)
                },
            }
        }

        // checks the sorting of all the declarations and raises warnings whenever necessary
        // takes a slice of tuples with a name, related attributes, spans and whether to warn for an unordered use list
        fn check_sort(old_list: &[(String, String, Span, bool)], cx: &Context, kind: &str, syntax: &str) {
            let length = old_list.len();
            let mut new_list = old_list
                                .iter()
                                .map(|&(ref name, ref attrs, _span, warn)| (name.clone(), attrs.clone(), warn))
                                .collect::<Vec<(String, String, bool)>>();
            new_list.sort_by(|&(ref str_a, ref attr_a, _), &(ref str_b, ref attr_b, _)| {
                // a closure only to move the ordered `pub` statements to the bottom
                let new_str_a = "~".to_owned() + &str_a;    // since `~` is superior to almost all the ASCII chars
                let new_str_b = "~".to_owned() + &str_b;
                match (attr_a.ends_with("pub "), attr_b.ends_with("pub ")) {
                    (true, true) => new_str_a.cmp(&new_str_b),
                    (true, false) => new_str_a.cmp(str_b),
                    (false, true) => str_a.cmp(&new_str_b),
                    (false, false) => str_a.cmp(str_b),
                }
            });

            let mut index = 0;
            let mut span: Option<Span> = None;
            for i in 0..length {
                if (old_list[i].0 != new_list[i].0) || new_list[i].2 {
                    span = Some(old_list[i].2);
                    index = i;      // only to find the index of the first unsorted declaration
                    break;
                }
            }

            match span {
                Some(span_start) => {   // print all the declarations proceeding the first unsorted one
                    let suggestion_list = (index..length)
                                          .map(|i| {
                                              if i == length - 1 {  // increase the span to include more lines
                                                  let mut sp = span_start;
                                                  sp.hi = old_list[i].2.hi;
                                                  span = Some(sp);
                                              } format!("{}{} {};", new_list[i].1, syntax, new_list[i].0)
                                          }).collect::<Vec<String>>();
                    let suggestion = format!("{} should be in alphabetical order!\nTry this...\n\n{}\n\n",
                                            kind, suggestion_list.connect("\n"));
                    // unwrapping the value here, because it's certain there's something in `span`
                    cx.span_lint(UNSORTED_DECLARATIONS, span.unwrap(), &suggestion);
                },
                None => (),
            }
        }
    }
}
<commit_msg>preferring macro over other meta items...<commit_after>use rustc::lint::{Context, LintPass, LintArray};
use std::cmp::Ordering;
use syntax::ast::{Item, Item_, Lit_, MetaItem_, Mod, PathListItem_, ViewPath_, Visibility};
use syntax::codemap::Span;
use syntax::print::pprust::path_to_string;

declare_lint!(UNSORTED_DECLARATIONS, Warn,
              "Warn when the declarations of crates or modules are not in alphabetical order");

pub struct Sorter;

impl LintPass for Sorter {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNSORTED_DECLARATIONS)
    }

    fn check_mod(&mut self, cx: &Context, module: &Mod, _span: Span, _id: u32) {
        let session_codemap = cx.tcx.sess.codemap();
        let mut extern_crates = Vec::new();
        let mut uses = Vec::new();
        let mut mods = Vec::new();
        for item in &module.items {
            let item_name = format!("{}", item.ident.name.as_str());
            let item_span = item.span;
            match item.node.clone() {
                Item_::ItemExternCrate(_) if item_name != "std" => {
                    let item_attrs = get_item_attrs(&item, false);
                    extern_crates.push((item_name, item_attrs, item_span, false));
                },
                Item_::ItemMod(module) => {
                    let mod_invoked_file = session_codemap.span_to_filename(item.span);
                    let mod_declared_file = session_codemap.span_to_filename(module.inner);
                    if mod_declared_file != mod_invoked_file {      // ignores inline modules
                        let item_attrs = get_item_attrs(&item, true);
                        mods.push((item_name, item_attrs, item_span, false));
                    }
                },
                Item_::ItemUse(spanned) => {
                    let item_attrs = get_item_attrs(&item, true);
                    match spanned.node {
                        ViewPath_::ViewPathSimple(ref ident, ref path) => {
                            let path_str = path_to_string(&path);
                            let name = ident.name.as_str();
                            let renamed = match path_str.ends_with(&*name) {
                                true => path_str,   // for checking `use foo as bar`
                                false => format!("{} as {}", &path_str, &name),
                            };
                            uses.push((renamed, item_attrs, item_span, false));
                        },
                        ViewPath_::ViewPathList(ref path, ref list) => {
                            let old_list = list
                                           .iter()
                                           .map(|&list_item| {
                                                match list_item.node {
                                                    PathListItem_::PathListMod { .. } =>
                                                        "self".to_owned(),      // this must be `self`
                                                    PathListItem_::PathListIdent { name, .. } => {
                                                        // we don't have any renames inside brackets in servo
                                                        let interned = name.name.as_str();
                                                        let string = &*interned;
                                                        string.to_owned()
                                                    },
                                                }
                                            }).collect::<Vec<String>>();
                            let mut new_list = old_list.clone();
                            new_list.sort_by(|a, b| {
                                match (&**a, &**b) {    // `self` should be first in an use list
                                    ("self", _) => Ordering::Less,
                                    (_, "self") => Ordering::Greater,
                                    _ => a.cmp(b),
                                }
                            });
                            let mut warn = false;
                            for i in 0..old_list.len() {
                                if old_list[i] != new_list[i] {
                                    warn = true;
                                    break;
                                }
                            }
                            let use_list = format!("{}::{{{}}}", path_to_string(&path), new_list.connect(", "));
                            uses.push((use_list, item_attrs, path.span, warn));
                        },
                        ViewPath_::ViewPathGlob(ref path) => {
                            let path_str = path_to_string(&path) + "::*";
                            // we don't have any use statements like `use std::prelude::*`
                            // since it's done only by rustc, we can safely neglect those here
                            if !path_str.starts_with("std::") {
                                uses.push((path_str, item_attrs, item_span, false));
                            }
                        },
                    }
                },
                _ => (),
            }
        }

        check_sort(&extern_crates, cx, "crate declarations", "extern crate");
        check_sort(&mods, cx, "module declarations (other than inline modules)", "mod");
        check_sort(&uses, cx, "use statements", "use");

        // for collecting, formatting & filtering the attributes (and checking the visibility)
        fn get_item_attrs(item: &Item, pub_check: bool) -> String {
            let mut attr_vec = item.attrs
                               .iter()
                               .filter_map(|attr| {
                                   let meta_item = attr.node.value.node.clone();
                                   let meta_string = get_meta_as_string(&meta_item);
                                   match meta_string.starts_with("doc = ") {
                                       true => None,
                                       false => Some(format!("#[{}]", meta_string)),
                                   }
                               }).collect::<Vec<String>>();
            attr_vec.sort_by(|a, b| {
                match (&**a, &**b) {    // put `macro_use` first for later checking
                    ("#[macro_use]", _) => Ordering::Less,
                    (_, "#[macro_use]") => Ordering::Greater,
                    _ => a.cmp(b),
                }
            });
            let attr_string = attr_vec.connect("\n");
            match item.vis {
                Visibility::Public if pub_check => {
                    match attr_string.is_empty() {
                        true => "pub ".to_owned(),
                        false => attr_string + "\npub ",    // `pub` for mods and uses
                    }
                },
                _ => {
                    match attr_string.is_empty() {
                        true => attr_string,
                        false => attr_string + "\n",
                    }
                },
            }
        }

        // collect the information from meta items into Strings
        fn get_meta_as_string(meta_item: &MetaItem_) -> String {
            match *meta_item {
                MetaItem_::MetaWord(ref string) => format!("{}", string),
                MetaItem_::MetaList(ref string, ref meta_items) => {
                    let stuff = meta_items
                                .iter()
                                .map(|meta_item| {
                                    get_meta_as_string(&meta_item.node)
                                }).collect::<Vec<String>>();
                    format!("{}({})", string, stuff.connect(", "))
                },
                MetaItem_::MetaNameValue(ref string, ref literal) => {
                    let value = match literal.node {
                        Lit_::LitStr(ref inner_str, _style) => inner_str,
                        _ => panic!("unexpected literal found for meta item!"),
                    }; format!("{} = \"{}\"", string, value)
                },
            }
        }

        // checks the sorting of all the declarations and raises warnings whenever necessary
        // takes a slice of tuples with name, related attributes, spans and whether to warn for unordered use lists
        fn check_sort(old_list: &[(String, String, Span, bool)], cx: &Context, kind: &str, syntax: &str) {
            let length = old_list.len();
            let mut new_list = old_list
                                .iter()
                                .map(|&(ref name, ref attrs, _span, warn)| (name.clone(), attrs.clone(), warn))
                                .collect::<Vec<(String, String, bool)>>();
            new_list.sort_by(|&(ref str_a, ref attr_a, _), &(ref str_b, ref attr_b, _)| {
                // move the `pub` statements below (with `~` since it's on the farther side of ASCII)
                let mut new_str_a = str_for_biased_sort(&str_a, attr_a.ends_with("pub "), "~");
                let mut new_str_b = str_for_biased_sort(&str_b, attr_b.ends_with("pub "), "~");
                // move the #[macro_use] stuff above (with `!` since it's on the lower extreme of ASCII)
                new_str_a = str_for_biased_sort(&new_str_a, attr_a.starts_with("#[macro_use]"), "!");
                new_str_b = str_for_biased_sort(&new_str_b, attr_b.starts_with("#[macro_use]"), "!");
                new_str_a.cmp(&new_str_b)
            });

            let mut index = 0;
            let mut span: Option<Span> = None;
            for i in 0..length {
                if (old_list[i].0 != new_list[i].0) || new_list[i].2 {
                    span = Some(old_list[i].2);
                    index = i;      // only to find the index of the first unsorted declaration
                    break;          // because, we'll be printing everything following the first unsorted one
                }
            }

            match span {
                Some(span_start) => {   // print all the declarations proceeding the first unsorted one
                    let suggestion_list = (index..length)
                                          .map(|i| {
                                              if i == length - 1 {  // increase the span to include more lines
                                                  let mut sp = span_start;
                                                  sp.hi = old_list[i].2.hi;
                                                  span = Some(sp);
                                              } format!("{}{} {};", new_list[i].1, syntax, new_list[i].0)
                                          }).collect::<Vec<String>>();
                    let suggestion = format!("{} should be in alphabetical order!\nTry this...\n\n{}\n\n",
                                            kind, suggestion_list.connect("\n"));
                    // unwrapping the value here, because it's quite certain that there's something in `span`
                    cx.span_lint(UNSORTED_DECLARATIONS, span.unwrap(), &suggestion);
                },
                None => (),
            }

            // prepend given characters to names for biased sorting
            fn str_for_biased_sort(string: &String, choice: bool, prepend_char: &str) -> String {
                match choice {
                    true => prepend_char.to_owned() + &**string,
                    false => string.clone()
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use super::parse_module;

use core::semantic::ASTNode;

#[test]
fn test_basic_parse() {
    assert_eq!( parse_module("(+ 1 2)")
                    .unwrap()[0]
                    .to_sexpr(0)
              , "(+ 1 2)" )
}
<commit_msg>Parser tests import the right thing now (oops)<commit_after>use super::parse_module;

use core::semantic::ast::Node;

#[test]
fn test_basic_parse() {
    assert_eq!( parse_module("(+ 1 2)")
                    .unwrap()[0]
                    .to_sexpr(0)
              , "(+ 1 2)" )
}
<|endoftext|>


<commit_before>use syntax::ast;
use syntax::symbol::Symbol;

//////////////////////////////////////////////////////////////////////////////

pub trait ToSymbol {
    fn to_symbol(&self) -> Symbol;
}

impl ToSymbol for Symbol {
    fn to_symbol(&self) -> Symbol {
        self.clone()
    }
}

impl<'a> ToSymbol for &'a str {
    fn to_symbol(&self) -> Symbol {
        Symbol::intern(self)
    }
}

impl ToSymbol for ast::Ident {
    fn to_symbol(&self) -> Symbol {
        self.name
    }
}

impl<'a, T> ToSymbol for &'a T where T: ToSymbol {
    fn to_symbol(&self) -> Symbol {
        (**self).to_symbol()
    }
}

impl<'a, T> ToSymbol for &'a mut T where T: ToSymbol {
    fn to_symbol(&self) -> Symbol {
        (**self).to_symbol()
    }
}
<commit_msg>Implement ToSymbol for InternedString<commit_after>use syntax::ast;
use syntax::symbol::{InternedString, Symbol};

//////////////////////////////////////////////////////////////////////////////

pub trait ToSymbol {
    fn to_symbol(&self) -> Symbol;
}

impl ToSymbol for Symbol {
    fn to_symbol(&self) -> Symbol {
        self.clone()
    }
}

impl<'a> ToSymbol for &'a str {
    fn to_symbol(&self) -> Symbol {
        Symbol::intern(self)
    }
}

impl ToSymbol for ast::Ident {
    fn to_symbol(&self) -> Symbol {
        self.name
    }
}

impl ToSymbol for InternedString {
    fn to_symbol(&self) -> Symbol {
        Symbol::intern(self)
    }
}

impl<'a, T> ToSymbol for &'a T where T: ToSymbol {
    fn to_symbol(&self) -> Symbol {
        (**self).to_symbol()
    }
}

impl<'a, T> ToSymbol for &'a mut T where T: ToSymbol {
    fn to_symbol(&self) -> Symbol {
        (**self).to_symbol()
    }
}
<|endoftext|>


<commit_before>#![feature(phase)]
#![crate_name = "terrain"]

extern crate cgmath;
extern crate gfx;
#[phase(plugin)]
extern crate gfx_macros;
extern crate glfw;
extern crate native;
extern crate time;
extern crate genmesh;
extern crate noise;

use std::fmt;
use cgmath::FixedArray;
use cgmath::{Matrix4, Point3, Vector3};
use cgmath::{Transform, AffineMatrix3};
use gfx::{Device, DeviceHelper};
use glfw::Context;
use genmesh::{Vertices, Triangulate};
use genmesh::generators::{Plane, SharedVertex, IndexedPolygon};
use time::precise_time_s;

use noise::source::Perlin;
use noise::source::Source;

#[vertex_format]
struct Vertex {
    #[name = "a_Pos"]
    pos: [f32, ..3],

    #[name = "a_Color"]
    color: [f32, ..3],
}

impl Clone for Vertex {
    fn clone(&self) -> Vertex {
        Vertex { pos: self.pos, color: self.color }
    }
}

impl fmt::Show for Vertex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Pos({}, {}, {})", self.pos[0], self.pos[1], self.pos[2])
    }
}

// The shader_param attribute makes sure the following struct can be used to
// pass parameters to a shader. Its argument is the name of the type that will
// be generated to represent your the batch. Search for `Terrain` below, to see
// how it's used.
#[shader_param(Terrain)]
struct Params {
    #[name = "u_Model"]
    model: [[f32, ..4], ..4],

    #[name = "u_View"]
    view: [[f32, ..4], ..4],

    #[name = "u_Proj"]
    proj: [[f32, ..4], ..4],
}

static VERTEX_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120

    attribute vec3 a_Pos;
    attribute vec3 a_Color;
    varying vec3 v_Color;

    uniform mat4 u_Model;
    uniform mat4 u_View;
    uniform mat4 u_Proj;

    void main() {
        v_Color = a_Color;
        gl_Position = u_Proj * u_View * u_Model * vec4(a_Pos, 1.0);
    }
"
GLSL_150: b"
    #version 150 core

    in vec3 a_Pos;
    in vec3 a_Color;
    out vec3 v_Color;

    uniform mat4 u_Model;
    uniform mat4 u_View;
    uniform mat4 u_Proj;

    void main() {
        v_Color = a_Color;
        gl_Position = u_Proj * u_View * u_Model * vec4(a_Pos, 1.0);
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120

    varying vec3 v_Color;
    out vec4 o_Color;

    void main() {
        o_Color = vec4(v_Color, 1.0);
    }
"
GLSL_150: b"
    #version 150 core

    in vec3 v_Color;
    out vec4 o_Color;

    void main() {
        o_Color = vec4(v_Color, 1.0);
    }
"
};

// We need to run on the main thread, so ensure we are using the `native` runtime. This is
// technically not needed, since this is the default, but it's not guaranteed.
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
     native::start(argc, argv, main)
}

fn calculate_color(height: f32) -> [f32, ..3] {
    if height > 8.0 {
        [0.9, 0.9, 0.9] // white
    } else if height > 0.0 {
        [0.7, 0.7, 0.7] // greay
    } else if height > -5.0 {
        [0.2, 0.7, 0.2] // green
    } else {
        [0.2, 0.2, 0.7] // blue
    }
}

fn main() {
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(glfw::ContextVersion(3, 2));
    glfw.window_hint(glfw::OpenglForwardCompat(true));
    glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));

    let (window, events) = glfw
        .create_window(800, 600, "Terrain example", glfw::Windowed)
        .expect("Failed to create GLFW window.");

    window.make_current();
    glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
    window.set_key_polling(true);

    let (w, h) = window.get_framebuffer_size();
    let frame = gfx::Frame::new(w as u16, h as u16);

    let mut device = gfx::GlDevice::new(|s| glfw.get_proc_address(s));

    let noise = Perlin::new();
    let plane = Plane::subdivide(256, 256);
    let vertex_data: Vec<Vertex> = plane.shared_vertex_iter()
        .map(|(x, y)| {
            let h = noise.get(x, y, 0.0) * 32.0;
            Vertex {
                pos: [25.0 * x, 25.0 * y, h],
                color: calculate_color(h),
            }
        })
        .collect();

    let index_data: Vec<u32> = plane.indexed_polygon_iter()
        .triangulate()
        .vertices()
        .map(|i| i as u32)
        .collect();

    let slice = {
        let buf = device.create_buffer_static(&index_data);
        gfx::IndexSlice32(gfx::TriangleList, buf, 0, index_data.len() as u32)
    };

    let mesh = device.create_mesh(vertex_data);
    let program = device.link_program(VERTEX_SRC.clone(), FRAGMENT_SRC.clone())
                        .unwrap();
    let state = gfx::DrawState::new().depth(gfx::state::LessEqual, true);

    let mut graphics = gfx::Graphics::new(device);
    let batch: Terrain = graphics.make_batch(&mesh, slice, &program, &state).unwrap();

    let aspect = w as f32 / h as f32;
    let mut data = Params {
        model: Matrix4::identity().into_fixed(),
        view: Matrix4::identity().into_fixed(),
        proj: cgmath::perspective(cgmath::deg(60.0f32), aspect,
                                  0.1, 1000.0).into_fixed(),
    };

    let clear_data = gfx::ClearData {
        color: Some([0.3, 0.3, 0.3, 1.0]),
        depth: Some(1.0),
        stencil: None,
    };

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _) =>
                    window.set_should_close(true),
                _ => {},
            }
        }

        let time = precise_time_s() as f32;
        let x = time.sin();
        let y = time.cos();
        let view: AffineMatrix3<f32> = Transform::look_at(
            &Point3::new(x * 32.0, y * 32.0, 16.0),
            &Point3::new(0.0, 0.0, 0.0),
            &Vector3::unit_z(),
        );
        data.view = view.mat.into_fixed();

        graphics.clear(clear_data, &frame);
        graphics.draw(&batch, &data, &frame);
        graphics.end_frame();

        window.swap_buffers();
    }
}
<commit_msg>Randomized perlin noise seed in terrain example<commit_after>#![feature(phase)]
#![crate_name = "terrain"]

extern crate cgmath;
extern crate gfx;
#[phase(plugin)]
extern crate gfx_macros;
extern crate glfw;
extern crate native;
extern crate time;
extern crate genmesh;
extern crate noise;

use std::fmt;
use std::rand::Rng;
use cgmath::FixedArray;
use cgmath::{Matrix4, Point3, Vector3};
use cgmath::{Transform, AffineMatrix3};
use gfx::{Device, DeviceHelper};
use glfw::Context;
use genmesh::{Vertices, Triangulate};
use genmesh::generators::{Plane, SharedVertex, IndexedPolygon};
use time::precise_time_s;

use noise::source::Perlin;
use noise::source::Source;

#[vertex_format]
struct Vertex {
    #[name = "a_Pos"]
    pos: [f32, ..3],

    #[name = "a_Color"]
    color: [f32, ..3],
}

impl Clone for Vertex {
    fn clone(&self) -> Vertex {
        Vertex { pos: self.pos, color: self.color }
    }
}

impl fmt::Show for Vertex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Pos({}, {}, {})", self.pos[0], self.pos[1], self.pos[2])
    }
}

// The shader_param attribute makes sure the following struct can be used to
// pass parameters to a shader. Its argument is the name of the type that will
// be generated to represent your the batch. Search for `Terrain` below, to see
// how it's used.
#[shader_param(Terrain)]
struct Params {
    #[name = "u_Model"]
    model: [[f32, ..4], ..4],

    #[name = "u_View"]
    view: [[f32, ..4], ..4],

    #[name = "u_Proj"]
    proj: [[f32, ..4], ..4],
}

static VERTEX_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120

    attribute vec3 a_Pos;
    attribute vec3 a_Color;
    varying vec3 v_Color;

    uniform mat4 u_Model;
    uniform mat4 u_View;
    uniform mat4 u_Proj;

    void main() {
        v_Color = a_Color;
        gl_Position = u_Proj * u_View * u_Model * vec4(a_Pos, 1.0);
    }
"
GLSL_150: b"
    #version 150 core

    in vec3 a_Pos;
    in vec3 a_Color;
    out vec3 v_Color;

    uniform mat4 u_Model;
    uniform mat4 u_View;
    uniform mat4 u_Proj;

    void main() {
        v_Color = a_Color;
        gl_Position = u_Proj * u_View * u_Model * vec4(a_Pos, 1.0);
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource = shaders! {
GLSL_120: b"
    #version 120

    varying vec3 v_Color;
    out vec4 o_Color;

    void main() {
        o_Color = vec4(v_Color, 1.0);
    }
"
GLSL_150: b"
    #version 150 core

    in vec3 v_Color;
    out vec4 o_Color;

    void main() {
        o_Color = vec4(v_Color, 1.0);
    }
"
};

// We need to run on the main thread, so ensure we are using the `native` runtime. This is
// technically not needed, since this is the default, but it's not guaranteed.
#[start]
fn start(argc: int, argv: *const *const u8) -> int {
     native::start(argc, argv, main)
}

fn calculate_color(height: f32) -> [f32, ..3] {
    if height > 8.0 {
        [0.9, 0.9, 0.9] // white
    } else if height > 0.0 {
        [0.7, 0.7, 0.7] // greay
    } else if height > -5.0 {
        [0.2, 0.7, 0.2] // green
    } else {
        [0.2, 0.2, 0.7] // blue
    }
}

fn main() {
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(glfw::ContextVersion(3, 2));
    glfw.window_hint(glfw::OpenglForwardCompat(true));
    glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));

    let (window, events) = glfw
        .create_window(800, 600, "Terrain example", glfw::Windowed)
        .expect("Failed to create GLFW window.");

    window.make_current();
    glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
    window.set_key_polling(true);

    let (w, h) = window.get_framebuffer_size();
    let frame = gfx::Frame::new(w as u16, h as u16);

    let mut device = gfx::GlDevice::new(|s| glfw.get_proc_address(s));

    let rand_seed = std::rand::task_rng().gen();
    let noise = Perlin::new().seed(rand_seed);
    let plane = Plane::subdivide(256, 256);
    let vertex_data: Vec<Vertex> = plane.shared_vertex_iter()
        .map(|(x, y)| {
            let h = noise.get(x, y, 0.0) * 32.0;
            Vertex {
                pos: [25.0 * x, 25.0 * y, h],
                color: calculate_color(h),
            }
        })
        .collect();

    let index_data: Vec<u32> = plane.indexed_polygon_iter()
        .triangulate()
        .vertices()
        .map(|i| i as u32)
        .collect();

    let slice = {
        let buf = device.create_buffer_static(&index_data);
        gfx::IndexSlice32(gfx::TriangleList, buf, 0, index_data.len() as u32)
    };

    let mesh = device.create_mesh(vertex_data);
    let program = device.link_program(VERTEX_SRC.clone(), FRAGMENT_SRC.clone())
                        .unwrap();
    let state = gfx::DrawState::new().depth(gfx::state::LessEqual, true);

    let mut graphics = gfx::Graphics::new(device);
    let batch: Terrain = graphics.make_batch(&mesh, slice, &program, &state).unwrap();

    let aspect = w as f32 / h as f32;
    let mut data = Params {
        model: Matrix4::identity().into_fixed(),
        view: Matrix4::identity().into_fixed(),
        proj: cgmath::perspective(cgmath::deg(60.0f32), aspect,
                                  0.1, 1000.0).into_fixed(),
    };

    let clear_data = gfx::ClearData {
        color: Some([0.3, 0.3, 0.3, 1.0]),
        depth: Some(1.0),
        stencil: None,
    };

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _) =>
                    window.set_should_close(true),
                _ => {},
            }
        }

        let time = precise_time_s() as f32;
        let x = time.sin();
        let y = time.cos();
        let view: AffineMatrix3<f32> = Transform::look_at(
            &Point3::new(x * 32.0, y * 32.0, 16.0),
            &Point3::new(0.0, 0.0, 0.0),
            &Vector3::unit_z(),
        );
        data.view = view.mat.into_fixed();

        graphics.clear(clear_data, &frame);
        graphics.draw(&batch, &data, &frame);
        graphics.end_frame();

        window.swap_buffers();
    }
}
<|endoftext|>


<commit_before>use af;
use af::{Dim4, Array, AfBackend, MatProp};
use std::fmt;
use std::cell::RefCell;
use std::ops::{Add, Sub, Mul, Div};

use device::{Device, DeviceManager};

pub struct Tensor<'a> {
  array: Array,
  device: Device,
  manager: &'a DeviceManager,
}

impl<'a> Tensor<'a> {
  fn new(array: Array, manager: &DeviceManager
         , backend: AfBackend, device: i32) -> Tensor {
    Tensor { manager: manager
             , array: array
             , device: Device{ backend: backend, id: device } }
  }

  fn get(&self) -> &Array {
    self.manager.swap_device(self.device);
    &self.array
  }

  fn get_mut(&mut self) -> &mut Array {
    self.manager.swap_device(self.device);
    &mut self.array
  }

  fn set(&mut self, update: &Array) {
    self.manager.swap_device(self.device);
    self.array.clone_from(update);
  }

  fn batch_add(&self, other: &Tensor, batch: bool) -> Tensor<'a> {
    if (other.device != self.device) {
      panic!("add: can't mix between two different devices");
    }

    Tensor { array: af::add(&self.array, &other.array, batch).unwrap()
             , device: self.device
             , manager: self.manager }
  }

  fn batch_sub(&self, other: &Tensor, batch: bool) -> Tensor<'a> {
    if (other.device != self.device) {
      panic!("sub: can't mix between two different devices");
    }

    Tensor { array: af::sub(&self.array, &other.array, batch).unwrap()
             , device: self.device
             , manager: self.manager }
  }

  fn batch_mul(&self, other: &Tensor, batch: bool) -> Tensor<'a> {
    if (other.device != self.device) {
      panic!("mul: can't mix between two different devices");
    }

    Tensor { array: af::mul(&self.array, &other.array, batch).unwrap()
             , device: self.device
             , manager: self.manager }
  }

  fn batch_div(&self, other: &Tensor, batch: bool) -> Tensor<'a> {
    if (other.device != self.device) {
      panic!("div: can't mix between two different devices");
    }

    Tensor { array: af::div(&self.array, &other.array, batch).unwrap()
             , device: self.device
             , manager: self.manager }
  }

  fn matmul(&self, other: &Tensor, lhs_prop: MatProp, rhs_prop: MatProp) -> Tensor<'a>
  {
    if (other.device != self.device) {
      panic!("div: can't mix between two different devices");
    }

    Tensor { array: af::matmul(&self.array, &other.array, lhs_prop, rhs_prop).unwrap()
             , device: self.device
             , manager: self.manager }
  }
}

impl<'a> fmt::Debug for Tensor<'a> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{:?}\nbackend: {:?}, device: {}", self.array.dims().unwrap().get().clone()
           , self.device.backend, self.device.id)
  }
}

impl<'a> Clone for Tensor<'a> {
    fn clone(&self) -> Tensor<'a> {
      self.manager.swap_device(self.device);
      Tensor{
        array: self.array.clone(),
        device: self.device.clone(),
        manager: self.manager,
      }
    }
}

macro_rules! get_mut_param_vec_func {
  ($fn_name: ident, $vec_extension: ident, $base_type: ty) => (
    #[allow(unused_mut)]
    pub fn $fn_name(&mut self, layer_index: usize) -> &mut Vec<$base_type> {
      assert!(self.layer_storage.len() - 1 >= layer_index);
      &mut self.layer_storage[layer_index].$vec_extension
    }
    )
}

impl<'a> Add<Tensor<'a>> for Tensor<'a> {
  type Output = Tensor<'a>;
  fn add(self, other: Tensor) -> Tensor<'a> {
    self.batch_add(&self, &other, false)
  }
}

impl<'a> Sub<Tensor<'a>> for Tensor<'a> {
  type Output = Tensor<'a>;
  fn sub(self, other: Tensor) -> Tensor<'a> {
    self.batch_sub(&self, &other, false)
  }
}

impl<'a> Mul<Tensor<'a>> for Tensor<'a> {
  type Output = Tensor<'a>;
  fn mul(self, other: Tensor) -> Tensor<'a> {
    self.batch_mul(&self, &other, false)
  }
}

impl<'a> Div<Tensor<'a>> for Tensor<'a> {
  type Output = Tensor<'a>;
  fn div(self, other: Tensor) -> Tensor<'a> {
    self.batch_div(&self, &other, false)
  }
}

// TODO: Enable f64/u64, etc support separately
macro_rules! algebra_impl (
  ($operand: ident, $fn_name: ident, $foo: ty) => (
    impl<'a> $operand<$foo> for Tensor<'a> {
      type Output = Tensor<'a>;
      fn $fn_name(self, rhs: $foo) -> Tensor<'a> {
        let rhs_float = rhs as f32;
        Tensor { array: af::$fn_name(&self.array, &rhs_float, false).unwrap()
                 , device: self.device
                 , manager: self.manager }
      }
    }
    impl<'a> $operand<Tensor<'a>> for $foo {
      type Output = Tensor<'a>;
      fn $fn_name(self, rhs : Tensor) -> Tensor<'a> {
        let lhs_float = self as f32;
        Tensor { array: af::$fn_name(&lhs_float, &rhs.array, false).unwrap()
                 , device: rhs.device
                 , manager: rhs.manager<'a> }
      }
    }
    ));

algebra_impl!(Mul, mul, i8);
algebra_impl!(Mul, mul, i16);
algebra_impl!(Mul, mul, i32);
algebra_impl!(Mul, mul, i64);
algebra_impl!(Mul, mul, isize);
algebra_impl!(Mul, mul, usize);
algebra_impl!(Mul, mul, u8);
algebra_impl!(Mul, mul, u16);
algebra_impl!(Mul, mul, u32);
algebra_impl!(Mul, mul, u64);
algebra_impl!(Mul, mul, f32);
algebra_impl!(Mul, mul, f64);

algebra_impl!(Add, add, i8);
algebra_impl!(Add, add, i16);
algebra_impl!(Add, add, i32);
algebra_impl!(Add, add, i64);
algebra_impl!(Add, add, isize);
algebra_impl!(Add, add, usize);
algebra_impl!(Add, add, u8);
algebra_impl!(Add, add, u16);
algebra_impl!(Add, add, u32);
algebra_impl!(Add, add, u64);
algebra_impl!(Add, add, f32);
algebra_impl!(Add, add, f64);

algebra_impl!(Sub, sub, i8);
algebra_impl!(Sub, sub, i16);
algebra_impl!(Sub, sub, i32);
algebra_impl!(Sub, sub, i64);
algebra_impl!(Sub, sub, isize);
algebra_impl!(Sub, sub, usize);
algebra_impl!(Sub, sub, u8);
algebra_impl!(Sub, sub, u16);
algebra_impl!(Sub, sub, u32);
algebra_impl!(Sub, sub, u64);
algebra_impl!(Sub, sub, f32);
algebra_impl!(Sub, sub, f64);

algebra_impl!(Div, div, i8);
algebra_impl!(Div, div, i16);
algebra_impl!(Div, div, i32);
algebra_impl!(Div, div, i64);
algebra_impl!(Div, div, isize);
algebra_impl!(Div, div, usize);
algebra_impl!(Div, div, u8);
algebra_impl!(Div, div, u16);
algebra_impl!(Div, div, u32);
algebra_impl!(Div, div, u64);
algebra_impl!(Div, div, f32);
algebra_impl!(Div, div, f64);
<commit_msg>[building] the opposite from primitive to normal is an issue still. still using lifetimes<commit_after>use af;
use af::{Dim4, Array, AfBackend, MatProp};
use std::fmt;
use std::cell::RefCell;
use std::ops::{Add, Sub, Mul, Div};

use device::{Device, DeviceManager};

pub struct Tensor<'a> {
  array: Array,
  device: Device,
  manager: &'a DeviceManager,
}

impl<'a> Tensor<'a> {
  fn new(array: Array, manager: &DeviceManager
         , backend: AfBackend, device: i32) -> Tensor {
    Tensor { manager: manager
             , array: array
             , device: Device{ backend: backend, id: device } }
  }

  fn get(&self) -> &Array {
    self.manager.swap_device(self.device);
    &self.array
  }

  fn get_mut(&mut self) -> &mut Array {
    self.manager.swap_device(self.device);
    &mut self.array
  }

  fn set(&mut self, update: &Array) {
    self.manager.swap_device(self.device);
    self.array.clone_from(update);
  }

  fn batch_add(&self, other: &Tensor, batch: bool) -> Tensor<'a> {
    if (other.device != self.device) {
      panic!("add: can't mix between two different devices");
    }

    Tensor { array: af::add(&self.array, &other.array, batch).unwrap()
             , device: self.device
             , manager: self.manager }
  }

  fn batch_sub(&self, other: &Tensor, batch: bool) -> Tensor<'a> {
    if (other.device != self.device) {
      panic!("sub: can't mix between two different devices");
    }

    Tensor { array: af::sub(&self.array, &other.array, batch).unwrap()
             , device: self.device
             , manager: self.manager }
  }

  fn batch_mul(&self, other: &Tensor, batch: bool) -> Tensor<'a> {
    if (other.device != self.device) {
      panic!("mul: can't mix between two different devices");
    }

    Tensor { array: af::mul(&self.array, &other.array, batch).unwrap()
             , device: self.device
             , manager: self.manager }
  }

  fn batch_div(&self, other: &Tensor, batch: bool) -> Tensor<'a> {
    if (other.device != self.device) {
      panic!("div: can't mix between two different devices");
    }

    Tensor { array: af::div(&self.array, &other.array, batch).unwrap()
             , device: self.device
             , manager: self.manager }
  }

  fn matmul(&self, other: &Tensor, lhs_prop: MatProp, rhs_prop: MatProp) -> Tensor<'a>
  {
    if (other.device != self.device) {
      panic!("div: can't mix between two different devices");
    }

    Tensor { array: af::matmul(&self.array, &other.array, lhs_prop, rhs_prop).unwrap()
             , device: self.device
             , manager: self.manager }
  }
}

impl<'a> fmt::Debug for Tensor<'a> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{:?}\nbackend: {:?}, device: {}", self.array.dims().unwrap().get().clone()
           , self.device.backend, self.device.id)
  }
}

impl<'a> Clone for Tensor<'a> {
    fn clone(&self) -> Tensor<'a> {
      self.manager.swap_device(self.device);
      Tensor{
        array: self.array.clone(),
        device: self.device.clone(),
        manager: self.manager,
      }
    }
}

macro_rules! get_mut_param_vec_func {
  ($fn_name: ident, $vec_extension: ident, $base_type: ty) => (
    #[allow(unused_mut)]
    pub fn $fn_name(&mut self, layer_index: usize) -> &mut Vec<$base_type> {
      assert!(self.layer_storage.len() - 1 >= layer_index);
      &mut self.layer_storage[layer_index].$vec_extension
    }
    )
}

impl<'a> Add<Tensor<'a>> for Tensor<'a> {
  type Output = Tensor<'a>;
  fn add(self, other: Tensor) -> Tensor<'a> {
    self.batch_add(&other, false)
  }
}

impl<'a> Sub<Tensor<'a>> for Tensor<'a> {
  type Output = Tensor<'a>;
  fn sub(self, other: Tensor) -> Tensor<'a> {
    self.batch_sub(&other, false)
  }
}

impl<'a> Mul<Tensor<'a>> for Tensor<'a> {
  type Output = Tensor<'a>;
  fn mul(self, other: Tensor) -> Tensor<'a> {
    self.batch_mul(&other, false)
  }
}

impl<'a> Div<Tensor<'a>> for Tensor<'a> {
  type Output = Tensor<'a>;
  fn div(self, other: Tensor) -> Tensor<'a> {
    self.batch_div(&other, false)
  }
}

// TODO: Enable f64/u64, etc support separately
macro_rules! algebra_impl (
  ($operand: ident, $fn_name: ident, $foo: ty) => (
    impl<'a> $operand<$foo> for Tensor<'a> {
      type Output = Tensor<'a>;
      fn $fn_name(self, rhs: $foo) -> Tensor<'a> {
        let rhs_float = rhs as f32;
        Tensor { array: af::$fn_name(&self.array, &rhs_float, false).unwrap()
                 , device: self.device
                 , manager: self.manager }
      }
    }
    // impl<'a> $operand<Tensor<'a>> for $foo {
    //   type Output = Tensor<'a>;
    //   fn $fn_name(self, rhs : Tensor) -> Tensor<'a> {
    //     let lhs_float = self as f32;
    //     Tensor { array: af::$fn_name(&lhs_float, &rhs.array, false).unwrap()
    //              , device: rhs.device
    //              , manager: rhs.manager }
    //   }
    // }
    ));

algebra_impl!(Mul, mul, i8);
algebra_impl!(Mul, mul, i16);
algebra_impl!(Mul, mul, i32);
algebra_impl!(Mul, mul, i64);
algebra_impl!(Mul, mul, isize);
algebra_impl!(Mul, mul, usize);
algebra_impl!(Mul, mul, u8);
algebra_impl!(Mul, mul, u16);
algebra_impl!(Mul, mul, u32);
algebra_impl!(Mul, mul, u64);
algebra_impl!(Mul, mul, f32);
algebra_impl!(Mul, mul, f64);

algebra_impl!(Add, add, i8);
algebra_impl!(Add, add, i16);
algebra_impl!(Add, add, i32);
algebra_impl!(Add, add, i64);
algebra_impl!(Add, add, isize);
algebra_impl!(Add, add, usize);
algebra_impl!(Add, add, u8);
algebra_impl!(Add, add, u16);
algebra_impl!(Add, add, u32);
algebra_impl!(Add, add, u64);
algebra_impl!(Add, add, f32);
algebra_impl!(Add, add, f64);

algebra_impl!(Sub, sub, i8);
algebra_impl!(Sub, sub, i16);
algebra_impl!(Sub, sub, i32);
algebra_impl!(Sub, sub, i64);
algebra_impl!(Sub, sub, isize);
algebra_impl!(Sub, sub, usize);
algebra_impl!(Sub, sub, u8);
algebra_impl!(Sub, sub, u16);
algebra_impl!(Sub, sub, u32);
algebra_impl!(Sub, sub, u64);
algebra_impl!(Sub, sub, f32);
algebra_impl!(Sub, sub, f64);

algebra_impl!(Div, div, i8);
algebra_impl!(Div, div, i16);
algebra_impl!(Div, div, i32);
algebra_impl!(Div, div, i64);
algebra_impl!(Div, div, isize);
algebra_impl!(Div, div, usize);
algebra_impl!(Div, div, u8);
algebra_impl!(Div, div, u16);
algebra_impl!(Div, div, u32);
algebra_impl!(Div, div, u64);
algebra_impl!(Div, div, f32);
algebra_impl!(Div, div, f64);
<|endoftext|>