<commit_before>use to_str::to_str;
use ptr::addr_of;
use comm::{Port, Chan};
use result::{Result, Ok, Err};
use std::net::ip::{
    get_addr, format_addr,
    IpAddr, IpGetAddrErr, Ipv4, Ipv6
};
use std::net::tcp::{connect, TcpSocket};
use std::net::url;
use std::net::url::Url;
use std::uv_global_loop;
use connection::{
    Connection, ConnectionFactory, UvConnectionFactory,
    MockConnection, MockConnectionFactory
};
use parser::{Parser, ParserCallbacks};
use request::build_request;

const timeout: uint = 2000;

/// HTTP status codes
enum StatusCode {
    StatusOk = 200,
    StatusFound = 302,
    StatusUnknown
}

/// HTTP request error conditions
enum RequestError {
    ErrorDnsResolution,
    ErrorConnect,
    ErrorMisc
}

/// Request
enum RequestEvent {
    Status(StatusCode),
    Payload(~mut Option<~[u8]>),
    Error(RequestError)
}

impl StatusCode: cmp::Eq {
    pure fn eq(&&other: StatusCode) -> bool {
        self as uint == other as uint
    }
    pure fn ne(&&other: StatusCode) -> bool {
        self as uint != other as uint
    }
}

impl RequestError: cmp::Eq {
    pure fn eq(&&other: RequestError) -> bool {
        self as uint == other as uint
    }
    pure fn ne(&&other: RequestError) -> bool {
        self as uint != other as uint
    }
}

impl RequestEvent: cmp::Eq {
    pure fn eq(&&other: RequestEvent) -> bool {
        // FIXME: bad copy
        match (self, other) {
          (Status(a), Status(b)) => a == b,
          (Payload(a), Payload(b)) => a == b,
          (Error(a), Error(b)) => a == b,

          (Status(*), _)
          | (Payload(*), _)
          | (Error(*), _) => false
        }
    }
    pure fn ne(&&other: RequestEvent) -> bool {
        !self.eq(other)
    }
}

type DnsResolver = fn@(host: ~str) -> Result<~[IpAddr], IpGetAddrErr>;

fn uv_dns_resolver() -> DnsResolver {
    |host: ~str| {
        let iotask = uv_global_loop::get();
        get_addr(host.to_str(), iotask)
    }
}

fn uv_http_request(+url: Url) -> HttpRequest<TcpSocket, UvConnectionFactory> {
    HttpRequest(uv_dns_resolver(), UvConnectionFactory, url)
}

#[allow(non_implicitly_copyable_typarams)]
struct HttpRequest<C: Connection, CF: ConnectionFactory<C>> {
    resolve_ip_addr: DnsResolver,
    connection_factory: CF,
    url: Url,
    parser: Parser,
    mut cb: fn@(+RequestEvent)
}

fn HttpRequest<C: Connection, CF: ConnectionFactory<C>>(resolver: DnsResolver,
                                                        +connection_factory: CF,
                                                        +url: Url) ->
                                                        HttpRequest<C,CF> {
    HttpRequest {
        resolve_ip_addr: resolver,
        connection_factory: connection_factory,
        url: url,
        parser: Parser(),
        cb: |_event| { }
    }
}

impl<C: Connection, CF: ConnectionFactory<C>> HttpRequest<C, CF> {
    fn begin(cb: fn@(+RequestEvent)) {
        #debug("http_client: looking up url %?", self.url.to_str());
        let ip_addr = match self.get_ip() {
          Ok(addr) => { copy addr }
          Err(e) => { cb(Error(e)); return }
        };

        #debug("http_client: using IP %? for %?", format_addr(&ip_addr), self.url.to_str());

        let socket = {
            #debug("http_client: connecting to %?", ip_addr);
            let socket = self.connection_factory.connect(copy ip_addr, 80);
            if socket.is_ok() {
                result::unwrap(socket)
            } else {
                #debug("http_client: unable to connect to %?: %?", ip_addr, socket);
                cb(Error(ErrorConnect));
                return;
            }
        };

        #debug("http_client: got socket for %?", ip_addr);

        let request_header = build_request(self.url);
        #debug("http_client: writing request header: %?", request_header);
        let request_header_bytes = str::to_bytes(request_header);
        match socket.write_(request_header_bytes) {
          result::Ok(*) => { }
          result::Err(*) => {
            // FIXME: Need test
            cb(Error(ErrorMisc));
            return;
          }
        }

        let read_port = {
            let read_port = socket.read_start_();
            if read_port.is_ok() {
                result::unwrap(read_port)
            } else {
                cb(Error(ErrorMisc));
                return;
            }
        };

        // This unsafety is unfortunate but we can't capture self
        // into shared closures
        let unsafe_self = addr_of(self);
        let callbacks: ParserCallbacks = {
            on_message_begin: || unsafe { (*unsafe_self).on_message_begin() },
            on_url: |data| unsafe { (*unsafe_self).on_url(data) },
            on_header_field: |data| unsafe { (*unsafe_self).on_header_field(data) },
            on_header_value: |data| unsafe { (*unsafe_self).on_header_value(data) },
            on_headers_complete: || unsafe { (*unsafe_self).on_headers_complete() },
            on_body: |data| unsafe { (*unsafe_self).on_body(data) },
            on_message_complete: || unsafe { (*unsafe_self).on_message_complete() }
        };

        // Set the callback used by the parser event handlers
        self.cb = cb;

        loop {
            let next_data = read_port.recv();

            if next_data.is_ok() {
                let next_data = next_data.get();
                #debug("data: %?", next_data);
                let bytes_parsed = self.parser.execute(next_data, &callbacks);
                if bytes_parsed != next_data.len() {
                    // FIXME: Need tests
                    fail ~"http parse failure";
                }
            } else {
                #debug("http_client: read error: %?", next_data);

                // This method of detecting EOF is lame
                match next_data {
                  result::Err({err_name: ~"EOF", _}) => {
                    self.parser.execute(~[], &callbacks);
                    break;
                  }
                  _ => {
                    // FIXME: Need tests and error handling
                    socket.read_stop_(read_port);
                    cb(Error(ErrorMisc));
                    return;
                  }
                }
            }
        }
        socket.read_stop_(read_port);
    }

    fn get_ip() -> Result<IpAddr, RequestError> {
        let ip_addrs = self.resolve_ip_addr(self.url.host);
        if ip_addrs.is_ok() {
            let ip_addrs = result::unwrap(ip_addrs);
            // FIXME: This log crashes
            //#debug("http_client: got IP addresses for %?: %?", self.url, ip_addrs);
            if ip_addrs.is_not_empty() {
                // FIXME: Which address should we really pick?
                let best_ip = do ip_addrs.find |ip| {
                    match ip {
                      Ipv4(*) => { true }
                      Ipv6(*) => { false }
                    }
                };

                if best_ip.is_some() {
                    return Ok(option::unwrap(best_ip));
                } else {
                    // FIXME: Need test
                    return Err(ErrorMisc);
                }
            } else {
                #debug("http_client: got no IP addresses for %?", self.url);
                // FIXME: Need test
                return Err(ErrorMisc);
            }
        } else {
            #debug("http_client: DNS lookup failure: %?", ip_addrs.get_err());
            return Err(ErrorDnsResolution);
        }
    }

    fn on_message_begin() -> bool {
        #debug("on_message_begin");
        true
    }

    fn on_url(+_data: ~[u8]) -> bool {
        #debug("on_url");
        true
    }

    fn on_header_field(+data: ~[u8]) -> bool {
        let header_field = str::from_bytes(data);
        #debug("on_header_field: %?", header_field);
        true
    }

    fn on_header_value(+data: ~[u8]) -> bool {
        let header_value = str::from_bytes(data);
        #debug("on_header_value: %?", header_value);
        true
    }

    fn on_headers_complete() -> bool {
        #debug("on_headers_complete");
        true
    }

    fn on_body(+data: ~[u8]) -> bool {
        #debug("on_body");
        let the_payload = Payload(~mut Some(data));
        self.cb(the_payload);
        true
    }

    fn on_message_complete() -> bool {
        #debug("on_message_complete");
        true
    }
}

#[allow(non_implicitly_copyable_typarams)]
fn sequence<C: Connection, CF: ConnectionFactory<C>>(request: HttpRequest<C, CF>) ->
    ~[RequestEvent] {

    let events = @mut ~[];
    do request.begin |event| {
        vec::push(*events, event)
    }
    return copy *events;
}

#[test]
#[allow(non_implicitly_copyable_typarams)]
fn test_resolve_error() {
    let url = url::from_str(~"http://example.com_not_real/").get();
    let request = uv_http_request(url);
    let events = sequence(request);

    assert events == ~[
        Error(ErrorDnsResolution),
    ];
}

#[test]
#[allow(non_implicitly_copyable_typarams)]
fn test_connect_error() {
    // This address is invalid because the first octet
    // of a class A address cannot be 0
    let url = url::from_str(~"http://0.42.42.42/").get();
    let request = uv_http_request(url);
    let events = sequence(request);

    assert events == ~[
        Error(ErrorConnect),
    ];
}

#[test]
#[allow(non_implicitly_copyable_typarams)]
fn test_connect_success() {
    let url = url::from_str(~"http://example.com/").get();
    let request = uv_http_request(url);
    let events = sequence(request);

    for events.each |ev| {
        match ev {
          Error(*) => { fail }
          _ => { }
        }
    }
}

#[test]
#[allow(non_implicitly_copyable_typarams)]
fn test_simple_body() {
    let url = url::from_str(~"http://www.iana.org/").get();
    let request = uv_http_request(url);
    let events = sequence(request);

    let mut found = false;

    for events.each |ev| {
        match ev {
          Payload(value) => {
            if str::from_bytes(value.get()).contains(~"DOCTYPE html") {
                found = true
            }
          }
          _ => { }
        }
    }

    assert found;
}

#[test]
#[ignore(reason = "ICE")]
#[allow(non_implicitly_copyable_typarams)]
fn test_simple_response() {
    let _url = url::from_str(~"http://whatever/").get();
    let _mock_connection: MockConnection = {
        write_fn: |_data| { Ok(()) },
        read_start_fn: || {
            let port = Port();
            let chan = port.chan();

            let response = ~"HTTP/1.0 200 OK\
                            \
                            Test";
            chan.send(Ok(str::to_bytes(response)));

            Ok(port)
        },
        read_stop_fn: |_port| { Ok(()) }
    };

    let _mock_connection_factory: MockConnectionFactory = {
        connect_fn: |_ip, _port| {

            // FIXME this doesn't work
            fail;//ok(mock_connection)
        }
    };
}
<commit_msg>Fixes for library changes<commit_after>use to_str::to_str;
use ptr::addr_of;
use comm::{Port, Chan};
use result::{Result, Ok, Err};
use std::net::ip::{
    get_addr, format_addr,
    IpAddr, IpGetAddrErr, Ipv4, Ipv6
};
use std::net::tcp::{connect, TcpSocket};
use std::net::url;
use std::net::url::Url;
use std::uv_global_loop;
use connection::{
    Connection, ConnectionFactory, UvConnectionFactory,
    MockConnection, MockConnectionFactory
};
use parser::{Parser, ParserCallbacks};
use request::build_request;

