<commit_before>extern crate log;

pub use cli::CliConfig;
pub use configuration::Configuration as Cfg;

use std::fmt::Debug;
use std::fmt::Formatter;
use std::fmt::Error;

use log::{LogRecord, LogLevel, LogLevelFilter, LogMetadata, SetLoggerError};

pub struct ImagLogger {
    lvl: LogLevel,
}

impl ImagLogger {

    pub fn new(lvl: LogLevel) -> ImagLogger {
        ImagLogger {
            lvl: lvl,
        }
    }

    pub fn init(cfg: &Cfg, config: &CliConfig) -> Result<(), SetLoggerError> {
        let lvl = if config.is_debugging() || cfg.is_debugging() {
            LogLevelFilter::Debug
        } else if config.is_verbose() || cfg.is_debugging() {
            LogLevelFilter::Info
        } else {
            LogLevelFilter::Error
        };

        log::set_logger(|max_log_lvl| {
            max_log_lvl.set(lvl);
            debug!("Init logger with: {}", lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        })
    }

}

impl log::Log for ImagLogger {

    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.lvl
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            println!("[{}]: {}", record.level(), record.args());
        }
    }
}

pub struct Runtime<'a> {
    pub config : CliConfig<'a>,
    pub configuration : Cfg,
}

impl<'a> Runtime<'a> {

    pub fn new(cfg: Cfg, config : CliConfig<'a>) -> Runtime<'a> {
        Runtime {
            config: config,
            configuration: cfg,
        }
    }

    pub fn is_verbose(&self) -> bool {
        self.config.is_verbose() || self.configuration.is_verbose()
    }

    pub fn is_debugging(&self) -> bool {
        self.config.is_debugging() || self.configuration.is_verbose()
    }

    pub fn get_rtp(&self) -> String {
        if let Some(rtp) = self.config.get_rtp() {
            rtp
        } else {
            self.configuration.get_rtp()
        }
    }

}

impl<'a> Debug for Runtime<'a> {

    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "Runtime (verbose: {}, debugging: {}, rtp: {})",
            self.is_verbose(),
            self.is_debugging(),
            self.get_rtp())
    }

}

<commit_msg>Provide getter for store path in Runtime object<commit_after>extern crate log;

pub use cli::CliConfig;
pub use configuration::Configuration as Cfg;

use std::fmt::Debug;
use std::fmt::Formatter;
use std::fmt::Error;

use log::{LogRecord, LogLevel, LogLevelFilter, LogMetadata, SetLoggerError};

pub struct ImagLogger {
    lvl: LogLevel,
}

impl ImagLogger {

    pub fn new(lvl: LogLevel) -> ImagLogger {
        ImagLogger {
            lvl: lvl,
        }
    }

    pub fn init(cfg: &Cfg, config: &CliConfig) -> Result<(), SetLoggerError> {
        let lvl = if config.is_debugging() || cfg.is_debugging() {
            LogLevelFilter::Debug
        } else if config.is_verbose() || cfg.is_debugging() {
            LogLevelFilter::Info
        } else {
            LogLevelFilter::Error
        };

        log::set_logger(|max_log_lvl| {
            max_log_lvl.set(lvl);
            debug!("Init logger with: {}", lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        })
    }

}

impl log::Log for ImagLogger {

    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.lvl
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            println!("[{}]: {}", record.level(), record.args());
        }
    }
}

pub struct Runtime<'a> {
    pub config : CliConfig<'a>,
    pub configuration : Cfg,
}

impl<'a> Runtime<'a> {

    pub fn new(cfg: Cfg, config : CliConfig<'a>) -> Runtime<'a> {
        Runtime {
            config: config,
            configuration: cfg,
        }
    }

    pub fn is_verbose(&self) -> bool {
        self.config.is_verbose() || self.configuration.is_verbose()
    }

    pub fn is_debugging(&self) -> bool {
        self.config.is_debugging() || self.configuration.is_verbose()
    }

    pub fn store_path(&self) -> String {
        self.config.store_path().unwrap_or(self.configuration.store_path())
    }

    pub fn get_rtp(&self) -> String {
        if let Some(rtp) = self.config.get_rtp() {
            rtp
        } else {
            self.configuration.get_rtp()
        }
    }

}

impl<'a> Debug for Runtime<'a> {

    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(f, "Runtime (verbose: {}, debugging: {}, rtp: {})",
            self.is_verbose(),
            self.is_debugging(),
            self.get_rtp())
    }

}

<|endoftext|>


<commit_before>//! The general point of the optimizations provided here is to simplify something like:
//!
//! ```rust
//! match x {
//!     Ok(x) => Ok(x),
//!     Err(x) => Err(x)
//! }
//! ```
//!
//! into just `x`.

use crate::transform::{simplify, MirPass, MirSource};
use itertools::Itertools as _;
use rustc::mir::*;
use rustc::ty::{Ty, TyCtxt};
use rustc_target::abi::VariantIdx;

/// Simplifies arms of form `Variant(x) => Variant(x)` to just a move.
///
/// This is done by transforming basic blocks where the statements match:
///
/// ```rust
/// _LOCAL_TMP = ((_LOCAL_1 as Variant ).FIELD: TY );
/// ((_LOCAL_0 as Variant).FIELD: TY) = move _LOCAL_TMP;
/// discriminant(_LOCAL_0) = VAR_IDX;
/// ```
///
/// into:
///
/// ```rust
/// _LOCAL_0 = move _LOCAL_1
/// ```
pub struct SimplifyArmIdentity;

impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
    fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
        for bb in basic_blocks {
            // Need 3 statements:
            let (s0, s1, s2) = match &mut *bb.statements {
                [s0, s1, s2] => (s0, s1, s2),
                _ => continue,
            };

            // Pattern match on the form we want:
            let (local_tmp_s0, local_1, vf_s0) = match match_get_variant_field(s0) {
                None => continue,
                Some(x) => x,
            };
            let (local_tmp_s1, local_0, vf_s1) = match match_set_variant_field(s1) {
                None => continue,
                Some(x) => x,
            };
            if local_tmp_s0 != local_tmp_s1
                // The field-and-variant information match up.
                || vf_s0 != vf_s1
                // Source and target locals have the same type.
                // FIXME(Centril | oli-obk): possibly relax to same layout?
                || local_decls[local_0].ty != local_decls[local_1].ty
                // We're setting the discriminant of `local_0` to this variant.
                || Some((local_0, vf_s0.var_idx)) != match_set_discr(s2)
            {
                continue;
            }

            // Right shape; transform!
            match &mut s0.kind {
                StatementKind::Assign(box (place, rvalue)) => {
                    *place = local_0.into();
                    *rvalue = Rvalue::Use(Operand::Move(local_1.into()));
                }
                _ => unreachable!(),
            }
            s1.make_nop();
            s2.make_nop();
        }
    }
}

/// Match on:
/// ```rust
/// _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY);
/// ```
fn match_get_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local, VarField<'tcx>)> {
    match &stmt.kind {
        StatementKind::Assign(box (place_into, rvalue_from)) => match rvalue_from {
            Rvalue::Use(Operand::Copy(pf)) | Rvalue::Use(Operand::Move(pf)) => {
                let local_into = place_into.as_local()?;
                let (local_from, vf) = match_variant_field_place(&pf)?;
                Some((local_into, local_from, vf))
            }
            _ => None,
        },
        _ => None,
    }
}

/// Match on:
/// ```rust
/// ((_LOCAL_FROM as Variant).FIELD: TY) = move _LOCAL_INTO;
/// ```
fn match_set_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local, VarField<'tcx>)> {
    match &stmt.kind {
        StatementKind::Assign(box (place_from, rvalue_into)) => match rvalue_into {
            Rvalue::Use(Operand::Move(place_into)) => {
                let local_into = place_into.as_local()?;
                let (local_from, vf) = match_variant_field_place(&place_from)?;
                Some((local_into, local_from, vf))
            }
            _ => None,
        },
        _ => None,
    }
}

/// Match on:
/// ```rust
/// discriminant(_LOCAL_TO_SET) = VAR_IDX;
/// ```
fn match_set_discr<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, VariantIdx)> {
    match &stmt.kind {
        StatementKind::SetDiscriminant { place, variant_index } => {
            Some((place.as_local()?, *variant_index))
        }
        _ => None,
    }
}

#[derive(PartialEq)]
struct VarField<'tcx> {
    field: Field,
    field_ty: Ty<'tcx>,
    var_idx: VariantIdx,
}

/// Match on `((_LOCAL as Variant).FIELD: TY)`.
fn match_variant_field_place<'tcx>(place: &Place<'tcx>) -> Option<(Local, VarField<'tcx>)> {
    match place.as_ref() {
        PlaceRef {
            local,
            projection: &[ProjectionElem::Downcast(_, var_idx), ProjectionElem::Field(field, ty)],
        } => Some((local, VarField { field, field_ty: ty, var_idx })),
        _ => None,
    }
}

/// Simplifies `SwitchInt(_) -> [targets]`,
/// where all the `targets` have the same form,
/// into `goto -> target_first`.
pub struct SimplifyBranchSame;

impl<'tcx> MirPass<'tcx> for SimplifyBranchSame {
    fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
        let mut did_remove_blocks = false;
        let bbs = body.basic_blocks_mut();
        for bb_idx in bbs.indices() {
            let targets = match &bbs[bb_idx].terminator().kind {
                TerminatorKind::SwitchInt { targets, .. } => targets,
                _ => continue,
            };

            let mut iter_bbs_reachable = targets
                .iter()
                .map(|idx| (*idx, &bbs[*idx]))
                .filter(|(_, bb)| {
                    // Reaching `unreachable` is UB so assume it doesn't happen.
                    bb.terminator().kind != TerminatorKind::Unreachable
                    // But `asm!(...)` could abort the program,
                    // so we cannot assume that the `unreachable` terminator itself is reachable.
                    // FIXME(Centril): use a normalization pass instead of a check.
                    || bb.statements.iter().any(|stmt| match stmt.kind {
                        StatementKind::InlineAsm(..) => true,
                        _ => false,
                    })
                })
                .peekable();

            // We want to `goto -> bb_first`.
            let bb_first = iter_bbs_reachable.peek().map(|(idx, _)| *idx).unwrap_or(targets[0]);

            // All successor basic blocks should have the exact same form.
            let all_successors_equivalent =
                iter_bbs_reachable.map(|(_, bb)| bb).tuple_windows().all(|(bb_l, bb_r)| {
                    bb_l.is_cleanup == bb_r.is_cleanup
                        && bb_l.terminator().kind == bb_r.terminator().kind
                        && bb_l.statements.iter().eq_by(&bb_r.statements, |x, y| x.kind == y.kind)
                });

            if all_successors_equivalent {
                // Replace `SwitchInt(..) -> [bb_first, ..];` with a `goto -> bb_first;`.
                bbs[bb_idx].terminator_mut().kind = TerminatorKind::Goto { target: bb_first };
                did_remove_blocks = true;
            }
        }

        if did_remove_blocks {
            // We have dead blocks now, so remove those.
            simplify::remove_dead_blocks(body);
        }
    }
}
<commit_msg>simplify_try: address some of eddyb's comments<commit_after>//! The general point of the optimizations provided here is to simplify something like:
//!
//! ```rust
//! match x {
//!     Ok(x) => Ok(x),
//!     Err(x) => Err(x)
//! }
//! ```
//!
//! into just `x`.

use crate::transform::{simplify, MirPass, MirSource};
use itertools::Itertools as _;
use rustc::mir::*;
use rustc::ty::{Ty, TyCtxt};
use rustc_target::abi::VariantIdx;

/// Simplifies arms of form `Variant(x) => Variant(x)` to just a move.
///
/// This is done by transforming basic blocks where the statements match:
///
/// ```rust
/// _LOCAL_TMP = ((_LOCAL_1 as Variant ).FIELD: TY );
/// ((_LOCAL_0 as Variant).FIELD: TY) = move _LOCAL_TMP;
/// discriminant(_LOCAL_0) = VAR_IDX;
/// ```
///
/// into:
///
/// ```rust
/// _LOCAL_0 = move _LOCAL_1
/// ```
pub struct SimplifyArmIdentity;

impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
    fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
        for bb in basic_blocks {
            // Need 3 statements:
            let (s0, s1, s2) = match &mut *bb.statements {
                [s0, s1, s2] => (s0, s1, s2),
                _ => continue,
            };

            // Pattern match on the form we want:
            let (local_tmp_s0, local_1, vf_s0) = match match_get_variant_field(s0) {
                None => continue,
                Some(x) => x,
            };
            let (local_tmp_s1, local_0, vf_s1) = match match_set_variant_field(s1) {
                None => continue,
                Some(x) => x,
            };
            if local_tmp_s0 != local_tmp_s1
                // Avoid moving into ourselves.
                || local_0 == local_1
                // The field-and-variant information match up.
                || vf_s0 != vf_s1
                // Source and target locals have the same type.
                // FIXME(Centril | oli-obk): possibly relax to same layout?
                || local_decls[local_0].ty != local_decls[local_1].ty
                // We're setting the discriminant of `local_0` to this variant.
                || Some((local_0, vf_s0.var_idx)) != match_set_discr(s2)
            {
                continue;
            }

            // Right shape; transform!
            s0.source_info = s2.source_info;
            match &mut s0.kind {
                StatementKind::Assign(box (place, rvalue)) => {
                    *place = local_0.into();
                    *rvalue = Rvalue::Use(Operand::Move(local_1.into()));
                }
                _ => unreachable!(),
            }
            s1.make_nop();
            s2.make_nop();
        }
    }
}

/// Match on:
/// ```rust
/// _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY);
/// ```
fn match_get_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local, VarField<'tcx>)> {
    match &stmt.kind {
        StatementKind::Assign(box (place_into, rvalue_from)) => match rvalue_from {
            Rvalue::Use(Operand::Copy(pf)) | Rvalue::Use(Operand::Move(pf)) => {
                let local_into = place_into.as_local()?;
                let (local_from, vf) = match_variant_field_place(&pf)?;
                Some((local_into, local_from, vf))
            }
            _ => None,
        },
        _ => None,
    }
}

/// Match on:
/// ```rust
/// ((_LOCAL_FROM as Variant).FIELD: TY) = move _LOCAL_INTO;
/// ```
fn match_set_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local, VarField<'tcx>)> {
    match &stmt.kind {
        StatementKind::Assign(box (place_from, rvalue_into)) => match rvalue_into {
            Rvalue::Use(Operand::Move(place_into)) => {
                let local_into = place_into.as_local()?;
                let (local_from, vf) = match_variant_field_place(&place_from)?;
                Some((local_into, local_from, vf))
            }
            _ => None,
        },
        _ => None,
    }
}

/// Match on:
/// ```rust
/// discriminant(_LOCAL_TO_SET) = VAR_IDX;
/// ```
fn match_set_discr<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, VariantIdx)> {
    match &stmt.kind {
        StatementKind::SetDiscriminant { place, variant_index } => {
            Some((place.as_local()?, *variant_index))
        }
        _ => None,
    }
}

#[derive(PartialEq)]
struct VarField<'tcx> {
    field: Field,
    field_ty: Ty<'tcx>,
    var_idx: VariantIdx,
}

/// Match on `((_LOCAL as Variant).FIELD: TY)`.
fn match_variant_field_place<'tcx>(place: &Place<'tcx>) -> Option<(Local, VarField<'tcx>)> {
    match place.as_ref() {
        PlaceRef {
            local,
            projection: &[ProjectionElem::Downcast(_, var_idx), ProjectionElem::Field(field, ty)],
        } => Some((local, VarField { field, field_ty: ty, var_idx })),
        _ => None,
    }
}

/// Simplifies `SwitchInt(_) -> [targets]`,
/// where all the `targets` have the same form,
/// into `goto -> target_first`.
pub struct SimplifyBranchSame;

impl<'tcx> MirPass<'tcx> for SimplifyBranchSame {
    fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
        let mut did_remove_blocks = false;
        let bbs = body.basic_blocks_mut();
        for bb_idx in bbs.indices() {
            let targets = match &bbs[bb_idx].terminator().kind {
                TerminatorKind::SwitchInt { targets, .. } => targets,
                _ => continue,
            };

            let mut iter_bbs_reachable = targets
                .iter()
                .map(|idx| (*idx, &bbs[*idx]))
                .filter(|(_, bb)| {
                    // Reaching `unreachable` is UB so assume it doesn't happen.
                    bb.terminator().kind != TerminatorKind::Unreachable
                    // But `asm!(...)` could abort the program,
                    // so we cannot assume that the `unreachable` terminator itself is reachable.
                    // FIXME(Centril): use a normalization pass instead of a check.
                    || bb.statements.iter().any(|stmt| match stmt.kind {
                        StatementKind::InlineAsm(..) => true,
                        _ => false,
                    })
                })
                .peekable();

            // We want to `goto -> bb_first`.
            let bb_first = iter_bbs_reachable.peek().map(|(idx, _)| *idx).unwrap_or(targets[0]);

            // All successor basic blocks should have the exact same form.
            let all_successors_equivalent =
                iter_bbs_reachable.map(|(_, bb)| bb).tuple_windows().all(|(bb_l, bb_r)| {
                    bb_l.is_cleanup == bb_r.is_cleanup
                        && bb_l.terminator().kind == bb_r.terminator().kind
                        && bb_l.statements.iter().eq_by(&bb_r.statements, |x, y| x.kind == y.kind)
                });

            if all_successors_equivalent {
                // Replace `SwitchInt(..) -> [bb_first, ..];` with a `goto -> bb_first;`.
                bbs[bb_idx].terminator_mut().kind = TerminatorKind::Goto { target: bb_first };
                did_remove_blocks = true;
            }
        }

        if did_remove_blocks {
            // We have dead blocks now, so remove those.
            simplify::remove_dead_blocks(body);
        }
    }
}
<|endoftext|>


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

//! Generic API bits for implementing new services.

use std::marker::PhantomData;

use reqwest::{Method, RequestBuilder, Response, Url};
use reqwest::header::Headers;
use serde::Serialize;
use serde::de::DeserializeOwned;

use super::{ApiResult, ApiVersion, ApiVersionRequest, Session};
use super::auth::AuthMethod;
use super::utils;

/// Type of query parameters.
#[derive(Clone, Debug)]
pub struct Query(pub Vec<(String, String)>);

/// Information about API endpoint.
#[derive(Clone, Debug)]
pub struct ServiceInfo {
    /// Root endpoint.
    pub root_url: Url,
    /// Current API version (if supported).
    pub current_version: Option<ApiVersion>,
    /// Minimum API version (if supported).
    pub minimum_version: Option<ApiVersion>
}

/// Trait representing a service type.
pub trait ServiceType {
    /// Service type to pass to the catalog.
    fn catalog_type() -> &'static str;

    /// Get basic service information.
    fn service_info(endpoint: Url, auth: &AuthMethod) -> ApiResult<ServiceInfo>;
}

/// Trait representing a service with API version support.
pub trait ApiVersioning {
    /// Return headers to set for this API version.
    fn api_version_headers(version: ApiVersion) -> ApiResult<Headers>;
}

/// A service-specific wrapper around Session.
#[derive(Debug)]
pub struct ServiceWrapper<'session, Srv: ServiceType> {
    session: &'session Session,
    service_type: PhantomData<Srv>,
}

impl Query {
    /// Empty query.
    pub fn new() -> Query {
        Query(Vec::new())
    }

    /// Add an item to the query.
    pub fn push<K, V>(&mut self, param: K, value: V)
            where K: Into<String>, V: ToString {
        self.0.push((param.into(), value.to_string()))
    }

    /// Add a strng item to the query.
    pub fn push_str<K, V>(&mut self, param: K, value: V)
            where K: Into<String>, V: Into<String> {
        self.0.push((param.into(), value.into()))
    }
}

impl<'session, Srv: ServiceType> ServiceWrapper<'session, Srv> {
    /// Create a new wrapper for the specific service.
    pub fn new(session: &'session Session) -> ServiceWrapper<'session, Srv> {
        ServiceWrapper {
            session: session,
            service_type: PhantomData,
        }
    }

    /// Construct and endpoint for the given service from the path.
    pub fn get_endpoint<P>(&self, path: P, query: Query) -> ApiResult<Url>
            where P: IntoIterator, P::Item: AsRef<str> {
        let info = self.session.get_service_info::<Srv>(None)?;
        let mut url = utils::url::extend(info.root_url, path);
        let _ = url.query_pairs_mut().extend_pairs(query.0);
        Ok(url)
    }

    /// Make an HTTP request to the given service.
    pub fn request<P>(&self, method: Method, path: P, query: Query)
            -> ApiResult<RequestBuilder>
            where P: IntoIterator, P::Item: AsRef<str> {
        let url = self.get_endpoint(path, query)?;
        let headers = self.session.service_headers::<Srv>();
        trace!("Sending HTTP {} request to {} with {:?}",
               method, url, headers);
        let mut builder = self.session.request(method, url)?;
        {
            let _unused = builder.headers(headers);
        }
        Ok(builder)
    }

    /// Make an HTTP request with JSON body and JSON response.
    pub fn json<P, Req, Res>(&self, method: Method, path: P, query: Query,
                             body: &Req) -> ApiResult<Res>
            where Req: Serialize, Res: DeserializeOwned,
            P: IntoIterator, P::Item: AsRef<str> {
        let mut builder = self.request(method, path, query)?;
        builder.json(body).send()?.error_for_status()?.json().map_err(From::from)
    }

    /// Make a GET request returning a JSON.
    pub fn get_json<P, Res>(&self, path: P, query: Query) -> ApiResult<Res>
            where Res: DeserializeOwned, P: IntoIterator, P::Item: AsRef<str> {
        self.request(Method::Get, path, query)?.send()?.error_for_status()?
            .json().map_err(From::from)
    }

    /// Make a POST request sending and returning a JSON.
    pub fn post_json<P, Req, Res>(&self, path: P, query: Query, body: &Req)
            -> ApiResult<Res> where Req: Serialize, Res: DeserializeOwned,
            P: IntoIterator, P::Item: AsRef<str> {
        self.json(Method::Post, path, query, body)
    }

    /// Make a POST request sending and returning a JSON.
    pub fn put_json<P, Req, Res>(&self, path: P, query: Query, body: &Req)
            -> ApiResult<Res> where Req: Serialize, Res: DeserializeOwned,
            P: IntoIterator, P::Item: AsRef<str> {
        self.json(Method::Put, path, query, body)
    }

    /// Make a PATCH request sending and returning a JSON.
    pub fn patch_json<P, Req, Res>(&self, path: P, query: Query, body: &Req)
            -> ApiResult<Res> where Req: Serialize, Res: DeserializeOwned,
            P: IntoIterator, P::Item: AsRef<str> {
        self.json(Method::Patch, path, query, body)
    }

    /// Make a DELETE request.
    pub fn delete<P>(&self, path: P, query: Query) -> ApiResult<Response>
            where P: IntoIterator, P::Item: AsRef<str> {
        self.request(Method::Delete, path, query)?.send()?
            .error_for_status().map_err(From::from)
    }
}

impl<'session, Srv: ServiceType> Clone for ServiceWrapper<'session, Srv> {
    fn clone(&self) -> ServiceWrapper<'session, Srv> {
        ServiceWrapper {
            session: self.session,
            service_type: PhantomData,
        }
    }
}