const timeout: uint = 2000;

/// HTTP status codes
enum StatusCode {
    StatusOk = 200,
    StatusFound = 302,
    StatusUnknown
}

/// HTTP request error conditions
enum RequestError {
    ErrorDnsResolution,
    ErrorConnect,
    ErrorMisc
}

/// Request
enum RequestEvent {
    Status(StatusCode),
    Payload(~mut Option<~[u8]>),
    Error(RequestError)
}

impl StatusCode: cmp::Eq {
    pure fn eq(other: &StatusCode) -> bool {
        self as uint == (*other) as uint
    }
    pure fn ne(other: &StatusCode) -> bool {
        self as uint != (*other) as uint
    }
}

impl RequestError: cmp::Eq {
    pure fn eq(other: &RequestError) -> bool {
        self as uint == (*other) as uint
    }
    pure fn ne(other: &RequestError) -> bool {
        self as uint != (*other) as uint
    }
}

impl RequestEvent: cmp::Eq {
    pure fn eq(other: &RequestEvent) -> bool {
        // FIXME: bad copy
        match (self, *other) {
          (Status(a), Status(b)) => a == b,
          (Payload(a), Payload(b)) => a == b,
          (Error(a), Error(b)) => a == b,

          (Status(*), _)
          | (Payload(*), _)
          | (Error(*), _) => false
        }
    }
    pure fn ne(other: &RequestEvent) -> bool {
        !self.eq(other)
    }
}

type DnsResolver = fn@(host: ~str) -> Result<~[IpAddr], IpGetAddrErr>;

fn uv_dns_resolver() -> DnsResolver {
    |host: ~str| {
        let iotask = uv_global_loop::get();
        get_addr(host.to_str(), iotask)
    }
}

fn uv_http_request(+url: Url) -> HttpRequest<TcpSocket, UvConnectionFactory> {
    HttpRequest(uv_dns_resolver(), UvConnectionFactory, url)
}

#[allow(non_implicitly_copyable_typarams)]
struct HttpRequest<C: Connection, CF: ConnectionFactory<C>> {
    resolve_ip_addr: DnsResolver,
    connection_factory: CF,
    url: Url,
    parser: Parser,
    mut cb: fn@(+RequestEvent)
}

fn HttpRequest<C: Connection, CF: ConnectionFactory<C>>(resolver: DnsResolver,
                                                        +connection_factory: CF,
                                                        +url: Url) ->
                                                        HttpRequest<C,CF> {
    HttpRequest {
        resolve_ip_addr: resolver,
        connection_factory: connection_factory,
        url: url,
        parser: Parser(),
        cb: |_event| { }
    }
}

impl<C: Connection, CF: ConnectionFactory<C>> HttpRequest<C, CF> {
    fn begin(cb: fn@(+RequestEvent)) {
        #debug("http_client: looking up url %?", self.url.to_str());
        let ip_addr = match self.get_ip() {
          Ok(addr) => { copy addr }
          Err(e) => { cb(Error(e)); return }
        };

        #debug("http_client: using IP %? for %?", format_addr(&ip_addr), self.url.to_str());

        let socket = {
            #debug("http_client: connecting to %?", ip_addr);
            let socket = self.connection_factory.connect(copy ip_addr, 80);
            if socket.is_ok() {
                result::unwrap(socket)
            } else {
                #debug("http_client: unable to connect to %?: %?", ip_addr, socket);
                cb(Error(ErrorConnect));
                return;
            }
        };

        #debug("http_client: got socket for %?", ip_addr);

        let request_header = build_request(self.url);
        #debug("http_client: writing request header: %?", request_header);
        let request_header_bytes = str::to_bytes(request_header);
        match socket.write_(request_header_bytes) {
          result::Ok(*) => { }
          result::Err(*) => {
            // FIXME: Need test
            cb(Error(ErrorMisc));
            return;
          }
        }

        let read_port = {
            let read_port = socket.read_start_();
            if read_port.is_ok() {
                result::unwrap(read_port)
            } else {
                cb(Error(ErrorMisc));
                return;
            }
        };

        // This unsafety is unfortunate but we can't capture self
        // into shared closures
        let unsafe_self = addr_of(self);
        let callbacks: ParserCallbacks = {
            on_message_begin: || unsafe { (*unsafe_self).on_message_begin() },
            on_url: |data| unsafe { (*unsafe_self).on_url(data) },
            on_header_field: |data| unsafe { (*unsafe_self).on_header_field(data) },
            on_header_value: |data| unsafe { (*unsafe_self).on_header_value(data) },
            on_headers_complete: || unsafe { (*unsafe_self).on_headers_complete() },
            on_body: |data| unsafe { (*unsafe_self).on_body(data) },
            on_message_complete: || unsafe { (*unsafe_self).on_message_complete() }
        };

        // Set the callback used by the parser event handlers
        self.cb = cb;

        loop {
            let next_data = read_port.recv();

            if next_data.is_ok() {
                let next_data = next_data.get();
                #debug("data: %?", next_data);
                let bytes_parsed = self.parser.execute(next_data, &callbacks);
                if bytes_parsed != next_data.len() {
                    // FIXME: Need tests
                    fail ~"http parse failure";
                }
            } else {
                #debug("http_client: read error: %?", next_data);

                // This method of detecting EOF is lame
                match next_data {
                  result::Err({err_name: ~"EOF", _}) => {
                    self.parser.execute(~[], &callbacks);
                    break;
                  }
                  _ => {
                    // FIXME: Need tests and error handling
                    socket.read_stop_(read_port);
                    cb(Error(ErrorMisc));
                    return;
                  }
                }
            }
        }
        socket.read_stop_(read_port);
    }

    fn get_ip() -> Result<IpAddr, RequestError> {
        let ip_addrs = self.resolve_ip_addr(self.url.host);
        if ip_addrs.is_ok() {
            let ip_addrs = result::unwrap(ip_addrs);
            // FIXME: This log crashes
            //#debug("http_client: got IP addresses for %?: %?", self.url, ip_addrs);
            if ip_addrs.is_not_empty() {
                // FIXME: Which address should we really pick?
                let best_ip = do ip_addrs.find |ip| {
                    match ip {
                      Ipv4(*) => { true }
                      Ipv6(*) => { false }
                    }
                };

                if best_ip.is_some() {
                    return Ok(option::unwrap(best_ip));
                } else {
                    // FIXME: Need test
                    return Err(ErrorMisc);
                }
            } else {
                #debug("http_client: got no IP addresses for %?", self.url);
                // FIXME: Need test
                return Err(ErrorMisc);
            }
        } else {
            #debug("http_client: DNS lookup failure: %?", ip_addrs.get_err());
            return Err(ErrorDnsResolution);
        }
    }

    fn on_message_begin() -> bool {
        #debug("on_message_begin");
        true
    }

    fn on_url(+_data: ~[u8]) -> bool {
        #debug("on_url");
        true
    }

    fn on_header_field(+data: ~[u8]) -> bool {
        let header_field = str::from_bytes(data);
        #debug("on_header_field: %?", header_field);
        true
    }

    fn on_header_value(+data: ~[u8]) -> bool {
        let header_value = str::from_bytes(data);
        #debug("on_header_value: %?", header_value);
        true
    }

    fn on_headers_complete() -> bool {
        #debug("on_headers_complete");
        true
    }

    fn on_body(+data: ~[u8]) -> bool {
        #debug("on_body");
        let the_payload = Payload(~mut Some(data));
        self.cb(the_payload);
        true
    }

    fn on_message_complete() -> bool {
        #debug("on_message_complete");
        true
    }
}

#[allow(non_implicitly_copyable_typarams)]
fn sequence<C: Connection, CF: ConnectionFactory<C>>(request: HttpRequest<C, CF>) ->
    ~[RequestEvent] {

    let events = @mut ~[];
    do request.begin |event| {
        vec::push(*events, event)
    }
    return copy *events;
}

#[test]
#[allow(non_implicitly_copyable_typarams)]
fn test_resolve_error() {
    let url = url::from_str(~"http://example.com_not_real/").get();
    let request = uv_http_request(url);
    let events = sequence(request);

    assert events == ~[
        Error(ErrorDnsResolution),
    ];
}

#[test]
#[allow(non_implicitly_copyable_typarams)]
fn test_connect_error() {
    // This address is invalid because the first octet
    // of a class A address cannot be 0
    let url = url::from_str(~"http://0.42.42.42/").get();
    let request = uv_http_request(url);
    let events = sequence(request);

    assert events == ~[
        Error(ErrorConnect),
    ];
}

#[test]
#[allow(non_implicitly_copyable_typarams)]
fn test_connect_success() {
    let url = url::from_str(~"http://example.com/").get();
    let request = uv_http_request(url);
    let events = sequence(request);

    for events.each |ev| {
        match ev {
          Error(*) => { fail }
          _ => { }
        }
    }
}

#[test]
#[allow(non_implicitly_copyable_typarams)]
fn test_simple_body() {
    let url = url::from_str(~"http://www.iana.org/").get();
    let request = uv_http_request(url);
    let events = sequence(request);

    let mut found = false;

    for events.each |ev| {
        match ev {
          Payload(value) => {
            if str::from_bytes(value.get()).contains(~"DOCTYPE html") {
                found = true
            }
          }
          _ => { }
        }
    }

    assert found;
}

#[test]
#[ignore(reason = "ICE")]
#[allow(non_implicitly_copyable_typarams)]
fn test_simple_response() {
    let _url = url::from_str(~"http://whatever/").get();
    let _mock_connection: MockConnection = {
        write_fn: |_data| { Ok(()) },
        read_start_fn: || {
            let port = Port();
            let chan = port.chan();

            let response = ~"HTTP/1.0 200 OK\
                            \
                            Test";
            chan.send(Ok(str::to_bytes(response)));

            Ok(port)
        },
        read_stop_fn: |_port| { Ok(()) }
    };

    let _mock_connection_factory: MockConnectionFactory = {
        connect_fn: |_ip, _port| {

            // FIXME this doesn't work
            fail;//ok(mock_connection)
        }
    };
}
<|endoftext|>


<commit_before>//! Defines a PolynomialCalculator with common arithmetic operations, functions
//! and constants already defined.

use super::*;
use calculator::*;
use tokenizer::Tokenizer;
use evaluator::{Evaluator, Function};
use parser::{Parser, Operator, OperatorAssociativity};
use polynomial::Polynomial;
use std::f64::consts::{PI, E};