impl ServiceInfo {
    /// Pick an API version.
    pub fn pick_api_version(&self, request: ApiVersionRequest)
            -> Option<ApiVersion> {
        match request {
            ApiVersionRequest::Minimum =>
                self.minimum_version,
            ApiVersionRequest::Latest =>
                self.current_version,
            ApiVersionRequest::Exact(req) => {
                self.current_version.and_then(|max| {
                    match self.minimum_version {
                        Some(min) if req >= min && req <= max => Some(req),
                        None if req == max => Some(req),
                        _ => None
                    }
                })
            },
            ApiVersionRequest::Choice(vec) => {
                if vec.is_empty() {
                    return None;
                }

                self.current_version.and_then(|max| {
                    match self.minimum_version {
                        Some(min) => vec.into_iter().filter(|x| {
                            *x >= min && *x <= max
                        }).max(),
                        None =>vec.into_iter().find(|x| *x == max)
                    }
                })
            }
        }
    }
}

#[cfg(test)]
pub mod test {
    use reqwest::Url;

    use super::super::{ApiVersion, ApiVersionRequest};
    use super::ServiceInfo;

    fn service_info(min: Option<u16>, max: Option<u16>) -> ServiceInfo {
        ServiceInfo {
            root_url: Url::parse("http://127.0.0.1").unwrap(),
            minimum_version: min.map(|x| ApiVersion(2, x)),
            current_version: max.map(|x| ApiVersion(2, x)),
        }
    }

    #[test]
    fn test_pick_version_exact() {
        let info = service_info(Some(1), Some(24));
        let version = ApiVersion(2, 22);
        let result = info.pick_api_version(ApiVersionRequest::Exact(version))
            .unwrap();
        assert_eq!(result, version);
    }

    #[test]
    fn test_pick_version_exact_mismatch() {
        let info = service_info(Some(1), Some(24));
        let version = ApiVersion(2, 25);
        let res1 = info.pick_api_version(ApiVersionRequest::Exact(version));
        assert!(res1.is_none());
        let version2 = ApiVersion(1, 11);
        let res2 = info.pick_api_version(ApiVersionRequest::Exact(version2));
        assert!(res2.is_none());
    }

    #[test]
    fn test_pick_version_exact_current_only() {
        let info = service_info(None, Some(24));
        let version = ApiVersion(2, 24);
        let result = info.pick_api_version(ApiVersionRequest::Exact(version))
            .unwrap();
        assert_eq!(result, version);
    }

    #[test]
    fn test_pick_version_exact_current_only_mismatch() {
        let info = service_info(None, Some(24));
        let version = ApiVersion(2, 22);
        let result = info.pick_api_version(ApiVersionRequest::Exact(version));
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_minimum() {
        let info = service_info(Some(1), Some(24));
        let result = info.pick_api_version(ApiVersionRequest::Minimum)
            .unwrap();
        assert_eq!(result, ApiVersion(2, 1));
    }

    #[test]
    fn test_pick_version_minimum_unknown() {
        let info = service_info(None, Some(24));
        let result = info.pick_api_version(ApiVersionRequest::Minimum);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_latest() {
        let info = service_info(Some(1), Some(24));
        let result = info.pick_api_version(ApiVersionRequest::Latest)
            .unwrap();
        assert_eq!(result, ApiVersion(2, 24));
    }

    #[test]
    fn test_pick_version_latest_unknown() {
        let info = service_info(Some(1), None);
        let result = info.pick_api_version(ApiVersionRequest::Latest);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_choice() {
        let info = service_info(Some(1), Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 2),
                          ApiVersion(2, 22), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice))
            .unwrap();
        assert_eq!(result, ApiVersion(2, 22));
    }

    #[test]
    fn test_pick_version_choice_mismatch() {
        let info = service_info(Some(1), Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice));
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_choice_current_only() {
        let info = service_info(None, Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 2),
                          ApiVersion(2, 24), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice))
            .unwrap();
        assert_eq!(result, ApiVersion(2, 24));
    }

    #[test]
    fn test_pick_version_choice_current_only_mismatch() {
        let info = service_info(None, Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 2),
                          ApiVersion(2, 22), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice));
        assert!(result.is_none());
    }
}
<commit_msg>refactor(service): remove generic Path from ServiceWrapper<commit_after>// Copyright 2017 Dmitry Tantsur <divius.inside@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Generic API bits for implementing new services.

use std::marker::PhantomData;

use reqwest::{Method, RequestBuilder, Response, Url};
use reqwest::header::Headers;
use serde::Serialize;
use serde::de::DeserializeOwned;

use super::{ApiResult, ApiVersion, ApiVersionRequest, Session};
use super::auth::AuthMethod;
use super::utils;

/// Type of query parameters.
#[derive(Clone, Debug)]
pub struct Query(pub Vec<(String, String)>);

/// Information about API endpoint.
#[derive(Clone, Debug)]
pub struct ServiceInfo {
    /// Root endpoint.
    pub root_url: Url,
    /// Current API version (if supported).
    pub current_version: Option<ApiVersion>,
    /// Minimum API version (if supported).
    pub minimum_version: Option<ApiVersion>
}

/// Trait representing a service type.
pub trait ServiceType {
    /// Service type to pass to the catalog.
    fn catalog_type() -> &'static str;

    /// Get basic service information.
    fn service_info(endpoint: Url, auth: &AuthMethod) -> ApiResult<ServiceInfo>;
}

/// Trait representing a service with API version support.
pub trait ApiVersioning {
    /// Return headers to set for this API version.
    fn api_version_headers(version: ApiVersion) -> ApiResult<Headers>;
}

/// A service-specific wrapper around Session.
#[derive(Debug)]
pub struct ServiceWrapper<'session, Srv: ServiceType> {
    session: &'session Session,
    service_type: PhantomData<Srv>,
}

impl Query {
    /// Empty query.
    pub fn new() -> Query {
        Query(Vec::new())
    }

    /// Add an item to the query.
    pub fn push<K, V>(&mut self, param: K, value: V)
            where K: Into<String>, V: ToString {
        self.0.push((param.into(), value.to_string()))
    }

    /// Add a strng item to the query.
    pub fn push_str<K, V>(&mut self, param: K, value: V)
            where K: Into<String>, V: Into<String> {
        self.0.push((param.into(), value.into()))
    }
}

impl<'session, Srv: ServiceType> ServiceWrapper<'session, Srv> {
    /// Create a new wrapper for the specific service.
    pub fn new(session: &'session Session) -> ServiceWrapper<'session, Srv> {
        ServiceWrapper {
            session: session,
            service_type: PhantomData,
        }
    }

    /// Construct and endpoint for the given service from the path.
    pub fn get_endpoint(&self, path: &[&str], query: Query) -> ApiResult<Url> {
        let info = self.session.get_service_info::<Srv>(None)?;
        let mut url = utils::url::extend(info.root_url, path);
        let _ = url.query_pairs_mut().extend_pairs(query.0);
        Ok(url)
    }

    /// Make an HTTP request to the given service.
    pub fn request(&self, method: Method, path: &[&str], query: Query)
            -> ApiResult<RequestBuilder> {
        let url = self.get_endpoint(path, query)?;
        let headers = self.session.service_headers::<Srv>();
        trace!("Sending HTTP {} request to {} with {:?}",
               method, url, headers);
        let mut builder = self.session.request(method, url)?;
        {
            let _unused = builder.headers(headers);
        }
        Ok(builder)
    }

    /// Make an HTTP request with JSON body and JSON response.
    pub fn json<Req, Res>(&self, method: Method, path: &[&str], query: Query,
                          body: &Req) -> ApiResult<Res>
            where Req: Serialize, Res: DeserializeOwned {
        let mut builder = self.request(method, path, query)?;
        builder.json(body).send()?.error_for_status()?.json().map_err(From::from)
    }

    /// Make a GET request returning a JSON.
    pub fn get_json<Res>(&self, path: &[&str], query: Query) -> ApiResult<Res>
            where Res: DeserializeOwned {
        self.request(Method::Get, path, query)?.send()?.error_for_status()?
            .json().map_err(From::from)
    }

    /// Make a POST request sending and returning a JSON.
    pub fn post_json<Req, Res>(&self, path: &[&str], query: Query, body: &Req)
            -> ApiResult<Res> where Req: Serialize, Res: DeserializeOwned {
        self.json(Method::Post, path, query, body)
    }

    /// Make a POST request sending and returning a JSON.
    pub fn put_json<Req, Res>(&self, path: &[&str], query: Query, body: &Req)
            -> ApiResult<Res> where Req: Serialize, Res: DeserializeOwned {
        self.json(Method::Put, path, query, body)
    }

    /// Make a PATCH request sending and returning a JSON.
    pub fn patch_json<Req, Res>(&self, path: &[&str], query: Query, body: &Req)
            -> ApiResult<Res> where Req: Serialize, Res: DeserializeOwned {
        self.json(Method::Patch, path, query, body)
    }

    /// Make a DELETE request.
    pub fn delete(&self, path: &[&str], query: Query) -> ApiResult<Response> {
        self.request(Method::Delete, path, query)?.send()?
            .error_for_status().map_err(From::from)
    }
}

impl<'session, Srv: ServiceType> Clone for ServiceWrapper<'session, Srv> {
    fn clone(&self) -> ServiceWrapper<'session, Srv> {
        ServiceWrapper {
            session: self.session,
            service_type: PhantomData,
        }
    }
}

impl ServiceInfo {
    /// Pick an API version.
    pub fn pick_api_version(&self, request: ApiVersionRequest)
            -> Option<ApiVersion> {
        match request {
            ApiVersionRequest::Minimum =>
                self.minimum_version,
            ApiVersionRequest::Latest =>
                self.current_version,
            ApiVersionRequest::Exact(req) => {
                self.current_version.and_then(|max| {
                    match self.minimum_version {
                        Some(min) if req >= min && req <= max => Some(req),
                        None if req == max => Some(req),
                        _ => None
                    }
                })
            },
            ApiVersionRequest::Choice(vec) => {
                if vec.is_empty() {
                    return None;
                }

                self.current_version.and_then(|max| {
                    match self.minimum_version {
                        Some(min) => vec.into_iter().filter(|x| {
                            *x >= min && *x <= max
                        }).max(),
                        None =>vec.into_iter().find(|x| *x == max)
                    }
                })
            }
        }
    }
}

#[cfg(test)]
pub mod test {
    use reqwest::Url;

    use super::super::{ApiVersion, ApiVersionRequest};
    use super::ServiceInfo;

    fn service_info(min: Option<u16>, max: Option<u16>) -> ServiceInfo {
        ServiceInfo {
            root_url: Url::parse("http://127.0.0.1").unwrap(),
            minimum_version: min.map(|x| ApiVersion(2, x)),
            current_version: max.map(|x| ApiVersion(2, x)),
        }
    }

    #[test]
    fn test_pick_version_exact() {
        let info = service_info(Some(1), Some(24));
        let version = ApiVersion(2, 22);
        let result = info.pick_api_version(ApiVersionRequest::Exact(version))
            .unwrap();
        assert_eq!(result, version);
    }

    #[test]
    fn test_pick_version_exact_mismatch() {
        let info = service_info(Some(1), Some(24));
        let version = ApiVersion(2, 25);
        let res1 = info.pick_api_version(ApiVersionRequest::Exact(version));
        assert!(res1.is_none());
        let version2 = ApiVersion(1, 11);
        let res2 = info.pick_api_version(ApiVersionRequest::Exact(version2));
        assert!(res2.is_none());
    }

    #[test]
    fn test_pick_version_exact_current_only() {
        let info = service_info(None, Some(24));
        let version = ApiVersion(2, 24);
        let result = info.pick_api_version(ApiVersionRequest::Exact(version))
            .unwrap();
        assert_eq!(result, version);
    }