/// PolynomialCalculator is a calculator using a PolynomialParser and a PolynomialEvaluator
/// to provide multiple default operations.
///
/// This calculator supports addition `+`, subtraction `-`, multiplication `*`,
/// division `/` and exponentiation `^` operators, `log(number, base)`,
/// `log10(number)` and `bind(polynomial, double)` functions, `x`, `inf`, `nan`
/// symbols and `pi` and `e` constants.
///
/// While usage of the calculator is the easiest way of embedding computation
/// engine into your program, please note that a Tokenizer, PolynomialParser and
/// PolynomialEvaluator is created with each call, which requires reallocation
/// of memory.
///
/// # Examples
///
/// ```
/// # use xxcalc::polynomial_calculator::PolynomialCalculator;
/// # use xxcalc::polynomial::Polynomial;
/// # use xxcalc::calculator::Calculator;
/// # use std::f64::consts::PI;
///
/// assert_eq!(PolynomialCalculator.process("2+2"), Ok(Polynomial::constant(4.0)));
/// assert_eq!(PolynomialCalculator.process("(2+2)*-2"), Ok(Polynomial::constant(-8.0)));
/// assert_eq!(String::from(PolynomialCalculator.process("(x+1)*(-0.13x^18-x^7)").unwrap()), "-0.13x^19-0.13x^18-x^8-x^7");
/// assert_eq!(PolynomialCalculator.process("bind(pi*x^2, 10)"), Ok(Polynomial::constant(PI * 10.0 * 10.0)));
/// ```
pub struct PolynomialCalculator;

impl Calculator<Tokenizer, PolynomialParser, PolynomialEvaluator> for PolynomialCalculator {

}

/// Extends Evaluator with handlers for common operators and functions.
pub struct PolynomialEvaluator {
  /// Underlying evaluator (one can use it to extend it furthermore)
  pub evaluator: Evaluator
}

/// Creates PolynomialEvaluator and extends the basic Evaluator.
///
/// Handlers for common arithmetic operations, functions and some constants
/// are registered to the underlying evaluator.
impl Default for PolynomialEvaluator {
  fn default() -> PolynomialEvaluator {
    let mut evaluator = Evaluator::default();

    evaluator.register_constant("x", Polynomial::linear(0.0, 1.0)).unwrap();
    evaluator.register_constant("pi", Polynomial::constant(PI)).unwrap();
    evaluator.register_constant("e", Polynomial::constant(E)).unwrap();
    evaluator.register_constant("inf", Polynomial::constant(1.0f64 / 0.0f64)).unwrap();
    evaluator.register_constant("nan", Polynomial::constant(0.0f64 / 0.0f64)).unwrap();

    evaluator.register_function("+", Function::new(2, Box::new(functions::addition))).unwrap();
    evaluator.register_function("-", Function::new(2, Box::new(functions::subtraction))).unwrap();
    evaluator.register_function("*", Function::new(2, Box::new(functions::multiplication))).unwrap();
    evaluator.register_function("/", Function::new(2, Box::new(functions::division))).unwrap();
    evaluator.register_function("^", Function::new(2, Box::new(functions::exponentiation))).unwrap();

    evaluator.register_function("log", Function::new(2, Box::new(functions::log))).unwrap();
    evaluator.register_function("log10", Function::new(1, Box::new(functions::log10))).unwrap();
    evaluator.register_function("bind", Function::new(2, Box::new(functions::bind))).unwrap();

    PolynomialEvaluator {
      evaluator: evaluator
    }
  }
}

/// Allows usage of PolynomialEvaluator as common TokensReducer
impl TokensReducer for PolynomialEvaluator {
  fn process(&self, tokens: &Tokens) -> Result<Polynomial, EvaluationError> {
    self.evaluator.process(tokens)
  }
}

/// Extends Parser with common arithmetic operators with correct precedence
/// and associativity.
pub struct PolynomialParser {
  /// Underlying parser (one can use it to extend it furthermore)
  pub parser: Parser
}

/// Creates PolynomialParser and extends basic Parser.
///
/// Common arithmetic operators are registered with the Parser.
impl Default for PolynomialParser {
  fn default() -> PolynomialParser {
    let mut parser = Parser::default();

    parser.register_operator('+', Operator::new(1, OperatorAssociativity::Left));
    parser.register_operator('-', Operator::new(1, OperatorAssociativity::Left));
    parser.register_operator('*', Operator::new(5, OperatorAssociativity::Left));
    parser.register_operator('/', Operator::new(5, OperatorAssociativity::Left));
    parser.register_operator('^', Operator::new(10, OperatorAssociativity::Right));

    PolynomialParser {
      parser: parser
    }
  }
}

/// Allows usage of PolynomialParser as common TokensProcessor
impl TokensProcessor for PolynomialParser {
  fn process(&mut self, tokens: &Tokens) -> Result<&Tokens, ParsingError> {
    self.parser.process(tokens)
  }
}

/// Implementations of function handlers used in operators and functions.
///
/// This module is public, so when you are writing another evaluator, but
/// it does not extend PolynomialEvaluator, you can reuse these functions
/// as handlers for some of the common operations.
///
/// Operations that are directly defined on the Polynomial (such as addition,
/// subtraction, multiplication and division), avoid cloning by using
/// the assignment with operation, thus optimizing memory usage.
pub mod functions {
  use polynomial::Polynomial;
  use EvaluationError;

  /// Adds two polynomials together (requires two arguments).
  pub fn addition(mut args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    let b = args.pop().unwrap();
    let mut a = args.pop().unwrap();

    a += b;
    Ok(a)
  }

  /// Subtracts two polynomials from each other (requires two arguments).
  pub fn subtraction(mut args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    let b = args.pop().unwrap();
    let mut a = args.pop().unwrap();

    a -= b;
    Ok(a)
  }

  /// Multiplies two polynomials together (requires two arguments).
  pub fn multiplication(mut args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    let b = args.pop().unwrap();
    let mut a = args.pop().unwrap();

    a *= b;
    Ok(a)
  }

  /// Divides two polynomials by each other (requires two arguments).
  ///
  /// # Errors
  ///
  /// It will return a wrapped PolynomialError when a degree of divident is
  /// smaller than a degree of divisor or when a divident is non-constant
  /// polynomial, while a divisor is a zero.
  pub fn division(mut args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    let b = args.pop().unwrap();
    let mut a = args.pop().unwrap();

    match (&mut a) / &b {
      Ok(_) => Ok(a),
      Err(e) => Err(EvaluationError::PolynomialError(e))
    }
  }

  /// Computes a logarithm of arbitrary base (requires two constant arguments).
  ///
  /// First arguments is a value to have a logarithm computed on, where a second
  /// argument is a base of the logarithm.
  ///
  /// # Errors
  ///
  /// It will return a wrapped PolynomialError::NonConstantError when any of the
  /// arguments is not a constant polynomial (a polynomial of degree zero).
  pub fn log(args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    Ok(Polynomial::constant(try!(args[0].as_f64()).log(try!(args[1].as_f64()))))
  }

  /// Computes a decimal logarithm (requires a single constant argument).
  ///
  /// # Errors
  ///
  /// It will return a wrapped PolynomialError::NonConstantError when the argument
  /// is not a constant polynomial (a polynomial of degree zero).
  pub fn log10(args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    Ok(Polynomial::constant(try!(args[0].as_f64()).log10()))
  }

  /// Binds a polynomial with a value (requires two arguments).
  ///
  /// This function computes value of given polynomial (first argument) when
  /// the symbol is replaced with a constant value (second argument).
  ///
  /// # Errors
  ///
  /// It will return a wrapper PolynomialError::NonConstantError when the second
  /// argument is not a constant polynomial (a polynomial of degree zero).
  pub fn bind(args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    Ok(args[0].bind(try!(args[1].as_f64())))
  }

  /// Performs exponentiation of polynomial (requires two arguments).
  ///
  /// First argument is an exponentiation base, where second argument is
  /// the exponent (which must be a constant polynomial).
  pub fn exponentiation(mut args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    let exponent = args.pop().unwrap();
    let base = args.pop().unwrap();

    let base_degree = base.degree();
    let exponent_degree = exponent.degree();

    if exponent_degree > 0 {
      Err(EvaluationError::NonConstantExponent)
    } else
    if base_degree == 0 {
      Ok(Polynomial::constant(base[0].powf(exponent[0])))
    } else
    if exponent[0] >= 0.0 && exponent[0].fract() == 0.0 {
      if base_degree == 1 && base[0] == 0.0 {
        let mut v = Polynomial::zero();
        v[exponent[0] as usize] = base[1].powf(exponent[0]);

        Ok(v)
      } else {
        let mut v = base.clone();
        let exp = exponent[0] as usize;

        {
          let mut vr = &mut v;
          for _ in 1..exp {
            vr *= &base;
          }
        }

        Ok(v)
      }
    } else {
      Err(EvaluationError::NonNaturalExponent)
    }
  }
}

#[cfg(test)]
mod tests {
  use polynomial::{Polynomial, PolynomialError};
  use polynomial_calculator::PolynomialCalculator;
  use EvaluationError;
  use calculator::Calculator;
  use calculator::CalculationError;
  use std::f64::consts::{PI, E};

  #[test]
  fn test_general() {
    assert_eq!(PolynomialCalculator.process("(3+(4-1))*5"), Ok(Polynomial::constant(30.0)));
  }

  #[test]
  fn test_constants() {
    assert_eq!(PolynomialCalculator.process("x"), Ok(Polynomial::linear(0.0, 1.0)));
    assert_eq!(PolynomialCalculator.process("pi"), Ok(Polynomial::constant(PI)));
    assert_eq!(PolynomialCalculator.process("e"), Ok(Polynomial::constant(E)));
  }

  #[test]
  fn test_operations() {
    assert_eq!(PolynomialCalculator.process("1+1"), Ok(Polynomial::constant(2.0)));
    assert_eq!(PolynomialCalculator.process("1+-1"), Ok(Polynomial::constant(0.0)));

    assert_eq!(PolynomialCalculator.process("1-1"), Ok(Polynomial::constant(0.0)));
    assert_eq!(PolynomialCalculator.process("1-3"), Ok(Polynomial::constant(-2.0)));
    assert_eq!(PolynomialCalculator.process("1--1"), Ok(Polynomial::constant(2.0)));

    assert_eq!(PolynomialCalculator.process("2*4"), Ok(Polynomial::constant(8.0)));
    assert_eq!(PolynomialCalculator.process("2*0"), Ok(Polynomial::constant(0.0)));

    assert_eq!(PolynomialCalculator.process("2/4"), Ok(Polynomial::constant(0.5)));
    assert!(PolynomialCalculator.process("2/0").unwrap().as_f64().unwrap().is_infinite());
    assert!(PolynomialCalculator.process("0/0").unwrap().as_f64().unwrap().is_nan());

    assert_eq!(PolynomialCalculator.process("2^0"), Ok(Polynomial::constant(1.0)));
    assert_eq!(PolynomialCalculator.process("2^4"), Ok(Polynomial::constant(16.0)));
  }

  #[test]
  fn test_polynomials() {
    assert_eq!(PolynomialCalculator.process("2x+1"), Ok(Polynomial::new(&[1.0, 2.0])));
    assert_eq!(PolynomialCalculator.process("2x+4x"), Ok(Polynomial::new(&[0.0, 6.0])));
    assert_eq!(PolynomialCalculator.process("2x-2x-1"), Ok(Polynomial::new(&[-1.0])));
    assert_eq!(PolynomialCalculator.process("2x--2x"), Ok(Polynomial::new(&[0.0, 4.0])));
    assert_eq!(PolynomialCalculator.process("2x*4x"), Ok(Polynomial::new(&[0.0, 0.0, 8.0])));
    assert_eq!(PolynomialCalculator.process("2x*(4x+1)"), Ok(Polynomial::new(&[0.0, 2.0, 8.0])));
    assert_eq!(PolynomialCalculator.process("2x/x"), Ok(Polynomial::new(&[2.0])));
    assert_eq!(PolynomialCalculator.process("2x/0"), Err(CalculationError::EvaluationError(EvaluationError::PolynomialError(PolynomialError::DivisionByZero))));
    assert_eq!(PolynomialCalculator.process("2x/x^2"), Err(CalculationError::EvaluationError(EvaluationError::PolynomialError(PolynomialError::DividentDegreeMismatch))));
    assert_eq!(PolynomialCalculator.process("(x^2-3x-10)/(x+2)"), Ok(Polynomial::new(&[-5.0, 1.0])));
    assert_eq!(PolynomialCalculator.process("x^5"), Ok(Polynomial::new(&[0.0, 0.0, 0.0, 0.0, 0.0, 1.0])));
    assert_eq!(PolynomialCalculator.process("(x+1)^5"), Ok(Polynomial::new(&[1.0, 5.0, 10.0, 10.0, 5.0, 1.0])));
  }
}
<commit_msg>documented exponentiation, special case for exp0<commit_after>//! Defines a PolynomialCalculator with common arithmetic operations, functions
//! and constants already defined.

use super::*;
use calculator::*;
use tokenizer::Tokenizer;
use evaluator::{Evaluator, Function};
use parser::{Parser, Operator, OperatorAssociativity};
use polynomial::Polynomial;
use std::f64::consts::{PI, E};

/// PolynomialCalculator is a calculator using a PolynomialParser and a PolynomialEvaluator
/// to provide multiple default operations.
///
/// This calculator supports addition `+`, subtraction `-`, multiplication `*`,
/// division `/` and exponentiation `^` operators, `log(number, base)`,
/// `log10(number)` and `bind(polynomial, double)` functions, `x`, `inf`, `nan`
/// symbols and `pi` and `e` constants.
///
/// While usage of the calculator is the easiest way of embedding computation
/// engine into your program, please note that a Tokenizer, PolynomialParser and
/// PolynomialEvaluator is created with each call, which requires reallocation
/// of memory.
///
/// # Examples
///
/// ```
/// # use xxcalc::polynomial_calculator::PolynomialCalculator;
/// # use xxcalc::polynomial::Polynomial;
/// # use xxcalc::calculator::Calculator;
/// # use std::f64::consts::PI;
///
/// assert_eq!(PolynomialCalculator.process("2+2"), Ok(Polynomial::constant(4.0)));
/// assert_eq!(PolynomialCalculator.process("(2+2)*-2"), Ok(Polynomial::constant(-8.0)));
/// assert_eq!(String::from(PolynomialCalculator.process("(x+1)*(-0.13x^18-x^7)").unwrap()), "-0.13x^19-0.13x^18-x^8-x^7");
/// assert_eq!(PolynomialCalculator.process("bind(pi*x^2, 10)"), Ok(Polynomial::constant(PI * 10.0 * 10.0)));
/// ```
pub struct PolynomialCalculator;

impl Calculator<Tokenizer, PolynomialParser, PolynomialEvaluator> for PolynomialCalculator {

}

/// Extends Evaluator with handlers for common operators and functions.
pub struct PolynomialEvaluator {
  /// Underlying evaluator (one can use it to extend it furthermore)
  pub evaluator: Evaluator
}

/// Creates PolynomialEvaluator and extends the basic Evaluator.
///
/// Handlers for common arithmetic operations, functions and some constants
/// are registered to the underlying evaluator.
impl Default for PolynomialEvaluator {
  fn default() -> PolynomialEvaluator {
    let mut evaluator = Evaluator::default();

    evaluator.register_constant("x", Polynomial::linear(0.0, 1.0)).unwrap();
    evaluator.register_constant("pi", Polynomial::constant(PI)).unwrap();
    evaluator.register_constant("e", Polynomial::constant(E)).unwrap();
    evaluator.register_constant("inf", Polynomial::constant(1.0f64 / 0.0f64)).unwrap();
    evaluator.register_constant("nan", Polynomial::constant(0.0f64 / 0.0f64)).unwrap();

    evaluator.register_function("+", Function::new(2, Box::new(functions::addition))).unwrap();
    evaluator.register_function("-", Function::new(2, Box::new(functions::subtraction))).unwrap();
    evaluator.register_function("*", Function::new(2, Box::new(functions::multiplication))).unwrap();
    evaluator.register_function("/", Function::new(2, Box::new(functions::division))).unwrap();
    evaluator.register_function("^", Function::new(2, Box::new(functions::exponentiation))).unwrap();

    evaluator.register_function("log", Function::new(2, Box::new(functions::log))).unwrap();
    evaluator.register_function("log10", Function::new(1, Box::new(functions::log10))).unwrap();
    evaluator.register_function("bind", Function::new(2, Box::new(functions::bind))).unwrap();

    PolynomialEvaluator {
      evaluator: evaluator
    }
  }
}

/// Allows usage of PolynomialEvaluator as common TokensReducer
impl TokensReducer for PolynomialEvaluator {
  fn process(&self, tokens: &Tokens) -> Result<Polynomial, EvaluationError> {
    self.evaluator.process(tokens)
  }
}

/// Extends Parser with common arithmetic operators with correct precedence
/// and associativity.
pub struct PolynomialParser {
  /// Underlying parser (one can use it to extend it furthermore)
  pub parser: Parser
}

/// Creates PolynomialParser and extends basic Parser.
///
/// Common arithmetic operators are registered with the Parser.
impl Default for PolynomialParser {
  fn default() -> PolynomialParser {
    let mut parser = Parser::default();

    parser.register_operator('+', Operator::new(1, OperatorAssociativity::Left));
    parser.register_operator('-', Operator::new(1, OperatorAssociativity::Left));
    parser.register_operator('*', Operator::new(5, OperatorAssociativity::Left));
    parser.register_operator('/', Operator::new(5, OperatorAssociativity::Left));
    parser.register_operator('^', Operator::new(10, OperatorAssociativity::Right));

    PolynomialParser {
      parser: parser
    }
  }
}

/// Allows usage of PolynomialParser as common TokensProcessor
impl TokensProcessor for PolynomialParser {
  fn process(&mut self, tokens: &Tokens) -> Result<&Tokens, ParsingError> {
    self.parser.process(tokens)
  }
}

/// Implementations of function handlers used in operators and functions.
///
/// This module is public, so when you are writing another evaluator, but
/// it does not extend PolynomialEvaluator, you can reuse these functions
/// as handlers for some of the common operations.
///
/// Operations that are directly defined on the Polynomial (such as addition,
/// subtraction, multiplication and division), avoid cloning by using
/// the assignment with operation, thus optimizing memory usage.
pub mod functions {
  use polynomial::Polynomial;
  use EvaluationError;

  /// Adds two polynomials together (requires two arguments).
  pub fn addition(mut args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    let b = args.pop().unwrap();
    let mut a = args.pop().unwrap();

    a += b;
    Ok(a)
  }

  /// Subtracts two polynomials from each other (requires two arguments).
  pub fn subtraction(mut args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    let b = args.pop().unwrap();
    let mut a = args.pop().unwrap();

    a -= b;
    Ok(a)
  }

  /// Multiplies two polynomials together (requires two arguments).
  pub fn multiplication(mut args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    let b = args.pop().unwrap();
    let mut a = args.pop().unwrap();

    a *= b;
    Ok(a)
  }

  /// Divides two polynomials by each other (requires two arguments).
  ///
  /// # Errors
  ///
  /// It will return a wrapped PolynomialError when a degree of divident is
  /// smaller than a degree of divisor or when a divident is non-constant
  /// polynomial, while a divisor is a zero.
  pub fn division(mut args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    let b = args.pop().unwrap();
    let mut a = args.pop().unwrap();

    match (&mut a) / &b {
      Ok(_) => Ok(a),
      Err(e) => Err(EvaluationError::PolynomialError(e))
    }
  }

  /// Computes a logarithm of arbitrary base (requires two constant arguments).
  ///
  /// First arguments is a value to have a logarithm computed on, where a second
  /// argument is a base of the logarithm.
  ///
  /// # Errors
  ///
  /// It will return a wrapped PolynomialError::NonConstantError when any of the
  /// arguments is not a constant polynomial (a polynomial of degree zero).
  pub fn log(args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    Ok(Polynomial::constant(try!(args[0].as_f64()).log(try!(args[1].as_f64()))))
  }

  /// Computes a decimal logarithm (requires a single constant argument).
  ///
  /// # Errors
  ///
  /// It will return a wrapped PolynomialError::NonConstantError when the argument
  /// is not a constant polynomial (a polynomial of degree zero).
  pub fn log10(args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    Ok(Polynomial::constant(try!(args[0].as_f64()).log10()))
  }

  /// Binds a polynomial with a value (requires two arguments).
  ///
  /// This function computes value of given polynomial (first argument) when
  /// the symbol is replaced with a constant value (second argument).
  ///
  /// # Errors
  ///
  /// It will return a wrapped PolynomialError::NonConstantError when the second
  /// argument is not a constant polynomial (a polynomial of degree zero).
  pub fn bind(args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    Ok(args[0].bind(try!(args[1].as_f64())))
  }