    #[test]
    fn test_pick_version_exact_current_only_mismatch() {
        let info = service_info(None, Some(24));
        let version = ApiVersion(2, 22);
        let result = info.pick_api_version(ApiVersionRequest::Exact(version));
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_minimum() {
        let info = service_info(Some(1), Some(24));
        let result = info.pick_api_version(ApiVersionRequest::Minimum)
            .unwrap();
        assert_eq!(result, ApiVersion(2, 1));
    }

    #[test]
    fn test_pick_version_minimum_unknown() {
        let info = service_info(None, Some(24));
        let result = info.pick_api_version(ApiVersionRequest::Minimum);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_latest() {
        let info = service_info(Some(1), Some(24));
        let result = info.pick_api_version(ApiVersionRequest::Latest)
            .unwrap();
        assert_eq!(result, ApiVersion(2, 24));
    }

    #[test]
    fn test_pick_version_latest_unknown() {
        let info = service_info(Some(1), None);
        let result = info.pick_api_version(ApiVersionRequest::Latest);
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_choice() {
        let info = service_info(Some(1), Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 2),
                          ApiVersion(2, 22), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice))
            .unwrap();
        assert_eq!(result, ApiVersion(2, 22));
    }

    #[test]
    fn test_pick_version_choice_mismatch() {
        let info = service_info(Some(1), Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice));
        assert!(result.is_none());
    }

    #[test]
    fn test_pick_version_choice_current_only() {
        let info = service_info(None, Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 2),
                          ApiVersion(2, 24), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice))
            .unwrap();
        assert_eq!(result, ApiVersion(2, 24));
    }

    #[test]
    fn test_pick_version_choice_current_only_mismatch() {
        let info = service_info(None, Some(24));
        let choice = vec![ApiVersion(2, 0), ApiVersion(2, 2),
                          ApiVersion(2, 22), ApiVersion(2, 25)];
        let result = info.pick_api_version(ApiVersionRequest::Choice(choice));
        assert!(result.is_none());
    }
}
<|endoftext|>


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

#![crate_name = "snowmew"]
#![feature(globs)]

extern crate "snowmew-core"         as _core;
extern crate "snowmew-graphics"     as _graphics;
extern crate "snowmew-loader"       as _loader;
extern crate "snowmew-physics"      as _physics;
extern crate "snowmew-position"     as _position;
extern crate "snowmew-render-mux"   as _render;
extern crate "snowmew-render-data"  as _render_data;

pub use _core::common::ObjectKey as ObjectKey;

pub mod render {
    pub use _render::RenderFactory as DefaultRender;
    pub use _render_data::{
        RenderData,
        Renderable
    };
    pub use _core::{
        RenderFactory,
        Render,
    };
}

pub mod graphics {
    pub use _graphics::{
        default,
        Drawable,
        Geometry,
        geometry,
        Graphics,
        GraphicsData,
        light,
        Light,
        material,
        Material,
        texture,
        Texture,
        texture_atlas,
        VertexBuffer,
        VertexBufferIter,
    };
}

pub mod position {
    pub use _position::{
        MatrixManager,
        Deltas,
        ComputedPositionGL,
        ComputedPosition,
        CalcPositionsCl,
        PositionData,
        Positions
    };
}

pub mod core {
    pub use _core::{
        DisplayConfig,
        Render,
        IOManager,
    };

    pub use _core::io::{
        InputHandle,
        Window,
    };

    pub use _core::game::Game;
}

pub mod common {
    pub use _core::common::{
        Common,
        CommonData,
        ObjectKey,
        Duplicate
    };
}

pub mod config  {
    pub use _core::SnowmewConfig as SnowmewConfig;
}

pub mod input {
    pub use _core::input::*;
    pub use _core::input_integrator::{
        InputIntegrator,
        InputIntegratorGameData,
        InputIntegratorState,
    };
    pub use _core::input_integrator::input_integrator as integrator;
}<commit_msg>rexport debugger<commit_after>//   Copyright 2014 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#![crate_name = "snowmew"]
#![feature(globs)]

extern crate "snowmew-core"         as _core;
extern crate "snowmew-graphics"     as _graphics;
extern crate "snowmew-loader"       as _loader;
extern crate "snowmew-physics"      as _physics;
extern crate "snowmew-position"     as _position;
extern crate "snowmew-render-mux"   as _render;
extern crate "snowmew-render-data"  as _render_data;

pub use _core::common::ObjectKey as ObjectKey;

pub mod render {
    pub use _render::RenderFactory as DefaultRender;
    pub use _render_data::{
        RenderData,
        Renderable
    };
    pub use _core::{
        RenderFactory,
        Render,
    };
}

pub mod graphics {
    pub use _graphics::{
        default,
        Drawable,
        Geometry,
        geometry,
        Graphics,
        GraphicsData,
        light,
        Light,
        material,
        Material,
        texture,
        Texture,
        texture_atlas,
        VertexBuffer,
        VertexBufferIter,
    };
}

pub mod position {
    pub use _position::{
        MatrixManager,
        Deltas,
        ComputedPositionGL,
        ComputedPosition,
        CalcPositionsCl,
        PositionData,
        Positions
    };
}

pub mod core {
    pub use _core::{
        DisplayConfig,
        Render,
        IOManager,
    };

    pub use _core::io::{
        InputHandle,
        Window,
    };

    pub use _core::game::Game;
}

pub mod common {
    pub use _core::common::{
        Common,
        CommonData,
        ObjectKey,
        Duplicate
    };
}

pub mod config  {
    pub use _core::SnowmewConfig as SnowmewConfig;
}

pub mod input {
    pub use _core::input::*;
    pub use _core::input_integrator::{
        InputIntegrator,
        InputIntegratorGameData,
        InputIntegratorState,
    };
    pub use _core::input_integrator::input_integrator as integrator;
}

pub mod debug {
    pub use _core::debugger::{
        Debugger,
        DebuggerGameData,
        debugger
    };
}<|endoftext|>


<commit_before>//! Interfaces for accessing and managing sprints

// Third party
use url::form_urlencoded;

// Ours
use {Board, Jira, Result, SearchOptions};

#[derive(Debug)]
pub struct Sprints {
    jira: Jira,
}

#[derive(Deserialize, Debug)]
pub struct Sprint {
    pub id: u64,
    #[serde(rename = "self")]
    pub self_link: String,
    pub name: String,
    pub state: Option<String>,
    #[serde(rename = "startDate")]
    pub start_date: Option<String>,
    #[serde(rename = "endDate")]
    pub end_date: Option<String>,
    #[serde(rename = "completeDate")]
    pub complete_date: Option<String>,
    #[serde(rename = "originBoardId")]
    pub origin_board_id: Option<u64>,
}

#[derive(Deserialize, Debug)]
pub struct SprintResults {
    #[serde(rename = "maxResults")]
    pub max_results: u64,
    #[serde(rename = "startAt")]
    pub start_at: u64,
    #[serde(rename = "isLast")]
    pub is_last: bool,
    pub values: Vec<Sprint>,
}

impl Sprints {
    pub fn new(jira: &Jira) -> Sprints {
        Sprints { jira: jira.clone() }
    }

    /// returns a single page of board results
    /// https://docs.atlassian.com/jira-software/REST/latest/#agile/1.0/board/{boardId}/sprint-getAllSprints
    pub fn list(&self, board: &Board, options: &SearchOptions) -> Result<SprintResults> {
        let mut path = vec![
            "/board/".to_owned(),
            board.id.to_string(),
            "/sprint".to_owned(),
        ];
        let query_options = options.serialize().unwrap_or_default();
        let query = form_urlencoded::Serializer::new(query_options).finish();

        path.push(query);

        self.jira
            .get::<SprintResults>("agile", path.join("?").as_ref())
    }

    /// runs a type why may be used to iterate over consecutive pages of results
    /// https://docs.atlassian.com/jira-software/REST/latest/#agile/1.0/board-getAllBoards
    pub fn iter<'a>(
        &self,
        board: &'a Board,
        options: &'a SearchOptions,
    ) -> Result<SprintsIter<'a>> {
        SprintsIter::new(board, options, &self.jira)
    }
}

/// provides an iterator over multiple pages of search results
#[derive(Debug)]
pub struct SprintsIter<'a> {
    jira: Jira,
    board: &'a Board,
    results: SprintResults,
    search_options: &'a SearchOptions,
}

impl<'a> SprintsIter<'a> {
    fn new(board: &'a Board, options: &'a SearchOptions, jira: &Jira) -> Result<Self> {
        let results = jira.sprints().list(board, options)?;
        Ok(SprintsIter {
            board,
            jira: jira.clone(),
            results,
            search_options: options,
        })
    }

    fn more(&self) -> bool {
        self.results.is_last
    }
}

impl<'a> Iterator for SprintsIter<'a> {
    type Item = Sprint;
    fn next(&mut self) -> Option<Sprint> {
        self.results.values.pop().or_else(|| {
            if self.more() {
                match self.jira.sprints().list(
                    self.board,
                    &self.search_options
                        .as_builder()
                        .max_results(self.results.max_results)
                        .start_at(self.results.start_at + self.results.max_results)
                        .build(),
                ) {
                    Ok(new_results) => {
                        self.results = new_results;
                        self.results.values.pop()
                    }
                    _ => None,
                }
            } else {
                None
            }
        })
    }
}
<commit_msg>Fixed sprints URL<commit_after>//! Interfaces for accessing and managing sprints

// Third party
use url::form_urlencoded;

// Ours
use {Board, Jira, Result, SearchOptions};

#[derive(Debug)]
pub struct Sprints {
    jira: Jira,
}

#[derive(Deserialize, Debug)]
pub struct Sprint {
    pub id: u64,
    #[serde(rename = "self")]
    pub self_link: String,
    pub name: String,
    pub state: Option<String>,
    #[serde(rename = "startDate")]
    pub start_date: Option<String>,
    #[serde(rename = "endDate")]
    pub end_date: Option<String>,
    #[serde(rename = "completeDate")]
    pub complete_date: Option<String>,
    #[serde(rename = "originBoardId")]
    pub origin_board_id: Option<u64>,
}

#[derive(Deserialize, Debug)]
pub struct SprintResults {
    #[serde(rename = "maxResults")]
    pub max_results: u64,
    #[serde(rename = "startAt")]
    pub start_at: u64,
    #[serde(rename = "isLast")]
    pub is_last: bool,
    pub values: Vec<Sprint>,
}

impl Sprints {
    pub fn new(jira: &Jira) -> Sprints {
        Sprints { jira: jira.clone() }
    }

    /// returns a single page of board results
    /// https://docs.atlassian.com/jira-software/REST/latest/#agile/1.0/board/{boardId}/sprint-getAllSprints
    pub fn list(&self, board: &Board, options: &SearchOptions) -> Result<SprintResults> {
        let mut path = vec![format!("/board/{}/sprint", board.id.to_string())];
        let query_options = options.serialize().unwrap_or_default();
        let query = form_urlencoded::Serializer::new(query_options).finish();

        path.push(query);

        self.jira
            .get::<SprintResults>("agile", path.join("?").as_ref())
    }

    /// runs a type why may be used to iterate over consecutive pages of results
    /// https://docs.atlassian.com/jira-software/REST/latest/#agile/1.0/board-getAllBoards
    pub fn iter<'a>(
        &self,
        board: &'a Board,
        options: &'a SearchOptions,
    ) -> Result<SprintsIter<'a>> {
        SprintsIter::new(board, options, &self.jira)
    }
}

/// provides an iterator over multiple pages of search results
#[derive(Debug)]
pub struct SprintsIter<'a> {
    jira: Jira,
    board: &'a Board,
    results: SprintResults,
    search_options: &'a SearchOptions,
}

impl<'a> SprintsIter<'a> {
    fn new(board: &'a Board, options: &'a SearchOptions, jira: &Jira) -> Result<Self> {
        let results = jira.sprints().list(board, options)?;
        Ok(SprintsIter {
            board,
            jira: jira.clone(),
            results,
            search_options: options,
        })
    }

    fn more(&self) -> bool {
        self.results.is_last
    }
}

impl<'a> Iterator for SprintsIter<'a> {
    type Item = Sprint;
    fn next(&mut self) -> Option<Sprint> {
        self.results.values.pop().or_else(|| {
            if self.more() {
                match self.jira.sprints().list(
                    self.board,
                    &self.search_options
                        .as_builder()
                        .max_results(self.results.max_results)
                        .start_at(self.results.start_at + self.results.max_results)
                        .build(),
                ) {
                    Ok(new_results) => {
                        self.results = new_results;
                        self.results.values.pop()
                    }
                    _ => None,
                }
            } else {
                None
            }
        })
    }
}
<|endoftext|>


<commit_before>extern crate winapi;
extern crate "kernel32-sys" as win;

/**
 * Compulsory readup:
 * 1. http://qualapps.blogspot.se/2010/05/understanding-readdirectorychangesw.html
 * 2. http://stackoverflow.com/questions/339776/asynchronous-readdirectorychangesw
 * 3. https://msdn.microsoft.com/en-us/library/windows/desktop/aa363862%28v=vs.85%29.aspx
 * 4. https://msdn.microsoft.com/en-us/library/windows/desktop/aa365465%28v=vs.85%29.aspx
 *
 * The Windows implementation uses IOCP, I/O Completion Port(s) since it is regarded as most performant (read 1).
 * FindFirstChangeNotification API is **NOT** used.
 */

use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::RwLock;
use std::sync::Arc;
use std::marker::Send;

use fsnotify::*;

mod ffi;
use self::ffi::*;

struct WinFsNotifier<'a> {
	config:	Configuration<'a>,
	sender:	EventSender<'a>,

	// Indicates if the notifier is open or not, setting it to false closes it.
	open: Arc<RwLock<bool>>,
//	paths:	Arc<RwLock<HashMap<HANDLE, PathBuf>>>,

	// Handle to completion port:
	port:	HANDLE,
	add_queue: Vec<PathBuf>,
}

fsnotify_drop!( WinFsNotifier );

impl<'a> WinFsNotifier<'a> {
	fn run( &mut self ) {

	}
}

impl<'a> FsNotifier<'a> for WinFsNotifier<'a> {
	fn new( sender: EventSender<'a>, config: Configuration<'a> ) -> NotifyResult<Self> {
		// Retrieve IOCP.
		let port = try!( create_io_completion_port( INVALID_HANDLE_VALUE, 0 as HANDLE ) );

		Ok( WinFsNotifier {
			config: config,
			sender: sender,

			open:	Arc::new( RwLock::new( true ) ),
			port:	port,
		//	paths:	Arc::new( RwLock::new( HashMap::new() ) ),

			add_queue: vec![],
		} )
	}

	fn watch( &mut self, path: &Path ) -> R {
		// Are we using recursion?
		//let recurse = self.config.is_recursive() as BOOL;
		// Add to queue, handle in start().
		self.add_queue.push( path.to_path_buf() );

		not_implemented!();
	}

	fn unwatch( &mut self, path: &Path ) -> R {
		not_implemented!();
	}

	fn close( &mut self ) -> R {
		not_implemented!();
	}
}
<commit_msg>win: instruction queue.<commit_after>extern crate winapi;
extern crate "kernel32-sys" as win;

/**
 * Compulsory readup:
 * 1. http://qualapps.blogspot.se/2010/05/understanding-readdirectorychangesw.html
 * 2. http://stackoverflow.com/questions/339776/asynchronous-readdirectorychangesw
 * 3. https://msdn.microsoft.com/en-us/library/windows/desktop/aa363862%28v=vs.85%29.aspx
 * 4. https://msdn.microsoft.com/en-us/library/windows/desktop/aa365465%28v=vs.85%29.aspx
 *
 * The Windows implementation uses IOCP, I/O Completion Port(s) since it is regarded as most performant (read 1).
 * FindFirstChangeNotification API is **NOT** used.
 */

use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::RwLock;
use std::sync::Arc;
use std::marker::Send;

use fsnotify::*;

mod ffi;
use self::ffi::*;

struct WinFsNotifier<'a> {
	config:	Configuration<'a>,
	sender:	EventSender<'a>,

	// Indicates if the notifier is open or not, setting it to false closes it.
	open: Arc<RwLock<bool>>,
//	paths:	Arc<RwLock<HashMap<HANDLE, PathBuf>>>,

	// Handle to completion port:
	port:	HANDLE,
	queue:	Arc<RwLock<Vec<Instruction>>>,
}

fsnotify_drop!( WinFsNotifier );

enum InsType {
    ADD, REMOVE
}

struct Instruction {
    instruction: InsType,
    path: PathBuf,
}

impl<'a> WinFsNotifier<'a> {
	fn run( &mut self ) {

	}
}

impl<'a> FsNotifier<'a> for WinFsNotifier<'a> {
	fn new( sender: EventSender<'a>, config: Configuration<'a> ) -> NotifyResult<Self> {
		// Retrieve IOCP.
		let port = try!( create_io_completion_port( INVALID_HANDLE_VALUE, 0 as HANDLE ) );

		Ok( WinFsNotifier {
			config: config,
			sender: sender,

			open:	Arc::new( RwLock::new( true ) ),
			port:	port,
		//	paths:	Arc::new( RwLock::new( HashMap::new() ) ),

			queue:	Arc::new( RwLock::new( vec![] ) ),
		} )
	}

	fn watch( &mut self, path: &Path ) -> R {
		// Are we using recursion?
		//let recurse = self.config.is_recursive() as BOOL;
		// Add to queue, handle in start().
	//	self.add_queue.push( path.to_path_buf() );

		not_implemented!();
	}

	fn unwatch( &mut self, path: &Path ) -> R {
		not_implemented!();
	}

	fn close( &mut self ) -> R {
		not_implemented!();
	}
}
<|endoftext|>


<commit_before>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
//! USER procedure declarations, constant definitions and macros
//2193
pub const WHEEL_DELTA: ::DWORD = 120;
//2206
pub const XBUTTON1: ::DWORD = 0x0001;
pub const XBUTTON2: ::DWORD = 0x0002;
//3082
#[repr(C)] #[derive(Copy)] pub struct CREATESTRUCTA {
    lpCreateParams: ::LPVOID,
    hInstance: ::HINSTANCE,
    hMenu: ::HMENU,
    hwndParent: ::HWND,
    cy: ::c_int,
    cx: ::c_int,
    y: ::c_int,
    x: ::c_int,
    style: ::LONG,
    lpszName: ::LPCSTR,
    lpszClass: ::LPCSTR,
    dwExStyle: ::DWORD,
}
pub type LPCREATESTRUCTA = *mut CREATESTRUCTA;
#[repr(C)] #[derive(Copy)] pub struct CREATESTRUCTW {
    lpCreateParams: ::LPVOID,
    hInstance: ::HINSTANCE,
    hMenu: ::HMENU,
    hwndParent: ::HWND,
    cy: ::c_int,
    cx: ::c_int,
    y: ::c_int,
    x: ::c_int,
    style: ::LONG,
    lpszName: ::LPCWSTR,
    lpszClass: ::LPCWSTR,
    dwExStyle: ::DWORD,
}
pub type LPCREATESTRUCTW = *mut CREATESTRUCTW;
//3400
pub const PM_NOREMOVE: ::UINT = 0x0000;
pub const PM_REMOVE: ::UINT = 0x0001;
pub const PM_NOYIELD: ::UINT = 0x0002;
pub const PM_QS_INPUT: ::UINT = QS_INPUT << 16;
pub const PM_QS_POSTMESSAGE: ::UINT = (QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16;
pub const PM_QS_PAINT: ::UINT = QS_PAINT << 16;
pub const PM_QS_SENDMESSAGE: ::UINT = QS_SENDMESSAGE << 16;
//5741
pub const KEYEVENTF_EXTENDEDKEY: ::DWORD = 0x0001;
pub const KEYEVENTF_KEYUP: ::DWORD = 0x0002;
pub const KEYEVENTF_UNICODE: ::DWORD = 0x0004;
pub const KEYEVENTF_SCANCODE: ::DWORD = 0x0008;
pub const MOUSEEVENTF_MOVE: ::DWORD = 0x0001;
pub const MOUSEEVENTF_LEFTDOWN: ::DWORD = 0x0002;
pub const MOUSEEVENTF_LEFTUP: ::DWORD = 0x0004;
pub const MOUSEEVENTF_RIGHTDOWN: ::DWORD = 0x0008;
pub const MOUSEEVENTF_RIGHTUP: ::DWORD = 0x0010;
pub const MOUSEEVENTF_MIDDLEDOWN: ::DWORD = 0x0020;
pub const MOUSEEVENTF_MIDDLEUP: ::DWORD = 0x0040;
pub const MOUSEEVENTF_XDOWN: ::DWORD = 0x0080;
pub const MOUSEEVENTF_XUP: ::DWORD = 0x0100;
pub const MOUSEEVENTF_WHEEL: ::DWORD = 0x0800;
pub const MOUSEEVENTF_HWHEEL: ::DWORD = 0x01000;
pub const MOUSEEVENTF_MOVE_NOCOALESCE: ::DWORD = 0x2000;
pub const MOUSEEVENTF_VIRTUALDESK: ::DWORD = 0x4000;
pub const MOUSEEVENTF_ABSOLUTE: ::DWORD = 0x8000;
#[repr(C)] #[derive(Copy)] pub struct MOUSEINPUT {
    pub dx: ::LONG,
    pub dy: ::LONG,
    pub mouseData: ::DWORD,
    pub dwFlags: ::DWORD,
    pub time: ::DWORD,
    pub dwExtraInfo: ::ULONG_PTR,
}
pub type PMOUSEINPUT = *mut MOUSEINPUT;
pub type LPMOUSEINPUT = *mut MOUSEINPUT;
#[repr(C)] #[derive(Copy)] pub struct KEYBDINPUT {
    pub wVk: ::WORD,
    pub wScan: ::WORD,
    pub dwFlags: ::DWORD,
    pub time: ::DWORD,
    pub dwExtraInfo: ::ULONG_PTR,
}
pub type PKEYBDINPUT = *mut KEYBDINPUT;
pub type LPKEYBDINPUT = *mut KEYBDINPUT;
#[repr(C)] #[derive(Copy)] pub struct HARDWAREINPUT {
    pub uMsg: ::DWORD,
    pub wParamL: ::WORD,
    pub wParamH: ::WORD,
}
pub type PHARDWAREINPUT = *mut HARDWAREINPUT;
pub type LPHARDWAREINPUT= *mut HARDWAREINPUT;
pub const INPUT_MOUSE: ::DWORD = 0;
pub const INPUT_KEYBOARD: ::DWORD = 1;
pub const INPUT_HARDWARE: ::DWORD = 2;
#[repr(C)] #[derive(Copy)] pub struct INPUT {
    pub type_: ::DWORD,
    pub union_: (), // FIXME - Use unions or unsafe enums here somehow
}
pub type PINPUT = *mut INPUT;
pub type LPINPUT = *mut INPUT;
//6573
pub const QS_KEY: ::DWORD = 0x0001;
pub const QS_MOUSEMOVE: ::DWORD = 0x0002;
pub const QS_MOUSEBUTTON: ::DWORD = 0x0004;
pub const QS_POSTMESSAGE: ::DWORD = 0x0008;
pub const QS_TIMER: ::DWORD = 0x0010;
pub const QS_PAINT: ::DWORD = 0x0020;
pub const QS_SENDMESSAGE: ::DWORD = 0x0040;
pub const QS_HOTKEY: ::DWORD = 0x0080;
pub const QS_ALLPOSTMESSAGE: ::DWORD = 0x0100;
pub const QS_RAWINPUT: ::DWORD = 0x0400;
pub const QS_TOUCH: ::DWORD = 0x0800;
pub const QS_POINTER: ::DWORD = 0x1000;
pub const QS_MOUSE: ::DWORD = QS_MOUSEMOVE | QS_MOUSEBUTTON;
pub const QS_INPUT: ::DWORD = QS_MOUSE | QS_KEY | QS_RAWINPUT | QS_TOUCH | QS_POINTER;
pub const QS_ALLEVENTS: ::DWORD = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY;
pub const QS_ALLINPUT: ::DWORD = QS_INPUT | QS_POSTMESSAGE | QS_TIMER
    | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE;