  /// Performs exponentiation of polynomial (requires two arguments).
  ///
  /// First argument is an exponentiation base, where second argument is
  /// the exponent (which must be a constant polynomial). Method of exponentiation
  /// is optimized, it depends on degree of the base and a value of the exponent.
  /// Exponentation of complicated polynomials is done subefficiently by multiplication.
  ///
  /// # Errors
  ///
  /// It will return a NonConstantExponent error when the exponient is not
  /// a constant polynomial. Performing such operation would result in a
  /// non-polynomial result.
  ///
  /// It will return a NonNaturalExponent error when the exponient is not
  /// a natural number and the base is not a constant polynomial. Performing
  /// such operation would result in a non-polynomial result.
  pub fn exponentiation(mut args: Vec<Polynomial>) -> Result<Polynomial, EvaluationError> {
    let exponent = args.pop().unwrap();
    let base = args.pop().unwrap();

    let base_degree = base.degree();
    let exponent_degree = exponent.degree();

    if exponent_degree > 0 {
      Err(EvaluationError::NonConstantExponent)
    } else
    if exponent[0] == 0.0 {
      Ok(Polynomial::constant(1.0))
    } else
    if base_degree == 0 {
      Ok(Polynomial::constant(base[0].powf(exponent[0])))
    } else
    if exponent[0] > 0.0 && exponent[0].fract() == 0.0 {
      if base_degree == 1 && base[0] == 0.0 {
        let mut v = Polynomial::zero();
        v[exponent[0] as usize] = base[1].powf(exponent[0]);

        Ok(v)
      } else {
        let mut v = base.clone();
        let exp = exponent[0] as usize;

        {
          let mut vr = &mut v;
          for _ in 1..exp {
            vr *= &base;
          }
        }

        Ok(v)
      }
    } else {
      Err(EvaluationError::NonNaturalExponent)
    }
  }
}

#[cfg(test)]
mod tests {
  use polynomial::{Polynomial, PolynomialError};
  use polynomial_calculator::PolynomialCalculator;
  use EvaluationError;
  use calculator::Calculator;
  use calculator::CalculationError;
  use std::f64::consts::{PI, E};

  #[test]
  fn test_general() {
    assert_eq!(PolynomialCalculator.process("(3+(4-1))*5"), Ok(Polynomial::constant(30.0)));
  }

  #[test]
  fn test_constants() {
    assert_eq!(PolynomialCalculator.process("x"), Ok(Polynomial::linear(0.0, 1.0)));
    assert_eq!(PolynomialCalculator.process("pi"), Ok(Polynomial::constant(PI)));
    assert_eq!(PolynomialCalculator.process("e"), Ok(Polynomial::constant(E)));
  }

  #[test]
  fn test_operations() {
    assert_eq!(PolynomialCalculator.process("1+1"), Ok(Polynomial::constant(2.0)));
    assert_eq!(PolynomialCalculator.process("1+-1"), Ok(Polynomial::constant(0.0)));

    assert_eq!(PolynomialCalculator.process("1-1"), Ok(Polynomial::constant(0.0)));
    assert_eq!(PolynomialCalculator.process("1-3"), Ok(Polynomial::constant(-2.0)));
    assert_eq!(PolynomialCalculator.process("1--1"), Ok(Polynomial::constant(2.0)));

    assert_eq!(PolynomialCalculator.process("2*4"), Ok(Polynomial::constant(8.0)));
    assert_eq!(PolynomialCalculator.process("2*0"), Ok(Polynomial::constant(0.0)));

    assert_eq!(PolynomialCalculator.process("2/4"), Ok(Polynomial::constant(0.5)));
    assert!(PolynomialCalculator.process("2/0").unwrap().as_f64().unwrap().is_infinite());
    assert!(PolynomialCalculator.process("0/0").unwrap().as_f64().unwrap().is_nan());

    assert_eq!(PolynomialCalculator.process("2^0"), Ok(Polynomial::constant(1.0)));
    assert_eq!(PolynomialCalculator.process("2^4"), Ok(Polynomial::constant(16.0)));
  }

  #[test]
  fn test_polynomials() {
    assert_eq!(PolynomialCalculator.process("2x+1"), Ok(Polynomial::new(&[1.0, 2.0])));
    assert_eq!(PolynomialCalculator.process("2x+4x"), Ok(Polynomial::new(&[0.0, 6.0])));
    assert_eq!(PolynomialCalculator.process("2x-2x-1"), Ok(Polynomial::new(&[-1.0])));
    assert_eq!(PolynomialCalculator.process("2x--2x"), Ok(Polynomial::new(&[0.0, 4.0])));
    assert_eq!(PolynomialCalculator.process("2x*4x"), Ok(Polynomial::new(&[0.0, 0.0, 8.0])));
    assert_eq!(PolynomialCalculator.process("2x*(4x+1)"), Ok(Polynomial::new(&[0.0, 2.0, 8.0])));
    assert_eq!(PolynomialCalculator.process("2x/x"), Ok(Polynomial::new(&[2.0])));
    assert_eq!(PolynomialCalculator.process("2x/0"), Err(CalculationError::EvaluationError(EvaluationError::PolynomialError(PolynomialError::DivisionByZero))));
    assert_eq!(PolynomialCalculator.process("2x/x^2"), Err(CalculationError::EvaluationError(EvaluationError::PolynomialError(PolynomialError::DividentDegreeMismatch))));
    assert_eq!(PolynomialCalculator.process("(x^2-3x-10)/(x+2)"), Ok(Polynomial::new(&[-5.0, 1.0])));
    assert_eq!(PolynomialCalculator.process("x^5"), Ok(Polynomial::new(&[0.0, 0.0, 0.0, 0.0, 0.0, 1.0])));
    assert_eq!(PolynomialCalculator.process("(x+1)^5"), Ok(Polynomial::new(&[1.0, 5.0, 10.0, 10.0, 5.0, 1.0])));
  }
}
<|endoftext|>


<commit_before>// exec-env:RUST_CC_ZEAL=1

fn main() {
    #error["%?", os::getenv(~"RUST_CC_ZEAL")];
    let _x = @{a: @10, b: ~true};
}
<commit_msg>test: XFAIL issue-1466.rs due to cycle collector crashes.<commit_after>// exec-env:RUST_CC_ZEAL=1
// xfail-test

fn main() {
    #error["%?", os::getenv(~"RUST_CC_ZEAL")];
    let _x = @{a: @10, b: ~true};
}
<|endoftext|>


<commit_before>//! Crate `ruma-api-macros` provides a procedural macro for easily generating
//! [ruma-api](https://github.com/ruma/ruma-api)-compatible endpoints.
//!
//! See the documentation for the `ruma_api!` macro for usage details.

#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    // missing_docs, # Uncomment when https://github.com/rust-lang/rust/pull/60562 is released.
    warnings
)]
#![warn(
    clippy::empty_line_after_outer_attr,
    clippy::expl_impl_clone_on_copy,
    clippy::if_not_else,
    clippy::items_after_statements,
    clippy::match_same_arms,
    clippy::mem_forget,
    clippy::missing_docs_in_private_items,
    clippy::multiple_inherent_impl,
    clippy::mut_mut,
    clippy::needless_borrow,
    clippy::needless_continue,
    clippy::single_match_else,
    clippy::unicode_not_nfc,
    clippy::use_self,
    clippy::used_underscore_binding,
    clippy::wrong_pub_self_convention,
    clippy::wrong_self_convention
)]
#![allow(clippy::cognitive_complexity)]
// Since we support Rust 1.34.2, we can't apply this suggestion yet
#![allow(clippy::use_self)]
#![recursion_limit = "256"]

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::ToTokens;

use crate::api::{Api, RawApi};

mod api;

/// Generates a `ruma_api::Endpoint` from a concise definition.
///
/// The macro expects the following structure as input:
///
/// ```text
/// ruma_api! {
///     metadata {
///         description: &'static str
///         method: http::Method,
///         name: &'static str,
///         path: &'static str,
///         rate_limited: bool,
///         requires_authentication: bool,
///     }
///
///     request {
///         // Struct fields for each piece of data required
///         // to make a request to this API endpoint.
///     }
///
///     response {
///         // Struct fields for each piece of data expected
///         // in the response from this API endpoint.
///     }
/// }
/// # }
/// ```
///
/// This will generate a `ruma_api::Metadata` value to be used for the `ruma_api::Endpoint`'s
/// associated constant, single `Request` and `Response` structs, and the necessary trait
/// implementations to convert the request into a `http::Request` and to create a response from a
/// `http::Response` and vice versa.
///
/// The details of each of the three sections of the macros are documented below.
///
/// ## Metadata
///
/// *   `description`: A short description of what the endpoint does.
/// *   `method`: The HTTP method used for requests to the endpoint.
///     It's not necessary to import `http::Method`'s associated constants. Just write
///     the value as if it was imported, e.g. `GET`.
/// *   `name`: A unique name for the endpoint.
///     Generally this will be the same as the containing module.
/// *   `path`: The path component of the URL for the endpoint, e.g. "/foo/bar".
///     Components of the path that are parameterized can indicate a varible by using a Rust
///     identifier prefixed with a colon, e.g. `/foo/:some_parameter`.
///     A corresponding query string parameter will be expected in the request struct (see below
///     for details).
/// *   `rate_limited`: Whether or not the endpoint enforces rate limiting on requests.
/// *   `requires_authentication`: Whether or not the endpoint requires a valid access token.
///
/// ## Request
///
/// The request block contains normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There are also a few special attributes available to control how the struct is converted into a
/// `http::Request`:
///
/// *   `#[ruma_api(header = "HEADER_NAME")]`: Fields with this attribute will be treated as HTTP
///     headers on the request.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
/// *   `#[ruma_api(path)]`: Fields with this attribute will be inserted into the matching path
///     component of the request URL.
/// *   `#[ruma_api(query)]`: Fields with this attribute will be inserting into the URL's query
///     string.
///
/// Any field that does not include one of these attributes will be part of the request's JSON
/// body.
///
/// ## Response
///
/// Like the request block, the response block consists of normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There is also a special attribute available to control how the struct is created from a
/// `http::Request`:
///
/// *   `#[ruma_api(header = "HEADER_NAME")]`: Fields with this attribute will be treated as HTTP
///     headers on the response.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
///
/// Any field that does not include the above attribute will be expected in the response's JSON
/// body.
///
/// ## Newtype bodies
///
/// Both the request and response block also support "newtype bodies" by using the
/// `#[ruma_api(body)]` attribute on a field. If present on a field, the entire request or response
/// body will be treated as the value of the field. This allows you to treat the entire request or
/// response body as a specific type, rather than a JSON object with named fields. Only one field in
/// each struct can be marked with this attribute. It is an error to have a newtype body field and
/// normal body fields within the same struct.
///
/// # Examples
///
/// ```rust,ignore
/// # fn main() {
/// pub mod some_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "some_endpoint",
///             path: "/_matrix/some/endpoint/:baz",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             pub foo: String,
///
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             #[ruma_api(query)]
///             pub bar: String,
///
///             #[ruma_api(path)]
///             pub baz: String,
///         }
///
///         response {
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             pub value: String,
///         }
///     }
/// }
///
/// pub mod newtype_body_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     #[derive(Clone, Debug, Deserialize, Serialize)]
///     pub struct MyCustomType {
///         pub foo: String,
///     }
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "newtype_body_endpoint",
///             path: "/_matrix/some/newtype/body/endpoint",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             #[ruma_api(body)]
///             pub file: Vec<u8>,
///         }
///
///         response {
///             #[ruma_api(body)]
///             pub my_custom_type: MyCustomType,
///         }
///     }
/// }
/// # }
/// ```
#[proc_macro]
pub fn ruma_api(input: TokenStream) -> TokenStream {
    let raw_api = syn::parse_macro_input!(input as RawApi);

    let api = Api::from(raw_api);

    api.into_token_stream().into()
}
<commit_msg>Remove unnecessary main declaration in doctest<commit_after>//! Crate `ruma-api-macros` provides a procedural macro for easily generating
//! [ruma-api](https://github.com/ruma/ruma-api)-compatible endpoints.
//!
//! See the documentation for the `ruma_api!` macro for usage details.

#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    // missing_docs, # Uncomment when https://github.com/rust-lang/rust/pull/60562 is released.
    warnings
)]
#![warn(
    clippy::empty_line_after_outer_attr,
    clippy::expl_impl_clone_on_copy,
    clippy::if_not_else,
    clippy::items_after_statements,
    clippy::match_same_arms,
    clippy::mem_forget,
    clippy::missing_docs_in_private_items,
    clippy::multiple_inherent_impl,
    clippy::mut_mut,
    clippy::needless_borrow,
    clippy::needless_continue,
    clippy::single_match_else,
    clippy::unicode_not_nfc,
    clippy::use_self,
    clippy::used_underscore_binding,
    clippy::wrong_pub_self_convention,
    clippy::wrong_self_convention
)]
#![allow(clippy::cognitive_complexity)]
// Since we support Rust 1.34.2, we can't apply this suggestion yet
#![allow(clippy::use_self)]
#![recursion_limit = "256"]

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::ToTokens;

use crate::api::{Api, RawApi};

mod api;

/// Generates a `ruma_api::Endpoint` from a concise definition.
///
/// The macro expects the following structure as input:
///
/// ```text
/// ruma_api! {
///     metadata {
///         description: &'static str
///         method: http::Method,
///         name: &'static str,
///         path: &'static str,
///         rate_limited: bool,
///         requires_authentication: bool,
///     }
///
///     request {
///         // Struct fields for each piece of data required
///         // to make a request to this API endpoint.
///     }
///
///     response {
///         // Struct fields for each piece of data expected
///         // in the response from this API endpoint.
///     }
/// }
/// # }
/// ```
///
/// This will generate a `ruma_api::Metadata` value to be used for the `ruma_api::Endpoint`'s
/// associated constant, single `Request` and `Response` structs, and the necessary trait
/// implementations to convert the request into a `http::Request` and to create a response from a
/// `http::Response` and vice versa.
///
/// The details of each of the three sections of the macros are documented below.
///
/// ## Metadata
///
/// *   `description`: A short description of what the endpoint does.
/// *   `method`: The HTTP method used for requests to the endpoint.
///     It's not necessary to import `http::Method`'s associated constants. Just write
///     the value as if it was imported, e.g. `GET`.
/// *   `name`: A unique name for the endpoint.
///     Generally this will be the same as the containing module.
/// *   `path`: The path component of the URL for the endpoint, e.g. "/foo/bar".
///     Components of the path that are parameterized can indicate a varible by using a Rust
///     identifier prefixed with a colon, e.g. `/foo/:some_parameter`.
///     A corresponding query string parameter will be expected in the request struct (see below
///     for details).
/// *   `rate_limited`: Whether or not the endpoint enforces rate limiting on requests.
/// *   `requires_authentication`: Whether or not the endpoint requires a valid access token.
///
/// ## Request
///
/// The request block contains normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There are also a few special attributes available to control how the struct is converted into a
/// `http::Request`:
///
/// *   `#[ruma_api(header = "HEADER_NAME")]`: Fields with this attribute will be treated as HTTP
///     headers on the request.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
/// *   `#[ruma_api(path)]`: Fields with this attribute will be inserted into the matching path
///     component of the request URL.
/// *   `#[ruma_api(query)]`: Fields with this attribute will be inserting into the URL's query
///     string.
///
/// Any field that does not include one of these attributes will be part of the request's JSON
/// body.
///
/// ## Response
///
/// Like the request block, the response block consists of normal struct field definitions.
/// Doc comments and attributes are allowed as normal.
/// There is also a special attribute available to control how the struct is created from a
/// `http::Request`:
///
/// *   `#[ruma_api(header = "HEADER_NAME")]`: Fields with this attribute will be treated as HTTP
///     headers on the response.
///     The value must implement `AsRef<str>`.
///     Generally this is a `String`.
///     The attribute value shown above as `HEADER_NAME` must be a header name constant from
///     `http::header`, e.g. `CONTENT_TYPE`.
///
/// Any field that does not include the above attribute will be expected in the response's JSON
/// body.
///
/// ## Newtype bodies
///
/// Both the request and response block also support "newtype bodies" by using the
/// `#[ruma_api(body)]` attribute on a field. If present on a field, the entire request or response
/// body will be treated as the value of the field. This allows you to treat the entire request or
/// response body as a specific type, rather than a JSON object with named fields. Only one field in
/// each struct can be marked with this attribute. It is an error to have a newtype body field and
/// normal body fields within the same struct.
///
/// # Examples
///
/// ```rust,ignore
/// pub mod some_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "some_endpoint",
///             path: "/_matrix/some/endpoint/:baz",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             pub foo: String,
///
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             #[ruma_api(query)]
///             pub bar: String,
///
///             #[ruma_api(path)]
///             pub baz: String,
///         }
///
///         response {
///             #[ruma_api(header = CONTENT_TYPE)]
///             pub content_type: String,
///
///             pub value: String,
///         }
///     }
/// }
///
/// pub mod newtype_body_endpoint {
///     use ruma_api_macros::ruma_api;
///
///     #[derive(Clone, Debug, Deserialize, Serialize)]
///     pub struct MyCustomType {
///         pub foo: String,
///     }
///
///     ruma_api! {
///         metadata {
///             description: "Does something.",
///             method: GET,
///             name: "newtype_body_endpoint",
///             path: "/_matrix/some/newtype/body/endpoint",
///             rate_limited: false,
///             requires_authentication: false,
///         }
///
///         request {
///             #[ruma_api(body)]
///             pub file: Vec<u8>,
///         }
///
///         response {
///             #[ruma_api(body)]
///             pub my_custom_type: MyCustomType,
///         }
///     }
/// }
/// ```
#[proc_macro]
pub fn ruma_api(input: TokenStream) -> TokenStream {
    let raw_api = syn::parse_macro_input!(input as RawApi);

    let api = Api::from(raw_api);

    api.into_token_stream().into()
}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_variables)]

extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::WindowSettings;
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

struct App {
    window: Rc<RefCell<GlutinWindow>>,
    graphics: Rc<RefCell<GlGraphics>>,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    cursor_pos: [f64; 2],
    bg_color: [f32; 4]
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    match action {
                        CharacterAction::Jump => {

                        },
                        CharacterAction::MoveLeft => {
                            self.character.current_velocity[0] += 0.5
                        },
                        CharacterAction::MoveRight => {
                            self.character.current_velocity[0] -= 0.5
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.cursor_pos = [x, y];
                }
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs) {

    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();

        // draw the background color
        {
            gl_graphics.draw(args.viewport(), |_, gl| clear(self.bg_color, gl));
        }

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0], self.character.topleft[1], self.character.size);
            let (x, y) = ((args.width / 2) as f64, (args.height / 2) as f64);

            gl_graphics.draw(args.viewport(), |c, gl| {
                let transform = c.transform.trans(x, y);
                rectangle(self.character.color, square, transform, gl);
            });
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.cursor_pos[0], self.cursor_pos[1], 5.0);
            gl_graphics.draw(args.viewport(), |c, gl| {
                let transform = c.transform.trans(0.0, 0.0);
                ellipse([0.0, 1.0, 0.0, 1.0], dot, transform, gl)
            })
        }
    }
}

struct Character {
    color: [f32; 4],
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: [f32; 4], tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0f64, 0.0],
            size: sz
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const WINDOW_SIZE: (u32, u32)  = (800, 600);
    const OPENGL: OpenGL = OpenGL::V3_2;

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .unwrap_or_else(|e| panic!("Could not create window: {}", e));

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE.into())
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .build_translator();

    let character = Character::new([1.0, 0.0, 0.0, 1.0],
                                   [30.0, 30.0],
                                   50.0);

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        translator: translator,
        character: character,
        cursor_pos: [0.0, 0.0],
        bg_color: [0.0, 0.0, 0.0, 1.0] // black background
    };

    for e in app.window.clone().events() {
        match e {
            Event::Render(r) => { app.render(&r); },
            Event::Update(u) => { app.update(&u); },
            Event::Input(i)  => { app.input(&i); },
            _ => { }
        }
    }
}
<commit_msg>Refactor cursor dot drawing code<commit_after>#![allow(dead_code, unused_variables)]

extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::WindowSettings;
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

struct App {
    window: Rc<RefCell<GlutinWindow>>,
    graphics: Rc<RefCell<GlGraphics>>,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    cursor_pos: [f64; 2],
    bg_color: [f32; 4]
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    match action {
                        CharacterAction::Jump => {

                        },
                        CharacterAction::MoveLeft => {
                            self.character.current_velocity[0] += 0.5
                        },
                        CharacterAction::MoveRight => {
                            self.character.current_velocity[0] -= 0.5
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.cursor_pos = [x, y];
                }
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs) {

    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();

        // draw the background color
        {
            gl_graphics.draw(args.viewport(), |_, gl| clear(self.bg_color, gl));
        }

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0], self.character.topleft[1], self.character.size);
            let (x, y) = ((args.width / 2) as f64, (args.height / 2) as f64);

            gl_graphics.draw(args.viewport(), |c, gl| {
                let transform = c.transform.trans(x, y);
                rectangle(self.character.color, square, transform, gl);
            });
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.cursor_pos[0], self.cursor_pos[1], 5.0);
            gl_graphics.draw(args.viewport(), |c, gl| ellipse([0.0, 1.0, 0.0, 1.0], dot, c.transform, gl))
        }
    }
}