//6789
pub const SM_CXSCREEN: ::c_int = 0;
pub const SM_CYSCREEN: ::c_int = 1;
pub const SM_CXVSCROLL: ::c_int = 2;
pub const SM_CYHSCROLL: ::c_int = 3;
pub const SM_CYCAPTION: ::c_int = 4;
pub const SM_CXBORDER: ::c_int = 5;
pub const SM_CYBORDER: ::c_int = 6;
pub const SM_CXDLGFRAME: ::c_int = 7;
pub const SM_CYDLGFRAME: ::c_int = 8;
pub const SM_CYVTHUMB: ::c_int = 9;
pub const SM_CXHTHUMB: ::c_int = 10;
pub const SM_CXICON: ::c_int = 11;
pub const SM_CYICON: ::c_int = 12;
pub const SM_CXCURSOR: ::c_int = 13;
pub const SM_CYCURSOR: ::c_int = 14;
pub const SM_CYMENU: ::c_int = 15;
pub const SM_CXFULLSCREEN: ::c_int = 16;
pub const SM_CYFULLSCREEN: ::c_int = 17;
pub const SM_CYKANJIWINDOW: ::c_int = 18;
pub const SM_MOUSEPRESENT: ::c_int = 19;
pub const SM_CYVSCROLL: ::c_int = 20;
pub const SM_CXHSCROLL: ::c_int = 21;
pub const SM_DEBUG: ::c_int = 22;
pub const SM_SWAPBUTTON: ::c_int = 23;
pub const SM_RESERVED1: ::c_int = 24;
pub const SM_RESERVED2: ::c_int = 25;
pub const SM_RESERVED3: ::c_int = 26;
pub const SM_RESERVED4: ::c_int = 27;
pub const SM_CXMIN: ::c_int = 28;
pub const SM_CYMIN: ::c_int = 29;
pub const SM_CXSIZE: ::c_int = 30;
pub const SM_CYSIZE: ::c_int = 31;
pub const SM_CXFRAME: ::c_int = 32;
pub const SM_CYFRAME: ::c_int = 33;
pub const SM_CXMINTRACK: ::c_int = 34;
pub const SM_CYMINTRACK: ::c_int = 35;
pub const SM_CXDOUBLECLK: ::c_int = 36;
pub const SM_CYDOUBLECLK: ::c_int = 37;
pub const SM_CXICONSPACING: ::c_int = 38;
pub const SM_CYICONSPACING: ::c_int = 39;
pub const SM_MENUDROPALIGNMENT: ::c_int = 40;
pub const SM_PENWINDOWS: ::c_int = 41;
pub const SM_DBCSENABLED: ::c_int = 42;
pub const SM_CMOUSEBUTTONS: ::c_int = 43;
pub const SM_CXFIXEDFRAME: ::c_int = SM_CXDLGFRAME;
pub const SM_CYFIXEDFRAME: ::c_int = SM_CYDLGFRAME;
pub const SM_CXSIZEFRAME: ::c_int = SM_CXFRAME;
pub const SM_CYSIZEFRAME: ::c_int = SM_CYFRAME;
pub const SM_SECURE: ::c_int = 44;
pub const SM_CXEDGE: ::c_int = 45;
pub const SM_CYEDGE: ::c_int = 46;
pub const SM_CXMINSPACING: ::c_int = 47;
pub const SM_CYMINSPACING: ::c_int = 48;
pub const SM_CXSMICON: ::c_int = 49;
pub const SM_CYSMICON: ::c_int = 50;
pub const SM_CYSMCAPTION: ::c_int = 51;
pub const SM_CXSMSIZE: ::c_int = 52;
pub const SM_CYSMSIZE: ::c_int = 53;
pub const SM_CXMENUSIZE: ::c_int = 54;
pub const SM_CYMENUSIZE: ::c_int = 55;
pub const SM_ARRANGE: ::c_int = 56;
pub const SM_CXMINIMIZED: ::c_int = 57;
pub const SM_CYMINIMIZED: ::c_int = 58;
pub const SM_CXMAXTRACK: ::c_int = 59;
pub const SM_CYMAXTRACK: ::c_int = 60;
pub const SM_CXMAXIMIZED: ::c_int = 61;
pub const SM_CYMAXIMIZED: ::c_int = 62;
pub const SM_NETWORK: ::c_int = 63;
pub const SM_CLEANBOOT: ::c_int = 67;
pub const SM_CXDRAG: ::c_int = 68;
pub const SM_CYDRAG: ::c_int = 69;
pub const SM_SHOWSOUNDS: ::c_int = 70;
pub const SM_CXMENUCHECK: ::c_int = 71;
pub const SM_CYMENUCHECK: ::c_int = 72;
pub const SM_SLOWMACHINE: ::c_int = 73;
pub const SM_MIDEASTENABLED: ::c_int = 74;
pub const SM_MOUSEWHEELPRESENT: ::c_int = 75;
pub const SM_XVIRTUALSCREEN: ::c_int = 76;
pub const SM_YVIRTUALSCREEN: ::c_int = 77;
pub const SM_CXVIRTUALSCREEN: ::c_int = 78;
pub const SM_CYVIRTUALSCREEN: ::c_int = 79;
pub const SM_CMONITORS: ::c_int = 80;
pub const SM_SAMEDISPLAYFORMAT: ::c_int = 81;
pub const SM_IMMENABLED: ::c_int = 82;
pub const SM_CXFOCUSBORDER: ::c_int = 83;
pub const SM_CYFOCUSBORDER: ::c_int = 84;
pub const SM_TABLETPC: ::c_int = 86;
pub const SM_MEDIACENTER: ::c_int = 87;
pub const SM_STARTER: ::c_int = 88;
pub const SM_SERVERR2: ::c_int = 89;
pub const SM_MOUSEHORIZONTALWHEELPRESENT: ::c_int = 91;
pub const SM_CXPADDEDBORDER: ::c_int = 92;
pub const SM_DIGITIZER: ::c_int = 94;
pub const SM_MAXIMUMTOUCHES: ::c_int = 95;
pub const SM_CMETRICS: ::c_int = 97;
pub const SM_REMOTESESSION: ::c_int = 0x1000;
pub const SM_SHUTTINGDOWN: ::c_int = 0x2000;
pub const SM_REMOTECONTROL: ::c_int = 0x2001;
pub const SM_CARETBLINKINGENABLED: ::c_int = 0x2002;
pub const SM_CONVERTIBLESLATEMODE: ::c_int = 0x2003;
pub const SM_SYSTEMDOCKED: ::c_int = 0x2004;
<commit_msg>Experimental INPUT_generic<commit_after>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
//! USER procedure declarations, constant definitions and macros
//2193
pub const WHEEL_DELTA: ::DWORD = 120;
//2206
pub const XBUTTON1: ::DWORD = 0x0001;
pub const XBUTTON2: ::DWORD = 0x0002;
//3082
#[repr(C)] #[derive(Copy)] pub struct CREATESTRUCTA {
    lpCreateParams: ::LPVOID,
    hInstance: ::HINSTANCE,
    hMenu: ::HMENU,
    hwndParent: ::HWND,
    cy: ::c_int,
    cx: ::c_int,
    y: ::c_int,
    x: ::c_int,
    style: ::LONG,
    lpszName: ::LPCSTR,
    lpszClass: ::LPCSTR,
    dwExStyle: ::DWORD,
}
pub type LPCREATESTRUCTA = *mut CREATESTRUCTA;
#[repr(C)] #[derive(Copy)] pub struct CREATESTRUCTW {
    lpCreateParams: ::LPVOID,
    hInstance: ::HINSTANCE,
    hMenu: ::HMENU,
    hwndParent: ::HWND,
    cy: ::c_int,
    cx: ::c_int,
    y: ::c_int,
    x: ::c_int,
    style: ::LONG,
    lpszName: ::LPCWSTR,
    lpszClass: ::LPCWSTR,
    dwExStyle: ::DWORD,
}
pub type LPCREATESTRUCTW = *mut CREATESTRUCTW;
//3400
pub const PM_NOREMOVE: ::UINT = 0x0000;
pub const PM_REMOVE: ::UINT = 0x0001;
pub const PM_NOYIELD: ::UINT = 0x0002;
pub const PM_QS_INPUT: ::UINT = QS_INPUT << 16;
pub const PM_QS_POSTMESSAGE: ::UINT = (QS_POSTMESSAGE | QS_HOTKEY | QS_TIMER) << 16;
pub const PM_QS_PAINT: ::UINT = QS_PAINT << 16;
pub const PM_QS_SENDMESSAGE: ::UINT = QS_SENDMESSAGE << 16;
//5741
pub const KEYEVENTF_EXTENDEDKEY: ::DWORD = 0x0001;
pub const KEYEVENTF_KEYUP: ::DWORD = 0x0002;
pub const KEYEVENTF_UNICODE: ::DWORD = 0x0004;
pub const KEYEVENTF_SCANCODE: ::DWORD = 0x0008;
pub const MOUSEEVENTF_MOVE: ::DWORD = 0x0001;
pub const MOUSEEVENTF_LEFTDOWN: ::DWORD = 0x0002;
pub const MOUSEEVENTF_LEFTUP: ::DWORD = 0x0004;
pub const MOUSEEVENTF_RIGHTDOWN: ::DWORD = 0x0008;
pub const MOUSEEVENTF_RIGHTUP: ::DWORD = 0x0010;
pub const MOUSEEVENTF_MIDDLEDOWN: ::DWORD = 0x0020;
pub const MOUSEEVENTF_MIDDLEUP: ::DWORD = 0x0040;
pub const MOUSEEVENTF_XDOWN: ::DWORD = 0x0080;
pub const MOUSEEVENTF_XUP: ::DWORD = 0x0100;
pub const MOUSEEVENTF_WHEEL: ::DWORD = 0x0800;
pub const MOUSEEVENTF_HWHEEL: ::DWORD = 0x01000;
pub const MOUSEEVENTF_MOVE_NOCOALESCE: ::DWORD = 0x2000;
pub const MOUSEEVENTF_VIRTUALDESK: ::DWORD = 0x4000;
pub const MOUSEEVENTF_ABSOLUTE: ::DWORD = 0x8000;
#[repr(C)] #[derive(Copy)] pub struct MOUSEINPUT {
    pub dx: ::LONG,
    pub dy: ::LONG,
    pub mouseData: ::DWORD,
    pub dwFlags: ::DWORD,
    pub time: ::DWORD,
    pub dwExtraInfo: ::ULONG_PTR,
}
pub type PMOUSEINPUT = *mut MOUSEINPUT;
pub type LPMOUSEINPUT = *mut MOUSEINPUT;
#[repr(C)] #[derive(Copy)] pub struct KEYBDINPUT {
    pub wVk: ::WORD,
    pub wScan: ::WORD,
    pub dwFlags: ::DWORD,
    pub time: ::DWORD,
    pub dwExtraInfo: ::ULONG_PTR,
}
pub type PKEYBDINPUT = *mut KEYBDINPUT;
pub type LPKEYBDINPUT = *mut KEYBDINPUT;
#[repr(C)] #[derive(Copy)] pub struct HARDWAREINPUT {
    pub uMsg: ::DWORD,
    pub wParamL: ::WORD,
    pub wParamH: ::WORD,
}
pub type PHARDWAREINPUT = *mut HARDWAREINPUT;
pub type LPHARDWAREINPUT= *mut HARDWAREINPUT;
pub const INPUT_MOUSE: ::DWORD = 0;
pub const INPUT_KEYBOARD: ::DWORD = 1;
pub const INPUT_HARDWARE: ::DWORD = 2;
#[repr(C)] #[derive(Copy)] pub struct INPUT {
    pub type_: ::DWORD,
    pub union_: (), // FIXME - Use unions or unsafe enums here somehow
}
/// A highly experimental version of INPUT. You have been warned.
#[repr(C)] #[derive(Copy)] pub struct INPUT_generic<T> {
    pub type_: ::DWORD,
    pub union_: T,
}
pub type PINPUT = *mut INPUT;
pub type LPINPUT = *mut INPUT;
//6573
pub const QS_KEY: ::DWORD = 0x0001;
pub const QS_MOUSEMOVE: ::DWORD = 0x0002;
pub const QS_MOUSEBUTTON: ::DWORD = 0x0004;
pub const QS_POSTMESSAGE: ::DWORD = 0x0008;
pub const QS_TIMER: ::DWORD = 0x0010;
pub const QS_PAINT: ::DWORD = 0x0020;
pub const QS_SENDMESSAGE: ::DWORD = 0x0040;
pub const QS_HOTKEY: ::DWORD = 0x0080;
pub const QS_ALLPOSTMESSAGE: ::DWORD = 0x0100;
pub const QS_RAWINPUT: ::DWORD = 0x0400;
pub const QS_TOUCH: ::DWORD = 0x0800;
pub const QS_POINTER: ::DWORD = 0x1000;
pub const QS_MOUSE: ::DWORD = QS_MOUSEMOVE | QS_MOUSEBUTTON;
pub const QS_INPUT: ::DWORD = QS_MOUSE | QS_KEY | QS_RAWINPUT | QS_TOUCH | QS_POINTER;
pub const QS_ALLEVENTS: ::DWORD = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY;
pub const QS_ALLINPUT: ::DWORD = QS_INPUT | QS_POSTMESSAGE | QS_TIMER
    | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE;