struct Character {
    color: [f32; 4],
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: [f32; 4], tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0f64, 0.0],
            size: sz
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const WINDOW_SIZE: (u32, u32)  = (800, 600);
    const OPENGL: OpenGL = OpenGL::V3_2;

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .unwrap_or_else(|e| panic!("Could not create window: {}", e));

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE.into())
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .build_translator();

    let character = Character::new([1.0, 0.0, 0.0, 1.0],
                                   [30.0, 30.0],
                                   50.0);

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        translator: translator,
        character: character,
        cursor_pos: [0.0, 0.0],
        bg_color: [0.0, 0.0, 0.0, 1.0] // black background
    };

    for e in app.window.clone().events() {
        match e {
            Event::Render(r) => { app.render(&r); },
            Event::Update(u) => { app.update(&u); },
            Event::Input(i)  => { app.input(&i); },
            _ => { }
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate itertools;
#[macro_use] extern crate log;
extern crate regex;
extern crate toml;

extern crate libimagstore;

pub mod error;
pub mod exec;
pub mod result;
pub mod tag;
pub mod tagable;
pub mod util;
pub mod ui;

<commit_msg>Enable lints<commit_after>#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_mut,
    unused_qualifications,
    while_true,
)]

extern crate clap;
extern crate itertools;
#[macro_use] extern crate log;
extern crate regex;
extern crate toml;

extern crate libimagstore;

pub mod error;
pub mod exec;
pub mod result;
pub mod tag;
pub mod tagable;
pub mod util;
pub mod ui;

<|endoftext|>


<commit_before>use rustc::ty::{Ty, TyCtxt};
use rustc::mir::*;
use rustc::util::nodemap::FxHashMap;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use smallvec::SmallVec;
use syntax_pos::{Span};

use std::fmt;
use std::ops::{Index, IndexMut};

use self::abs_domain::{AbstractElem, Lift};

mod abs_domain;

newtype_index! {
    pub struct MovePathIndex {
        DEBUG_FORMAT = "mp{}"
    }
}

newtype_index! {
    pub struct MoveOutIndex {
        DEBUG_FORMAT = "mo{}"
    }
}

newtype_index! {
    pub struct InitIndex {
        DEBUG_FORMAT = "in{}"
    }
}

impl MoveOutIndex {
    pub fn move_path_index(&self, move_data: &MoveData<'_>) -> MovePathIndex {
        move_data.moves[*self].path
    }
}

/// `MovePath` is a canonicalized representation of a path that is
/// moved or assigned to.
///
/// It follows a tree structure.
///
/// Given `struct X { m: M, n: N }` and `x: X`, moves like `drop x.m;`
/// move *out* of the place `x.m`.
///
/// The MovePaths representing `x.m` and `x.n` are siblings (that is,
/// one of them will link to the other via the `next_sibling` field,
/// and the other will have no entry in its `next_sibling` field), and
/// they both have the MovePath representing `x` as their parent.
#[derive(Clone)]
pub struct MovePath<'tcx> {
    pub next_sibling: Option<MovePathIndex>,
    pub first_child: Option<MovePathIndex>,
    pub parent: Option<MovePathIndex>,
    pub place: Place<'tcx>,
}

impl<'tcx> MovePath<'tcx> {
    pub fn parents(
        &self,
        move_paths: &IndexVec<MovePathIndex, MovePath<'_>>,
    ) -> Vec<MovePathIndex> {
        let mut parents = Vec::new();

        let mut curr_parent = self.parent;
        while let Some(parent_mpi) = curr_parent {
            parents.push(parent_mpi);
            curr_parent = move_paths[parent_mpi].parent;
        }

        parents
    }
}

impl<'tcx> fmt::Debug for MovePath<'tcx> {
    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(w, "MovePath {{")?;
        if let Some(parent) = self.parent {
            write!(w, " parent: {:?},", parent)?;
        }
        if let Some(first_child) = self.first_child {
            write!(w, " first_child: {:?},", first_child)?;
        }
        if let Some(next_sibling) = self.next_sibling {
            write!(w, " next_sibling: {:?}", next_sibling)?;
        }
        write!(w, " place: {:?} }}", self.place)
    }
}

impl<'tcx> fmt::Display for MovePath<'tcx> {
    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(w, "{:?}", self.place)
    }
}

#[derive(Debug)]
pub struct MoveData<'tcx> {
    pub move_paths: IndexVec<MovePathIndex, MovePath<'tcx>>,
    pub moves: IndexVec<MoveOutIndex, MoveOut>,
    /// Each Location `l` is mapped to the MoveOut's that are effects
    /// of executing the code at `l`. (There can be multiple MoveOut's
    /// for a given `l` because each MoveOut is associated with one
    /// particular path being moved.)
    pub loc_map: LocationMap<SmallVec<[MoveOutIndex; 4]>>,
    pub path_map: IndexVec<MovePathIndex, SmallVec<[MoveOutIndex; 4]>>,
    pub rev_lookup: MovePathLookup,
    pub inits: IndexVec<InitIndex, Init>,
    /// Each Location `l` is mapped to the Inits that are effects
    /// of executing the code at `l`.
    pub init_loc_map: LocationMap<SmallVec<[InitIndex; 4]>>,
    pub init_path_map: IndexVec<MovePathIndex, SmallVec<[InitIndex; 4]>>,
}

pub trait HasMoveData<'tcx> {
    fn move_data(&self) -> &MoveData<'tcx>;
}

#[derive(Debug)]
pub struct LocationMap<T> {
    /// Location-indexed (BasicBlock for outer index, index within BB
    /// for inner index) map.
    pub(crate) map: IndexVec<BasicBlock, Vec<T>>,
}

impl<T> Index<Location> for LocationMap<T> {
    type Output = T;
    fn index(&self, index: Location) -> &Self::Output {
        &self.map[index.block][index.statement_index]
    }
}

impl<T> IndexMut<Location> for LocationMap<T> {
    fn index_mut(&mut self, index: Location) -> &mut Self::Output {
        &mut self.map[index.block][index.statement_index]
    }
}

impl<T> LocationMap<T> where T: Default + Clone {
    fn new(mir: &Mir<'_>) -> Self {
        LocationMap {
            map: mir.basic_blocks().iter().map(|block| {
                vec![T::default(); block.statements.len()+1]
            }).collect()
        }
    }
}

/// `MoveOut` represents a point in a program that moves out of some
/// L-value; i.e., "creates" uninitialized memory.
///
/// With respect to dataflow analysis:
/// - Generated by moves and declaration of uninitialized variables.
/// - Killed by assignments to the memory.
#[derive(Copy, Clone)]
pub struct MoveOut {
    /// path being moved
    pub path: MovePathIndex,
    /// location of move
    pub source: Location,
}

impl fmt::Debug for MoveOut {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "{:?}@{:?}", self.path, self.source)
    }
}

/// `Init` represents a point in a program that initializes some L-value;
#[derive(Copy, Clone)]
pub struct Init {
    /// path being initialized
    pub path: MovePathIndex,
    /// location of initialization
    pub location: InitLocation,
    /// Extra information about this initialization
    pub kind: InitKind,
}

/// Initializations can be from an argument or from a statement. Arguments
/// do not have locations, in those cases the `Local` is kept..
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InitLocation {
    Argument(Local),
    Statement(Location),
}

/// Additional information about the initialization.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InitKind {
    /// Deep init, even on panic
    Deep,
    /// Only does a shallow init
    Shallow,
    /// This doesn't initialize the variable on panic (and a panic is possible).
    NonPanicPathOnly,
}

impl fmt::Debug for Init {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "{:?}@{:?} ({:?})", self.path, self.location, self.kind)
    }
}

impl Init {
    crate fn span<'gcx>(&self, mir: &Mir<'gcx>) -> Span {
        match self.location {
            InitLocation::Argument(local) => mir.local_decls[local].source_info.span,
            InitLocation::Statement(location) => mir.source_info(location).span,
        }
    }
}

/// Tables mapping from a place to its MovePathIndex.
#[derive(Debug)]
pub struct MovePathLookup {
    locals: IndexVec<Local, MovePathIndex>,

    /// projections are made from a base-place and a projection
    /// elem. The base-place will have a unique MovePathIndex; we use
    /// the latter as the index into the outer vector (narrowing
    /// subsequent search so that it is solely relative to that
    /// base-place). For the remaining lookup, we map the projection
    /// elem to the associated MovePathIndex.
    projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>
}

mod builder;

#[derive(Copy, Clone, Debug)]
pub enum LookupResult {
    Exact(MovePathIndex),
    Parent(Option<MovePathIndex>)
}

impl MovePathLookup {
    // Unlike the builder `fn move_path_for` below, this lookup
    // alternative will *not* create a MovePath on the fly for an
    // unknown place, but will rather return the nearest available
    // parent.
    pub fn find(&self, place: &Place<'tcx>) -> LookupResult {
        match *place {
            Place::Base(PlaceBase::Local(local)) => LookupResult::Exact(self.locals[local]),
            Place::Base(PlaceBase::Static(..)) => LookupResult::Parent(None),
            Place::Projection(ref proj) => {
                match self.find(&proj.base) {
                    LookupResult::Exact(base_path) => {
                        match self.projections.get(&(base_path, proj.elem.lift())) {
                            Some(&subpath) => LookupResult::Exact(subpath),
                            None => LookupResult::Parent(Some(base_path))
                        }
                    }
                    inexact => inexact
                }
            }
        }
    }

    pub fn find_local(&self, local: Local) -> MovePathIndex {
        self.locals[local]
    }
}

#[derive(Debug)]
pub struct IllegalMoveOrigin<'tcx> {
    pub(crate) location: Location,
    pub(crate) kind: IllegalMoveOriginKind<'tcx>,
}

#[derive(Debug)]
pub(crate) enum IllegalMoveOriginKind<'tcx> {
    /// Illegal move due to attempt to move from `static` variable.
    Static,

    /// Illegal move due to attempt to move from behind a reference.
    BorrowedContent {
        /// The place the reference refers to: if erroneous code was trying to
        /// move from `(*x).f` this will be `*x`.
        target_place: Place<'tcx>,
    },

    /// Illegal move due to attempt to move from field of an ADT that
    /// implements `Drop`. Rust maintains invariant that all `Drop`
    /// ADT's remain fully-initialized so that user-defined destructor
    /// can safely read from all of the ADT's fields.
    InteriorOfTypeWithDestructor { container_ty: Ty<'tcx> },

    /// Illegal move due to attempt to move out of a slice or array.
    InteriorOfSliceOrArray { ty: Ty<'tcx>, is_index: bool, },
}

#[derive(Debug)]
pub enum MoveError<'tcx> {
    IllegalMove { cannot_move_out_of: IllegalMoveOrigin<'tcx> },
    UnionMove { path: MovePathIndex },
}

impl<'tcx> MoveError<'tcx> {
    fn cannot_move_out_of(location: Location, kind: IllegalMoveOriginKind<'tcx>) -> Self {
        let origin = IllegalMoveOrigin { location, kind };
        MoveError::IllegalMove { cannot_move_out_of: origin }
    }
}

impl<'a, 'gcx, 'tcx> MoveData<'tcx> {
    pub fn gather_moves(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>)
                        -> Result<Self, (Self, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
        builder::gather_moves(mir, tcx)
    }

    /// For the move path `mpi`, returns the root local variable (if any) that starts the path.
    /// (e.g., for a path like `a.b.c` returns `Some(a)`)
    pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
        loop {
            let path = &self.move_paths[mpi];
            if let Place::Base(PlaceBase::Local(l)) = path.place { return Some(l); }
            if let Some(parent) = path.parent { mpi = parent; continue } else { return None }
        }
    }
}
<commit_msg>Make find iterate instead of recurse<commit_after>use rustc::ty::{Ty, TyCtxt};
use rustc::mir::*;
use rustc::util::nodemap::FxHashMap;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use smallvec::SmallVec;
use syntax_pos::{Span};