//6789
pub const SM_CXSCREEN: ::c_int = 0;
pub const SM_CYSCREEN: ::c_int = 1;
pub const SM_CXVSCROLL: ::c_int = 2;
pub const SM_CYHSCROLL: ::c_int = 3;
pub const SM_CYCAPTION: ::c_int = 4;
pub const SM_CXBORDER: ::c_int = 5;
pub const SM_CYBORDER: ::c_int = 6;
pub const SM_CXDLGFRAME: ::c_int = 7;
pub const SM_CYDLGFRAME: ::c_int = 8;
pub const SM_CYVTHUMB: ::c_int = 9;
pub const SM_CXHTHUMB: ::c_int = 10;
pub const SM_CXICON: ::c_int = 11;
pub const SM_CYICON: ::c_int = 12;
pub const SM_CXCURSOR: ::c_int = 13;
pub const SM_CYCURSOR: ::c_int = 14;
pub const SM_CYMENU: ::c_int = 15;
pub const SM_CXFULLSCREEN: ::c_int = 16;
pub const SM_CYFULLSCREEN: ::c_int = 17;
pub const SM_CYKANJIWINDOW: ::c_int = 18;
pub const SM_MOUSEPRESENT: ::c_int = 19;
pub const SM_CYVSCROLL: ::c_int = 20;
pub const SM_CXHSCROLL: ::c_int = 21;
pub const SM_DEBUG: ::c_int = 22;
pub const SM_SWAPBUTTON: ::c_int = 23;
pub const SM_RESERVED1: ::c_int = 24;
pub const SM_RESERVED2: ::c_int = 25;
pub const SM_RESERVED3: ::c_int = 26;
pub const SM_RESERVED4: ::c_int = 27;
pub const SM_CXMIN: ::c_int = 28;
pub const SM_CYMIN: ::c_int = 29;
pub const SM_CXSIZE: ::c_int = 30;
pub const SM_CYSIZE: ::c_int = 31;
pub const SM_CXFRAME: ::c_int = 32;
pub const SM_CYFRAME: ::c_int = 33;
pub const SM_CXMINTRACK: ::c_int = 34;
pub const SM_CYMINTRACK: ::c_int = 35;
pub const SM_CXDOUBLECLK: ::c_int = 36;
pub const SM_CYDOUBLECLK: ::c_int = 37;
pub const SM_CXICONSPACING: ::c_int = 38;
pub const SM_CYICONSPACING: ::c_int = 39;
pub const SM_MENUDROPALIGNMENT: ::c_int = 40;
pub const SM_PENWINDOWS: ::c_int = 41;
pub const SM_DBCSENABLED: ::c_int = 42;
pub const SM_CMOUSEBUTTONS: ::c_int = 43;
pub const SM_CXFIXEDFRAME: ::c_int = SM_CXDLGFRAME;
pub const SM_CYFIXEDFRAME: ::c_int = SM_CYDLGFRAME;
pub const SM_CXSIZEFRAME: ::c_int = SM_CXFRAME;
pub const SM_CYSIZEFRAME: ::c_int = SM_CYFRAME;
pub const SM_SECURE: ::c_int = 44;
pub const SM_CXEDGE: ::c_int = 45;
pub const SM_CYEDGE: ::c_int = 46;
pub const SM_CXMINSPACING: ::c_int = 47;
pub const SM_CYMINSPACING: ::c_int = 48;
pub const SM_CXSMICON: ::c_int = 49;
pub const SM_CYSMICON: ::c_int = 50;
pub const SM_CYSMCAPTION: ::c_int = 51;
pub const SM_CXSMSIZE: ::c_int = 52;
pub const SM_CYSMSIZE: ::c_int = 53;
pub const SM_CXMENUSIZE: ::c_int = 54;
pub const SM_CYMENUSIZE: ::c_int = 55;
pub const SM_ARRANGE: ::c_int = 56;
pub const SM_CXMINIMIZED: ::c_int = 57;
pub const SM_CYMINIMIZED: ::c_int = 58;
pub const SM_CXMAXTRACK: ::c_int = 59;
pub const SM_CYMAXTRACK: ::c_int = 60;
pub const SM_CXMAXIMIZED: ::c_int = 61;
pub const SM_CYMAXIMIZED: ::c_int = 62;
pub const SM_NETWORK: ::c_int = 63;
pub const SM_CLEANBOOT: ::c_int = 67;
pub const SM_CXDRAG: ::c_int = 68;
pub const SM_CYDRAG: ::c_int = 69;
pub const SM_SHOWSOUNDS: ::c_int = 70;
pub const SM_CXMENUCHECK: ::c_int = 71;
pub const SM_CYMENUCHECK: ::c_int = 72;
pub const SM_SLOWMACHINE: ::c_int = 73;
pub const SM_MIDEASTENABLED: ::c_int = 74;
pub const SM_MOUSEWHEELPRESENT: ::c_int = 75;
pub const SM_XVIRTUALSCREEN: ::c_int = 76;
pub const SM_YVIRTUALSCREEN: ::c_int = 77;
pub const SM_CXVIRTUALSCREEN: ::c_int = 78;
pub const SM_CYVIRTUALSCREEN: ::c_int = 79;
pub const SM_CMONITORS: ::c_int = 80;
pub const SM_SAMEDISPLAYFORMAT: ::c_int = 81;
pub const SM_IMMENABLED: ::c_int = 82;
pub const SM_CXFOCUSBORDER: ::c_int = 83;
pub const SM_CYFOCUSBORDER: ::c_int = 84;
pub const SM_TABLETPC: ::c_int = 86;
pub const SM_MEDIACENTER: ::c_int = 87;
pub const SM_STARTER: ::c_int = 88;
pub const SM_SERVERR2: ::c_int = 89;
pub const SM_MOUSEHORIZONTALWHEELPRESENT: ::c_int = 91;
pub const SM_CXPADDEDBORDER: ::c_int = 92;
pub const SM_DIGITIZER: ::c_int = 94;
pub const SM_MAXIMUMTOUCHES: ::c_int = 95;
pub const SM_CMETRICS: ::c_int = 97;
pub const SM_REMOTESESSION: ::c_int = 0x1000;
pub const SM_SHUTTINGDOWN: ::c_int = 0x2000;
pub const SM_REMOTECONTROL: ::c_int = 0x2001;
pub const SM_CARETBLINKINGENABLED: ::c_int = 0x2002;
pub const SM_CONVERTIBLESLATEMODE: ::c_int = 0x2003;
pub const SM_SYSTEMDOCKED: ::c_int = 0x2004;
<|endoftext|>


<commit_before>extern mod rsfml;

use rsfml::window::{ContextSettings, VideoMode, event};
use rsfml::graphics::{RenderWindow, sfClose};

mod cpu;

#[cfg(target_os="macos")]
#[start]
fn start(argc: int, argv: **u8) -> int {
    std::rt::start_on_main_thread(argc, argv, main)
}

fn main() {
    // Create the window of the application
    let setting = ContextSettings::default();
    let mut window = match RenderWindow::new(VideoMode::new_init(320, 160, 32), ~"rustchip", sfClose, &setting) {
        Some(window) => window,
        None => fail!("Cannot create a new Render Window.")
    };
    window.set_framerate_limit(60);
	let mut system = ::cpu::Cpu::new();

	system.load("/Users/derekguenther/Downloads/c8games/TETRIS");
	//system.print_mem();

    while window.is_open() {
        loop {
            match window.poll_event() {
                event::Closed => { window.close()}
                event::NoEvent => { break }
                _ => {}
            }
        }
		system.cycle();
        system.draw(&mut window);
    }

}<commit_msg>Moved hardcoded ROM path to an argument<commit_after>extern mod rsfml;

use rsfml::window::{ContextSettings, VideoMode, event};
use rsfml::graphics::{RenderWindow, sfClose};

use std::os::args;

mod cpu;

#[cfg(target_os="macos")]
#[start]
fn start(argc: int, argv: **u8) -> int {
    std::rt::start_on_main_thread(argc, argv, main)
}

fn main() {
    let arg_list = args();
    if (arg_list.len() <= 1) {
        fail!("You must pass in a ROM for rustchip to read.");
    }

    // Create the window of the application
    let setting = ContextSettings::default();
    let mut window = match RenderWindow::new(VideoMode::new_init(320, 160, 32), ~"rustchip", sfClose, &setting) {
        Some(window) => window,
        None => fail!("Cannot create a new Render Window.")
    };
    window.set_framerate_limit(60);
	let mut system = ::cpu::Cpu::new();

	system.load(arg_list[1]);

    while window.is_open() {
        loop {
            match window.poll_event() {
                event::Closed => { window.close()}
                event::NoEvent => { break }
                _ => {}
            }
        }
		system.cycle();
        system.draw(&mut window);
    }

}<|endoftext|>


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

//! Code to save/load the dep-graph from files.

use rustc_data_structures::fx::FxHashMap;
use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc::ty::maps::OnDiskCache;
use rustc::util::common::time_ext;
use rustc_serialize::Decodable as RustcDecodable;
use rustc_serialize::opaque::Decoder;
use std::path::Path;
use std;

use super::data::*;
use super::fs::*;
use super::file_format;
use super::work_product;

pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    if !tcx.dep_graph.is_fully_enabled() {
        return
    }

    tcx.allocate_metadata_dep_nodes();
    tcx.precompute_in_scope_traits_hashes();
}

type WorkProductMap = FxHashMap<WorkProductId, WorkProduct>;

pub enum LoadResult<T> {
    Ok { data: T },
    DataOutOfDate,
    Error { message: String },
}