use std::fmt;
use std::ops::{Index, IndexMut};

use self::abs_domain::{AbstractElem, Lift};

mod abs_domain;

newtype_index! {
    pub struct MovePathIndex {
        DEBUG_FORMAT = "mp{}"
    }
}

newtype_index! {
    pub struct MoveOutIndex {
        DEBUG_FORMAT = "mo{}"
    }
}

newtype_index! {
    pub struct InitIndex {
        DEBUG_FORMAT = "in{}"
    }
}

impl MoveOutIndex {
    pub fn move_path_index(&self, move_data: &MoveData<'_>) -> MovePathIndex {
        move_data.moves[*self].path
    }
}

/// `MovePath` is a canonicalized representation of a path that is
/// moved or assigned to.
///
/// It follows a tree structure.
///
/// Given `struct X { m: M, n: N }` and `x: X`, moves like `drop x.m;`
/// move *out* of the place `x.m`.
///
/// The MovePaths representing `x.m` and `x.n` are siblings (that is,
/// one of them will link to the other via the `next_sibling` field,
/// and the other will have no entry in its `next_sibling` field), and
/// they both have the MovePath representing `x` as their parent.
#[derive(Clone)]
pub struct MovePath<'tcx> {
    pub next_sibling: Option<MovePathIndex>,
    pub first_child: Option<MovePathIndex>,
    pub parent: Option<MovePathIndex>,
    pub place: Place<'tcx>,
}

impl<'tcx> MovePath<'tcx> {
    pub fn parents(
        &self,
        move_paths: &IndexVec<MovePathIndex, MovePath<'_>>,
    ) -> Vec<MovePathIndex> {
        let mut parents = Vec::new();

        let mut curr_parent = self.parent;
        while let Some(parent_mpi) = curr_parent {
            parents.push(parent_mpi);
            curr_parent = move_paths[parent_mpi].parent;
        }

        parents
    }
}

impl<'tcx> fmt::Debug for MovePath<'tcx> {
    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(w, "MovePath {{")?;
        if let Some(parent) = self.parent {
            write!(w, " parent: {:?},", parent)?;
        }
        if let Some(first_child) = self.first_child {
            write!(w, " first_child: {:?},", first_child)?;
        }
        if let Some(next_sibling) = self.next_sibling {
            write!(w, " next_sibling: {:?}", next_sibling)?;
        }
        write!(w, " place: {:?} }}", self.place)
    }
}

impl<'tcx> fmt::Display for MovePath<'tcx> {
    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(w, "{:?}", self.place)
    }
}

#[derive(Debug)]
pub struct MoveData<'tcx> {
    pub move_paths: IndexVec<MovePathIndex, MovePath<'tcx>>,
    pub moves: IndexVec<MoveOutIndex, MoveOut>,
    /// Each Location `l` is mapped to the MoveOut's that are effects
    /// of executing the code at `l`. (There can be multiple MoveOut's
    /// for a given `l` because each MoveOut is associated with one
    /// particular path being moved.)
    pub loc_map: LocationMap<SmallVec<[MoveOutIndex; 4]>>,
    pub path_map: IndexVec<MovePathIndex, SmallVec<[MoveOutIndex; 4]>>,
    pub rev_lookup: MovePathLookup,
    pub inits: IndexVec<InitIndex, Init>,
    /// Each Location `l` is mapped to the Inits that are effects
    /// of executing the code at `l`.
    pub init_loc_map: LocationMap<SmallVec<[InitIndex; 4]>>,
    pub init_path_map: IndexVec<MovePathIndex, SmallVec<[InitIndex; 4]>>,
}

pub trait HasMoveData<'tcx> {
    fn move_data(&self) -> &MoveData<'tcx>;
}

#[derive(Debug)]
pub struct LocationMap<T> {
    /// Location-indexed (BasicBlock for outer index, index within BB
    /// for inner index) map.
    pub(crate) map: IndexVec<BasicBlock, Vec<T>>,
}

impl<T> Index<Location> for LocationMap<T> {
    type Output = T;
    fn index(&self, index: Location) -> &Self::Output {
        &self.map[index.block][index.statement_index]
    }
}

impl<T> IndexMut<Location> for LocationMap<T> {
    fn index_mut(&mut self, index: Location) -> &mut Self::Output {
        &mut self.map[index.block][index.statement_index]
    }
}

impl<T> LocationMap<T> where T: Default + Clone {
    fn new(mir: &Mir<'_>) -> Self {
        LocationMap {
            map: mir.basic_blocks().iter().map(|block| {
                vec![T::default(); block.statements.len()+1]
            }).collect()
        }
    }
}

/// `MoveOut` represents a point in a program that moves out of some
/// L-value; i.e., "creates" uninitialized memory.
///
/// With respect to dataflow analysis:
/// - Generated by moves and declaration of uninitialized variables.
/// - Killed by assignments to the memory.
#[derive(Copy, Clone)]
pub struct MoveOut {
    /// path being moved
    pub path: MovePathIndex,
    /// location of move
    pub source: Location,
}

impl fmt::Debug for MoveOut {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "{:?}@{:?}", self.path, self.source)
    }
}

/// `Init` represents a point in a program that initializes some L-value;
#[derive(Copy, Clone)]
pub struct Init {
    /// path being initialized
    pub path: MovePathIndex,
    /// location of initialization
    pub location: InitLocation,
    /// Extra information about this initialization
    pub kind: InitKind,
}

/// Initializations can be from an argument or from a statement. Arguments
/// do not have locations, in those cases the `Local` is kept..
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InitLocation {
    Argument(Local),
    Statement(Location),
}

/// Additional information about the initialization.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InitKind {
    /// Deep init, even on panic
    Deep,
    /// Only does a shallow init
    Shallow,
    /// This doesn't initialize the variable on panic (and a panic is possible).
    NonPanicPathOnly,
}

impl fmt::Debug for Init {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "{:?}@{:?} ({:?})", self.path, self.location, self.kind)
    }
}

impl Init {
    crate fn span<'gcx>(&self, mir: &Mir<'gcx>) -> Span {
        match self.location {
            InitLocation::Argument(local) => mir.local_decls[local].source_info.span,
            InitLocation::Statement(location) => mir.source_info(location).span,
        }
    }
}

/// Tables mapping from a place to its MovePathIndex.
#[derive(Debug)]
pub struct MovePathLookup {
    locals: IndexVec<Local, MovePathIndex>,

    /// projections are made from a base-place and a projection
    /// elem. The base-place will have a unique MovePathIndex; we use
    /// the latter as the index into the outer vector (narrowing
    /// subsequent search so that it is solely relative to that
    /// base-place). For the remaining lookup, we map the projection
    /// elem to the associated MovePathIndex.
    projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>
}

mod builder;

#[derive(Copy, Clone, Debug)]
pub enum LookupResult {
    Exact(MovePathIndex),
    Parent(Option<MovePathIndex>)
}

impl MovePathLookup {
    // Unlike the builder `fn move_path_for` below, this lookup
    // alternative will *not* create a MovePath on the fly for an
    // unknown place, but will rather return the nearest available
    // parent.
    pub fn find(&self, place: &Place<'tcx>) -> LookupResult {
        place.iterate(|place_base, place_projection| {
            let mut result = match place_base {
                PlaceBase::Local(local) => self.locals[*local],
                PlaceBase::Static(..) => return LookupResult::Parent(None),
            };

            for proj in place_projection {
                if let Some(&subpath) = self.projections.get(&(result, proj.elem.lift())) {
                    result = subpath;
                } else {
                    return LookupResult::Parent(Some(result));
                }
            }

            LookupResult::Exact(result)
        })
    }

    pub fn find_local(&self, local: Local) -> MovePathIndex {
        self.locals[local]
    }
}

#[derive(Debug)]
pub struct IllegalMoveOrigin<'tcx> {
    pub(crate) location: Location,
    pub(crate) kind: IllegalMoveOriginKind<'tcx>,
}

#[derive(Debug)]
pub(crate) enum IllegalMoveOriginKind<'tcx> {
    /// Illegal move due to attempt to move from `static` variable.
    Static,

    /// Illegal move due to attempt to move from behind a reference.
    BorrowedContent {
        /// The place the reference refers to: if erroneous code was trying to
        /// move from `(*x).f` this will be `*x`.
        target_place: Place<'tcx>,
    },

    /// Illegal move due to attempt to move from field of an ADT that
    /// implements `Drop`. Rust maintains invariant that all `Drop`
    /// ADT's remain fully-initialized so that user-defined destructor
    /// can safely read from all of the ADT's fields.
    InteriorOfTypeWithDestructor { container_ty: Ty<'tcx> },

    /// Illegal move due to attempt to move out of a slice or array.
    InteriorOfSliceOrArray { ty: Ty<'tcx>, is_index: bool, },
}

#[derive(Debug)]
pub enum MoveError<'tcx> {
    IllegalMove { cannot_move_out_of: IllegalMoveOrigin<'tcx> },
    UnionMove { path: MovePathIndex },
}

impl<'tcx> MoveError<'tcx> {
    fn cannot_move_out_of(location: Location, kind: IllegalMoveOriginKind<'tcx>) -> Self {
        let origin = IllegalMoveOrigin { location, kind };
        MoveError::IllegalMove { cannot_move_out_of: origin }
    }
}

impl<'a, 'gcx, 'tcx> MoveData<'tcx> {
    pub fn gather_moves(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'gcx, 'tcx>)
                        -> Result<Self, (Self, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
        builder::gather_moves(mir, tcx)
    }

    /// For the move path `mpi`, returns the root local variable (if any) that starts the path.
    /// (e.g., for a path like `a.b.c` returns `Some(a)`)
    pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
        loop {
            let path = &self.move_paths[mpi];
            if let Place::Base(PlaceBase::Local(l)) = path.place { return Some(l); }
            if let Some(parent) = path.parent { mpi = parent; continue } else { return None }
        }
    }
}
<|endoftext|>