impl LoadResult<(PreviousDepGraph, WorkProductMap)> {
    pub fn open(self, sess: &Session) -> (PreviousDepGraph, WorkProductMap) {
        match self {
            LoadResult::Error { message } => {
                sess.warn(&message);
                (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
            },
            LoadResult::DataOutOfDate => {
                if let Err(err) = delete_all_session_dir_contents(sess) {
                    sess.err(&format!("Failed to delete invalidated or incompatible \
                                      incremental compilation session directory contents `{}`: {}.",
                                      dep_graph_path(sess).display(), err));
                }
                (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
            }
            LoadResult::Ok { data } => data
        }
    }
}

fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec<u8>, usize)> {
    match file_format::read_file(report_incremental_info, path) {
        Ok(Some(data_and_pos)) => LoadResult::Ok {
            data: data_and_pos
        },
        Ok(None) => {
            // The file either didn't exist or was produced by an incompatible
            // compiler version. Neither is an error.
            LoadResult::DataOutOfDate
        }
        Err(err) => {
            LoadResult::Error {
                message: format!("could not load dep-graph from `{}`: {}",
                                  path.display(), err)
            }
        }
    }
}

fn delete_dirty_work_product(sess: &Session,
                             swp: SerializedWorkProduct) {
    debug!("delete_dirty_work_product({:?})", swp);
    work_product::delete_workproduct_files(sess, &swp.work_product);
}

/// Either a result that has already be computed or a
/// handle that will let us wait until it is computed
/// by a background thread.
pub enum MaybeAsync<T> {
    Sync(T),
    Async(std::thread::JoinHandle<T>)
}
impl<T> MaybeAsync<T> {
    pub fn open(self) -> std::thread::Result<T> {
        match self {
            MaybeAsync::Sync(result) => Ok(result),
            MaybeAsync::Async(handle) => handle.join()
        }
    }
}

/// Launch a thread and load the dependency graph in the background.
pub fn load_dep_graph(sess: &Session) ->
    MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>
{
    // Since `sess` isn't `Sync`, we perform all accesses to `sess`
    // before we fire the background thread.

    let time_passes = sess.time_passes();

    if sess.opts.incremental.is_none() {
        // No incremental compilation.
        return MaybeAsync::Sync(LoadResult::Ok {
            data: (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
        });
    }

    // Calling `sess.incr_comp_session_dir()` will panic if `sess.opts.incremental.is_none()`.
    // Fortunately, we just checked that this isn't the case.
    let path = dep_graph_path_from(&sess.incr_comp_session_dir());
    let report_incremental_info = sess.opts.debugging_opts.incremental_info;
    let expected_hash = sess.opts.dep_tracking_hash();

    let mut prev_work_products = FxHashMap();

    // If we are only building with -Zquery-dep-graph but without an actual
    // incr. comp. session directory, we exit here. Otherwise we'd fail
    // when trying to load work products.
    if sess.incr_comp_session_dir_opt().is_some() {
        let work_products_path = work_products_path(sess);
        let load_result = load_data(report_incremental_info, &work_products_path);

        if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
            // Decode the list of work_products
            let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
            let work_products: Vec<SerializedWorkProduct> =
                RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| {
                    let msg = format!("Error decoding `work-products` from incremental \
                                    compilation session directory: {}", e);
                    sess.fatal(&msg[..])
                });

            for swp in work_products {
                let mut all_files_exist = true;
                for &(_, ref file_name) in swp.work_product.saved_files.iter() {
                    let path = in_incr_comp_dir_sess(sess, file_name);
                    if !path.exists() {
                        all_files_exist = false;

                        if sess.opts.debugging_opts.incremental_info {
                            eprintln!("incremental: could not find file for work \
                                    product: {}", path.display());
                        }
                    }
                }

                if all_files_exist {
                    debug!("reconcile_work_products: all files for {:?} exist", swp);
                    prev_work_products.insert(swp.id, swp.work_product);
                } else {
                    debug!("reconcile_work_products: some file for {:?} does not exist", swp);
                    delete_dirty_work_product(sess, swp);
                }
            }
        }
    }

    MaybeAsync::Async(std::thread::spawn(move || {
        time_ext(time_passes, None, "background load prev dep-graph", move || {
            match load_data(report_incremental_info, &path) {
                LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
                LoadResult::Error { message } => LoadResult::Error { message },
                LoadResult::Ok { data: (bytes, start_pos) } => {

                    let mut decoder = Decoder::new(&bytes, start_pos);
                    let prev_commandline_args_hash = u64::decode(&mut decoder)
                        .expect("Error reading commandline arg hash from cached dep-graph");

                    if prev_commandline_args_hash != expected_hash {
                        if report_incremental_info {
                            println!("[incremental] completely ignoring cache because of \
                                    differing commandline arguments");
                        }
                        // We can't reuse the cache, purge it.
                        debug!("load_dep_graph_new: differing commandline arg hashes");

                        // No need to do any further work
                        return LoadResult::DataOutOfDate;
                    }

                    let dep_graph = SerializedDepGraph::decode(&mut decoder)
                        .expect("Error reading cached dep-graph");

                    LoadResult::Ok { data: (PreviousDepGraph::new(dep_graph), prev_work_products) }
                }
            }
        })
    }))
}

pub fn load_query_result_cache<'sess>(sess: &'sess Session) -> OnDiskCache<'sess> {
    if sess.opts.incremental.is_none() ||
       !sess.opts.debugging_opts.incremental_queries {
        return OnDiskCache::new_empty(sess.codemap());
    }

    match load_data(sess.opts.debugging_opts.incremental_info, &query_cache_path(sess)) {
        LoadResult::Ok{ data: (bytes, start_pos) } => OnDiskCache::new(sess, bytes, start_pos),
        _ => OnDiskCache::new_empty(sess.codemap())
    }
}
<commit_msg>Fix comment<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Code to save/load the dep-graph from files.

use rustc_data_structures::fx::FxHashMap;
use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc::ty::maps::OnDiskCache;
use rustc::util::common::time_ext;
use rustc_serialize::Decodable as RustcDecodable;
use rustc_serialize::opaque::Decoder;
use std::path::Path;
use std;

use super::data::*;
use super::fs::*;
use super::file_format;
use super::work_product;

pub fn dep_graph_tcx_init<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    if !tcx.dep_graph.is_fully_enabled() {
        return
    }

    tcx.allocate_metadata_dep_nodes();
    tcx.precompute_in_scope_traits_hashes();
}

type WorkProductMap = FxHashMap<WorkProductId, WorkProduct>;

pub enum LoadResult<T> {
    Ok { data: T },
    DataOutOfDate,
    Error { message: String },
}

impl LoadResult<(PreviousDepGraph, WorkProductMap)> {
    pub fn open(self, sess: &Session) -> (PreviousDepGraph, WorkProductMap) {
        match self {
            LoadResult::Error { message } => {
                sess.warn(&message);
                (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
            },
            LoadResult::DataOutOfDate => {
                if let Err(err) = delete_all_session_dir_contents(sess) {
                    sess.err(&format!("Failed to delete invalidated or incompatible \
                                      incremental compilation session directory contents `{}`: {}.",
                                      dep_graph_path(sess).display(), err));
                }
                (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
            }
            LoadResult::Ok { data } => data
        }
    }
}

fn load_data(report_incremental_info: bool, path: &Path) -> LoadResult<(Vec<u8>, usize)> {
    match file_format::read_file(report_incremental_info, path) {
        Ok(Some(data_and_pos)) => LoadResult::Ok {
            data: data_and_pos
        },
        Ok(None) => {
            // The file either didn't exist or was produced by an incompatible
            // compiler version. Neither is an error.
            LoadResult::DataOutOfDate
        }
        Err(err) => {
            LoadResult::Error {
                message: format!("could not load dep-graph from `{}`: {}",
                                  path.display(), err)
            }
        }
    }
}

fn delete_dirty_work_product(sess: &Session,
                             swp: SerializedWorkProduct) {
    debug!("delete_dirty_work_product({:?})", swp);
    work_product::delete_workproduct_files(sess, &swp.work_product);
}

/// Either a result that has already be computed or a
/// handle that will let us wait until it is computed
/// by a background thread.
pub enum MaybeAsync<T> {
    Sync(T),
    Async(std::thread::JoinHandle<T>)
}
impl<T> MaybeAsync<T> {
    pub fn open(self) -> std::thread::Result<T> {
        match self {
            MaybeAsync::Sync(result) => Ok(result),
            MaybeAsync::Async(handle) => handle.join()
        }
    }
}

/// Launch a thread and load the dependency graph in the background.
pub fn load_dep_graph(sess: &Session) ->
    MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>
{
    // Since `sess` isn't `Sync`, we perform all accesses to `sess`
    // before we fire the background thread.

    let time_passes = sess.time_passes();

    if sess.opts.incremental.is_none() {
        // No incremental compilation.
        return MaybeAsync::Sync(LoadResult::Ok {
            data: (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
        });
    }

    // Calling `sess.incr_comp_session_dir()` will panic if `sess.opts.incremental.is_none()`.
    // Fortunately, we just checked that this isn't the case.
    let path = dep_graph_path_from(&sess.incr_comp_session_dir());
    let report_incremental_info = sess.opts.debugging_opts.incremental_info;
    let expected_hash = sess.opts.dep_tracking_hash();

    let mut prev_work_products = FxHashMap();

    // If we are only building with -Zquery-dep-graph but without an actual
    // incr. comp. session directory, we skip this. Otherwise we'd fail
    // when trying to load work products.
    if sess.incr_comp_session_dir_opt().is_some() {
        let work_products_path = work_products_path(sess);
        let load_result = load_data(report_incremental_info, &work_products_path);

        if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
            // Decode the list of work_products
            let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
            let work_products: Vec<SerializedWorkProduct> =
                RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| {
                    let msg = format!("Error decoding `work-products` from incremental \
                                    compilation session directory: {}", e);
                    sess.fatal(&msg[..])
                });

            for swp in work_products {
                let mut all_files_exist = true;
                for &(_, ref file_name) in swp.work_product.saved_files.iter() {
                    let path = in_incr_comp_dir_sess(sess, file_name);
                    if !path.exists() {
                        all_files_exist = false;

                        if sess.opts.debugging_opts.incremental_info {
                            eprintln!("incremental: could not find file for work \
                                    product: {}", path.display());
                        }
                    }
                }

                if all_files_exist {
                    debug!("reconcile_work_products: all files for {:?} exist", swp);
                    prev_work_products.insert(swp.id, swp.work_product);
                } else {
                    debug!("reconcile_work_products: some file for {:?} does not exist", swp);
                    delete_dirty_work_product(sess, swp);
                }
            }
        }
    }

    MaybeAsync::Async(std::thread::spawn(move || {
        time_ext(time_passes, None, "background load prev dep-graph", move || {
            match load_data(report_incremental_info, &path) {
                LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
                LoadResult::Error { message } => LoadResult::Error { message },
                LoadResult::Ok { data: (bytes, start_pos) } => {

                    let mut decoder = Decoder::new(&bytes, start_pos);
                    let prev_commandline_args_hash = u64::decode(&mut decoder)
                        .expect("Error reading commandline arg hash from cached dep-graph");

                    if prev_commandline_args_hash != expected_hash {
                        if report_incremental_info {
                            println!("[incremental] completely ignoring cache because of \
                                    differing commandline arguments");
                        }
                        // We can't reuse the cache, purge it.
                        debug!("load_dep_graph_new: differing commandline arg hashes");

                        // No need to do any further work
                        return LoadResult::DataOutOfDate;
                    }

                    let dep_graph = SerializedDepGraph::decode(&mut decoder)
                        .expect("Error reading cached dep-graph");

                    LoadResult::Ok { data: (PreviousDepGraph::new(dep_graph), prev_work_products) }
                }
            }
        })
    }))
}

pub fn load_query_result_cache<'sess>(sess: &'sess Session) -> OnDiskCache<'sess> {
    if sess.opts.incremental.is_none() ||
       !sess.opts.debugging_opts.incremental_queries {
        return OnDiskCache::new_empty(sess.codemap());
    }

    match load_data(sess.opts.debugging_opts.incremental_info, &query_cache_path(sess)) {
        LoadResult::Ok{ data: (bytes, start_pos) } => OnDiskCache::new(sess, bytes, start_pos),
        _ => OnDiskCache::new_empty(sess.codemap())
    }
}
<|endoftext|>