<commit_before>use crate::api::{github, ServerResult};
use crate::load::{Config, InputData, TryCommit};
use futures::compat::Future01CompatExt;
use serde::Deserialize;

use regex::Regex;
use reqwest::header::USER_AGENT;

lazy_static::lazy_static! {
    static ref BODY_TRY_COMMIT: Regex =
        Regex::new(r#"(?:\W|^)@rust-timer\s+build\s+(\w+)(?:\W|$)"#).unwrap();
    static ref BODY_QUEUE: Regex =
        Regex::new(r#"(?:\W|^)@rust-timer\s+queue(?:\W|$)"#).unwrap();
}

async fn get_authorized_users() -> ServerResult<Vec<usize>> {
    let url = format!("{}/permissions/perf.json", ::rust_team_data::v1::BASE_URL);
    let client = reqwest::r#async::Client::new();
    client
        .get(&url)
        .send()
        .compat()
        .await
        .map_err(|err| format!("failed to fetch authorized users: {}", err))?
        .error_for_status()
        .map_err(|err| format!("failed to fetch authorized users: {}", err))?
        .json::<rust_team_data::v1::Permission>()
        .compat()
        .await
        .map_err(|err| format!("failed to fetch authorized users: {}", err))
        .map(|perms| perms.github_ids)
}

pub async fn handle_github(
    request: github::Request,
    data: &InputData,
) -> ServerResult<github::Response> {
    if request.comment.body.contains(" homu: ") {
        if let Some(sha) = handle_homu_res(&request, data).await {
            return enqueue_sha(request, data, &sha).await;
        }
    }

    if !request.comment.body.contains("@rust-timer ") {
        return Ok(github::Response);
    }

    if request.comment.author_association != github::Association::Owner
        && !get_authorized_users()
            .await?
            .contains(&request.comment.user.id)
    {
        post_comment(
            &data.config,
            &request.issue,
            "Insufficient permissions to issue commands to rust-timer.",
        )
        .await;
        return Ok(github::Response);
    }

    let body = &request.comment.body;

    if BODY_QUEUE.is_match(&body) {
        {
            let mut persistent = data.persistent.lock();
            persistent.pending_try_builds.insert(request.issue.number);
            persistent.write().expect("successful encode");
        }
        post_comment(
            &data.config,
            &request.issue,
            "Awaiting bors try build completion",
        )
        .await;
        return Ok(github::Response);
    }

    if let Some(captures) = BODY_TRY_COMMIT.captures(&body) {
        if let Some(commit) = captures.get(1).map(|c| c.as_str().to_owned()) {
            let commit = commit.trim_start_matches("https://github.com/rust-lang/rust/commit/");
            return enqueue_sha(request, data, &commit).await;
        }
    }

    Ok(github::Response)
}

async fn enqueue_sha(
    request: github::Request,
    data: &InputData,
    commit: &str,
) -> ServerResult<github::Response> {
    let client = reqwest::r#async::Client::new();
    let mut commit_response = client
        .get(&format!(
            "{}/commits/{}",
            request.issue.repository_url, commit
        ))
        .send()
        .compat()
        .await
        .map_err(|_| String::from("cannot get commit"))?;
    let commit_response = commit_response
        .json::<github::Commit>()
        .compat()
        .await
        .map_err(|e| format!("cannot deserialize commit: {:?}", e))?;
    if commit_response.parents.len() != 2 {
        post_comment(
            &data.config,
            &request.issue,
            format!(
                "Bors try commit {} unexpectedly has {} parents.",
                commit_response.sha,
                commit_response.parents.len()
            ),
        )
        .await;
        return Ok(github::Response);
    }
    let try_commit = TryCommit {
        sha: commit_response.sha.clone(),
        parent_sha: commit_response.parents[0].sha.clone(),
        issue: request.issue.clone(),
    };
    {
        let mut persistent = data.persistent.lock();
        if !persistent
            .try_commits
            .iter()
            .any(|c| c.sha() == &commit_response.sha)
        {
            persistent.try_commits.push(try_commit.clone());
        }
        persistent.write().expect("successful encode");
    }
    post_comment(
        &data.config,
        &request.issue,
        format!(
            "Queued {} with parent {}, future [comparison URL]({}).",
            commit_response.sha,
            commit_response.parents[0].sha,
            try_commit.comparison_url(),
        ),
    )
    .await;
    Ok(github::Response)
}

#[derive(Debug, Deserialize)]
#[serde(tag = "type")]
enum HomuComment {
    TryBuildCompleted { merge_sha: String },
}

async fn handle_homu_res(request: &github::Request, data: &InputData) -> Option<String> {
    if !request.comment.body.contains("Try build successful") {
        return None;
    }

    {
        let mut persistent = data.persistent.lock();
        if persistent.pending_try_builds.remove(&request.issue.number) {
            persistent.write().expect("successful encode");
        } else {
            log::debug!(
                "Skipping successful try build for pr {}, not in pending",
                request.issue.number
            );
            return None;
        }
    }

    let start = "<!-- homu: ";
    let start_idx = request.comment.body.find(start).expect("found homu") + start.len();
    let end_idx = start_idx + request.comment.body[start_idx..].find(" -->").unwrap();

    let sha = match serde_json::from_str(&request.comment.body[start_idx..end_idx]) {
        Ok(HomuComment::TryBuildCompleted { merge_sha }) => merge_sha,
        Err(err) => {
            log::warn!(
                "failed to parse try build result; comment: {:?}, part: {:?}, err: {:?}",
                request.comment.body,
                &request.comment.body[start_idx..end_idx],
                err
            );
            return None;
        }
    };

    Some(sha)
}

pub async fn post_comment<B>(cfg: &Config, issue: &github::Issue, body: B)
where
    B: Into<String>,
{
    let body = body.into();
    let timer_token = cfg.keys.github.clone().expect("needs rust-timer token");
    let client = reqwest::r#async::Client::new();
    let req = client
        .post(&issue.comments_url)
        .json(&github::PostComment {
            body: body.to_owned(),
        })
        .header(USER_AGENT, "perf-rust-lang-org-server")
        .basic_auth("rust-timer", Some(timer_token));

    if let Err(e) = req.send().compat().await {
        eprintln!("failed to post comment: {:?}", e);
    }
}
<commit_msg>Update code to build with recent nightlies<commit_after>use crate::api::{github, ServerResult};
use crate::load::{Config, InputData, TryCommit};
use futures::compat::Future01CompatExt;
use serde::Deserialize;

use regex::Regex;
use reqwest::header::USER_AGENT;

lazy_static::lazy_static! {
    static ref BODY_TRY_COMMIT: Regex =
        Regex::new(r#"(?:\W|^)@rust-timer\s+build\s+(\w+)(?:\W|$)"#).unwrap();
    static ref BODY_QUEUE: Regex =
        Regex::new(r#"(?:\W|^)@rust-timer\s+queue(?:\W|$)"#).unwrap();
}

async fn get_authorized_users() -> ServerResult<Vec<usize>> {
    let url = format!("{}/permissions/perf.json", ::rust_team_data::v1::BASE_URL);
    let client = reqwest::r#async::Client::new();
    client
        .get(&url)
        .send()
        .compat()
        .await
        .map_err(|err| format!("failed to fetch authorized users: {}", err))?
        .error_for_status()
        .map_err(|err| format!("failed to fetch authorized users: {}", err))?
        .json::<rust_team_data::v1::Permission>()
        .compat()
        .await
        .map_err(|err| format!("failed to fetch authorized users: {}", err))
        .map(|perms| perms.github_ids)
}

pub async fn handle_github(
    request: github::Request,
    data: &InputData,
) -> ServerResult<github::Response> {
    if request.comment.body.contains(" homu: ") {
        if let Some(sha) = handle_homu_res(&request, data).await {
            return enqueue_sha(request, data, sha).await;
        }
    }

    if !request.comment.body.contains("@rust-timer ") {
        return Ok(github::Response);
    }

    if request.comment.author_association != github::Association::Owner
        && !get_authorized_users()
            .await?
            .contains(&request.comment.user.id)
    {
        post_comment(
            &data.config,
            &request.issue,
            "Insufficient permissions to issue commands to rust-timer.",
        )
        .await;
        return Ok(github::Response);
    }

    if BODY_QUEUE.is_match(&request.comment.body) {
        {
            let mut persistent = data.persistent.lock();
            persistent.pending_try_builds.insert(request.issue.number);
            persistent.write().expect("successful encode");
        }
        post_comment(
            &data.config,
            &request.issue,
            "Awaiting bors try build completion",
        )
        .await;
        return Ok(github::Response);
    }

    if let Some(captures) = BODY_TRY_COMMIT.captures(&request.comment.body) {
        if let Some(commit) = captures.get(1).map(|c| c.as_str().to_owned()) {
            let commit = commit.trim_start_matches("https://github.com/rust-lang/rust/commit/");
            let f = enqueue_sha(request, data, commit.to_owned());
            return f.await;
        }
    }

    Ok(github::Response)
}

async fn enqueue_sha(
    request: github::Request,
    data: &InputData,
    commit: String,
) -> ServerResult<github::Response> {
    let client = reqwest::r#async::Client::new();
    let url = format!("{}/commits/{}", request.issue.repository_url, commit);
    let mut commit_response = client
        .get(&url)
        .send()
        .compat()
        .await
        .map_err(|_| String::from("cannot get commit"))?;
    let commit_response = commit_response.json::<github::Commit>().compat().await;
    let commit_response = match commit_response {
        Err(e) => return Err(format!("cannot deserialize commit: {:?}", e)),
        Ok(c) => c,
    };
    if commit_response.parents.len() != 2 {
        let msg = format!(
            "Bors try commit {} unexpectedly has {} parents.",
            commit_response.sha,
            commit_response.parents.len()
        );
        post_comment(&data.config, &request.issue, msg).await;
        return Ok(github::Response);
    }
    let try_commit = TryCommit {
        sha: commit_response.sha.clone(),
        parent_sha: commit_response.parents[0].sha.clone(),
        issue: request.issue.clone(),
    };
    {
        let mut persistent = data.persistent.lock();
        if !persistent
            .try_commits
            .iter()
            .any(|c| c.sha() == &commit_response.sha)
        {
            persistent.try_commits.push(try_commit.clone());
        }
        persistent.write().expect("successful encode");
    }
    let msg = format!(
        "Queued {} with parent {}, future [comparison URL]({}).",
        commit_response.sha,
        commit_response.parents[0].sha,
        try_commit.comparison_url(),
    );
    post_comment(&data.config, &request.issue, msg).await;
    Ok(github::Response)
}

#[derive(Debug, Deserialize)]
#[serde(tag = "type")]
enum HomuComment {
    TryBuildCompleted { merge_sha: String },
}

async fn handle_homu_res(request: &github::Request, data: &InputData) -> Option<String> {
    if !request.comment.body.contains("Try build successful") {
        return None;
    }

    {
        let mut persistent = data.persistent.lock();
        if persistent.pending_try_builds.remove(&request.issue.number) {
            persistent.write().expect("successful encode");
        } else {
            log::debug!(
                "Skipping successful try build for pr {}, not in pending",
                request.issue.number
            );
            return None;
        }
    }

    let start = "<!-- homu: ";
    let start_idx = request.comment.body.find(start).expect("found homu") + start.len();
    let end_idx = start_idx + request.comment.body[start_idx..].find(" -->").unwrap();

    let sha = match serde_json::from_str(&request.comment.body[start_idx..end_idx]) {
        Ok(HomuComment::TryBuildCompleted { merge_sha }) => merge_sha,
        Err(err) => {
            log::warn!(
                "failed to parse try build result; comment: {:?}, part: {:?}, err: {:?}",
                request.comment.body,
                &request.comment.body[start_idx..end_idx],
                err
            );
            return None;
        }
    };

    Some(sha)
}

pub async fn post_comment<B>(cfg: &Config, issue: &github::Issue, body: B)
where
    B: Into<String>,
{
    let body = body.into();
    let timer_token = cfg.keys.github.clone().expect("needs rust-timer token");
    let client = reqwest::r#async::Client::new();
    let req = client
        .post(&issue.comments_url)
        .json(&github::PostComment {
            body: body.to_owned(),
        })
        .header(USER_AGENT, "perf-rust-lang-org-server")
        .basic_auth("rust-timer", Some(timer_token));

    if let Err(e) = req.send().compat().await {
        eprintln!("failed to post comment: {:?}", e);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use interner::*;
use ast::*;

pub enum Instruction {
    PushInt(int),
    PushFloat(f64),
    Push(uint),
    PushGlobal(uint),
    Store(uint),
    CallGlobal(uint),
    Jump(uint),
    CJump(uint),

    AddInt,
    SubtractInt,
    MultiplyInt
}

type CExpr = Expr<InternedStr>;

pub enum Variable {
    Stack(uint),
    Global(uint)
}

pub struct CompiledFunction {
    pub id: InternedStr,
    pub instructions: Vec<Instruction>
}

pub trait CompilerEnv {
    fn find_var(&self, id: &InternedStr) -> Option<Variable>;
}

impl CompilerEnv for () {
    fn find_var(&self, id: &InternedStr) -> Option<Variable> {
        None
    }
}

impl CompilerEnv for HashMap<InternedStr, Variable> {
    fn find_var(&self, s: &InternedStr) -> Option<Variable> {
        self.find(s).map(|x| *x)
    }
}

impl <T: CompilerEnv, U: CompilerEnv> CompilerEnv for (T, U) {
    fn find_var(&self, s: &InternedStr) -> Option<Variable> {
        let &(ref outer, ref inner) = self;
        inner.find_var(s)
            .or_else(|| outer.find_var(s))
    }
}

impl CompilerEnv for Module<InternedStr> {
    fn find_var(&self, id: &InternedStr) -> Option<Variable> {
        self.functions.iter()
            .enumerate()
            .find(|&(_, f)| f.name == *id)
            .map(|(i, _)| Global(i))
    }
}

impl <'a, T: CompilerEnv> CompilerEnv for &'a T {
    fn find_var(&self, s: &InternedStr) -> Option<Variable> {
        self.find_var(s)
    }
}

pub struct Compiler<'a> {
    globals: &'a CompilerEnv,
    stack: HashMap<InternedStr, Variable>,
}

impl <'a> Compiler<'a> {

    pub fn new(globals: &'a CompilerEnv) -> Compiler<'a> {
        Compiler { globals: globals, stack: HashMap::new() }
    }

    fn find(&self, s: &InternedStr) -> Option<Variable> {
        self.stack.find_var(s)
            .or_else(||  self.globals.find_var(s))
    }

    fn new_stack_var(&mut self, s: InternedStr) {
        let v = Stack(self.stack.len());
        if self.stack.find(&s).is_some() {
            fail!("Variable shadowing is not allowed")
        }
        self.stack.insert(s, v);
    }

    fn stack_size(&self) -> uint {
        self.stack.len()
    }

    pub fn compile_module(&mut self, module: &Module<InternedStr>) -> Vec<CompiledFunction> {
        module.functions.iter()
            .map(|f| self.compile_function(f))
            .collect()
    }

    pub fn compile_function(&mut self, function: &Function<InternedStr>) -> CompiledFunction {
        for arg in function.arguments.iter() {
            self.new_stack_var(arg.name);
        }
        let mut instructions = Vec::new();
        self.compile(&function.expression, &mut instructions);
        for arg in function.arguments.iter() {
            self.stack.remove(&arg.name);
        }
        CompiledFunction { id: function.name, instructions: instructions }
    }

    fn compile(&mut self, expr: &CExpr, instructions: &mut Vec<Instruction>) {
        match *expr {
            Literal(ref lit) => {
                match *lit {
                    Integer(i) => instructions.push(PushInt(i)),
                    Float(f) => instructions.push(PushFloat(f)),
                    Bool(b) => instructions.push(PushInt(if b { 1 } else { 0 })),
                    String(s) => fail!("String is not implemented")
                }
            }
            Identifier(ref id) => {
                match self.find(id).unwrap_or_else(|| fail!("Undefined variable {}", id)) {
                    Stack(index) => instructions.push(Push(index)),
                    Global(index) => instructions.push(PushGlobal(index))
                }
            }
            IfElse(ref pred, ref if_true, ref if_false) => {
                self.compile(&**pred, instructions);
                let jump_index = instructions.len();
                instructions.push(CJump(0));
                self.compile(&**if_false, instructions);
                let false_jump_index = instructions.len();
                instructions.push(Jump(0));
                *instructions.get_mut(jump_index) = CJump(instructions.len());
                self.compile(&**if_true, instructions);
                *instructions.get_mut(false_jump_index) = Jump(instructions.len());
            }
            Block(ref exprs) => {
                for expr in exprs.iter() {
                    self.compile(expr, instructions);
                }
                for expr in exprs.iter() {
                    match expr {
                        &Let(ref id, _) => {
                            self.stack.remove(id);
                        }
                        _ => ()
                    }
                }
            }
            BinOp(ref lhs, ref op, ref rhs) => {
                self.compile(&**lhs, instructions);
                self.compile(&**rhs, instructions);
                match op.as_slice() {
                    "+" => instructions.push(AddInt),
                    "-" => instructions.push(SubtractInt),
                    "*" => instructions.push(MultiplyInt),
                    _ => fail!()
                }
            }
            Let(ref id, ref expr) => {
                self.new_stack_var(*id);
                self.compile(&**expr, instructions);
            }
            Call(ref func, ref args) => {
                self.compile(&**func, instructions);
                for arg in args.iter() {
                    self.compile(arg, instructions);
                }
                instructions.push(CallGlobal(args.len()));
            }
            While(ref pred, ref expr) => {
                //jump #test
                //#start:
                //[compile(expr)]
                //#test:
                //[compile(pred)]
                //cjump #start
                let mut pre_jump_index = instructions.len();
                instructions.push(Jump(0));
                self.compile(&**expr, instructions);
                *instructions.get_mut(pre_jump_index) = Jump(instructions.len());
                self.compile(&**pred, instructions);
                instructions.push(CJump(pre_jump_index + 1));
            }
            _ => fail!()
        }
    }
}
<commit_msg>Added assignment compilation<commit_after>use std::collections::HashMap;
use interner::*;
use ast::*;

pub enum Instruction {
    PushInt(int),
    PushFloat(f64),
    Push(uint),
    PushGlobal(uint),
    Store(uint),
    CallGlobal(uint),
    Jump(uint),
    CJump(uint),

    AddInt,
    SubtractInt,
    MultiplyInt
}

type CExpr = Expr<InternedStr>;

pub enum Variable {
    Stack(uint),
    Global(uint)
}

pub struct CompiledFunction {
    pub id: InternedStr,
    pub instructions: Vec<Instruction>
}

pub trait CompilerEnv {
    fn find_var(&self, id: &InternedStr) -> Option<Variable>;
}

impl CompilerEnv for () {
    fn find_var(&self, id: &InternedStr) -> Option<Variable> {
        None
    }
}

impl CompilerEnv for HashMap<InternedStr, Variable> {
    fn find_var(&self, s: &InternedStr) -> Option<Variable> {
        self.find(s).map(|x| *x)
    }
}

impl <T: CompilerEnv, U: CompilerEnv> CompilerEnv for (T, U) {
    fn find_var(&self, s: &InternedStr) -> Option<Variable> {
        let &(ref outer, ref inner) = self;
        inner.find_var(s)
            .or_else(|| outer.find_var(s))
    }
}

impl CompilerEnv for Module<InternedStr> {
    fn find_var(&self, id: &InternedStr) -> Option<Variable> {
        self.functions.iter()
            .enumerate()
            .find(|&(_, f)| f.name == *id)
            .map(|(i, _)| Global(i))
    }
}

impl <'a, T: CompilerEnv> CompilerEnv for &'a T {
    fn find_var(&self, s: &InternedStr) -> Option<Variable> {
        self.find_var(s)
    }
}

pub struct Compiler<'a> {
    globals: &'a CompilerEnv,
    stack: HashMap<InternedStr, Variable>,
}

impl <'a> Compiler<'a> {

    pub fn new(globals: &'a CompilerEnv) -> Compiler<'a> {
        Compiler { globals: globals, stack: HashMap::new() }
    }

    fn find(&self, s: &InternedStr) -> Option<Variable> {
        self.stack.find_var(s)
            .or_else(||  self.globals.find_var(s))
    }

    fn new_stack_var(&mut self, s: InternedStr) {
        let v = Stack(self.stack.len());
        if self.stack.find(&s).is_some() {
            fail!("Variable shadowing is not allowed")
        }
        self.stack.insert(s, v);
    }

    fn stack_size(&self) -> uint {
        self.stack.len()
    }

    pub fn compile_module(&mut self, module: &Module<InternedStr>) -> Vec<CompiledFunction> {
        module.functions.iter()
            .map(|f| self.compile_function(f))
            .collect()
    }

    pub fn compile_function(&mut self, function: &Function<InternedStr>) -> CompiledFunction {
        for arg in function.arguments.iter() {
            self.new_stack_var(arg.name);
        }
        let mut instructions = Vec::new();
        self.compile(&function.expression, &mut instructions);
        for arg in function.arguments.iter() {
            self.stack.remove(&arg.name);
        }
        CompiledFunction { id: function.name, instructions: instructions }
    }

    fn compile(&mut self, expr: &CExpr, instructions: &mut Vec<Instruction>) {
        match *expr {
            Literal(ref lit) => {
                match *lit {
                    Integer(i) => instructions.push(PushInt(i)),
                    Float(f) => instructions.push(PushFloat(f)),
                    Bool(b) => instructions.push(PushInt(if b { 1 } else { 0 })),
                    String(s) => fail!("String is not implemented")
                }
            }
            Identifier(ref id) => {
                match self.find(id).unwrap_or_else(|| fail!("Undefined variable {}", id)) {
                    Stack(index) => instructions.push(Push(index)),
                    Global(index) => instructions.push(PushGlobal(index))
                }
            }
            IfElse(ref pred, ref if_true, ref if_false) => {
                self.compile(&**pred, instructions);
                let jump_index = instructions.len();
                instructions.push(CJump(0));
                self.compile(&**if_false, instructions);
                let false_jump_index = instructions.len();
                instructions.push(Jump(0));
                *instructions.get_mut(jump_index) = CJump(instructions.len());
                self.compile(&**if_true, instructions);
                *instructions.get_mut(false_jump_index) = Jump(instructions.len());
            }
            Block(ref exprs) => {
                for expr in exprs.iter() {
                    self.compile(expr, instructions);
                }
                for expr in exprs.iter() {
                    match expr {
                        &Let(ref id, _) => {
                            self.stack.remove(id);
                        }
                        _ => ()
                    }
                }
            }
            BinOp(ref lhs, ref op, ref rhs) => {
                self.compile(&**lhs, instructions);
                self.compile(&**rhs, instructions);
                match op.as_slice() {
                    "+" => instructions.push(AddInt),
                    "-" => instructions.push(SubtractInt),
                    "*" => instructions.push(MultiplyInt),
                    _ => fail!()
                }
            }
            Let(ref id, ref expr) => {
                self.new_stack_var(*id);
                self.compile(&**expr, instructions);
            }
            Call(ref func, ref args) => {
                self.compile(&**func, instructions);
                for arg in args.iter() {
                    self.compile(arg, instructions);
                }
                instructions.push(CallGlobal(args.len()));
            }
            While(ref pred, ref expr) => {
                //jump #test
                //#start:
                //[compile(expr)]
                //#test:
                //[compile(pred)]
                //cjump #start
                let mut pre_jump_index = instructions.len();
                instructions.push(Jump(0));
                self.compile(&**expr, instructions);
                *instructions.get_mut(pre_jump_index) = Jump(instructions.len());
                self.compile(&**pred, instructions);
                instructions.push(CJump(pre_jump_index + 1));
            }
            Assign(ref lhs, ref rhs) => {
                self.compile(&**rhs, instructions);
                match **lhs {
                    Identifier(ref id) => {
                        let var = self.find(id)
                            .unwrap_or_else(|| fail!("Undefined variable {}", id));
                        match var {
                            Stack(i) => instructions.push(Store(i)),
                            Global(_) => fail!("Assignment to global {}", id)
                        }
                    }
                    _ => fail!("Assignment to {}", lhs)
                }
            }
            ref e => fail!("Cannot compile {}", e)
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeSet;
use std::fmt::{Display, Error, Formatter};
use action::{POSSIBLE_DIRECTIONS,POSSIBLE_MOVE_TYPES,Coordinate,Move};

pub const NUM_COLS: usize = 5;
pub const NUM_ROWS: usize = 4;

// Hacks for the three states of the lower-left of the board in JunSeok vs YeonSeung game
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum BoardType {
    Left,
    LeftOrMiddle,
    Middle,
    RightOrMiddle,
    Right,
}

impl BoardType {
    fn is_final(&self) -> bool {
        match *self {
            BoardType::Left => true,
            BoardType::Middle => true,
            BoardType::Right => true,
            BoardType::LeftOrMiddle => false,
            BoardType::RightOrMiddle => false,
        }
    }

    // Can a board of type `current` become this type?
    fn applies_to(&self, current: Option<BoardType>) -> bool {
        match (current, *self) {
            // a none board type can change to anything.
            (None, _) => true,
            // LeftOrMiddle can change to itself, left, or middle.
            (Some(BoardType::LeftOrMiddle), BoardType::LeftOrMiddle) => true,
            (Some(BoardType::LeftOrMiddle), BoardType::Left) => true,
            (Some(BoardType::LeftOrMiddle), BoardType::Middle) => true,
            (Some(BoardType::LeftOrMiddle), _) => false,
            // RightOrMiddle can change to itself, right, or middle.
            (Some(BoardType::RightOrMiddle), BoardType::RightOrMiddle) => true,
            (Some(BoardType::RightOrMiddle), BoardType::Right) => true,
            (Some(BoardType::RightOrMiddle), BoardType::Middle) => true,
            (Some(BoardType::RightOrMiddle), _) => false,
            // Left, Middle, Right can change to themselves only.
            (Some(BoardType::Left), BoardType::Left) => true,
            (Some(BoardType::Left), _) => false,
            (Some(BoardType::Middle), BoardType::Middle) => true,
            (Some(BoardType::Middle), _) => false,
            (Some(BoardType::Right), BoardType::Right) => true,
            (Some(BoardType::Right), _) => false,
        }
    }

    fn induced_by(&self, c: Coordinate) -> bool {
        // Not in the lower left, so it's a free pass.
        if !c.induces_board_type() {
            return true;
        }

        match *self {
            BoardType::Left          => c != Coordinate{row: 2, col: 1} && c != Coordinate{row: 1, col: 1},
            BoardType::LeftOrMiddle  => c == Coordinate{row: 1, col: 0},
            BoardType::Middle        => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 1, col: 1},
            BoardType::RightOrMiddle => c == Coordinate{row: 3, col: 1},
            BoardType::Right         => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 2, col: 0},
        }
    }
}

#[derive(Copy, Clone)]
enum Orientation {
    UpDown,
    LeftRight,
    UpLeft,
    UpRight,
    DownLeft,
    DownRight,
}

impl Orientation {
    fn to_str(&self) -> &'static str {
        match *self {
            Orientation::UpDown => "║",
            Orientation::LeftRight => "═",
            Orientation::UpLeft => "╝",
            Orientation::UpRight => "╚",
            Orientation::DownLeft => "╗",
            Orientation::DownRight => "╔",
        }
    }
}

const POSSIBLE_BOARD_TYPES: [BoardType; 5] = [
    BoardType::Left,
    BoardType::LeftOrMiddle,
    BoardType::Middle,
    BoardType::RightOrMiddle,
    BoardType::Right,
];

pub type BoardArray = [[bool; NUM_COLS]; NUM_ROWS];
pub struct Board {
    board: BoardArray,
    board_type: Option<BoardType>,
}

impl Board {
    pub fn new(array: BoardArray, board_type: Option<BoardType>) -> Board {
        Board{board: array, board_type: board_type}
    }

    pub fn make_move(&mut self, m: Move) {
        if let Some(bt) = m.new_board_type {
            if !bt.applies_to(self.board_type) {
                panic!("Board type is {:?}, not compatible with {:?}", self.board_type, bt);
            }
            self.board_type = m.new_board_type
        }
        self.set_squares(m, true)
    }

    pub fn undo_move(&mut self, m: Move) {
        self.board_type = m.old_board_type;
        self.set_squares(m, false)
    }

    fn set_squares(&mut self, m: Move, mode: bool) {
        self.board[m.coord.row][m.coord.col] = mode;
        for other_space in m.extensions().iter() {
            self.board[other_space.row][other_space.col] = mode;
        }
    }

    fn occupied(&self, c: Coordinate) -> bool {
        self.board[c.row][c.col]
    }

    // This assesses whether a coordinate can be placed on the board,
    // given the current type of the board.
    fn compatible(&self, c: Coordinate) -> bool {
        // Not in the lower left, so it's a free pass.
        if !c.induces_board_type() {
            return true;
        }

        match self.board_type {
            Some(BoardType::Left)          => c != Coordinate{row: 2, col: 1} && c != Coordinate{row: 1, col: 1},
            Some(BoardType::LeftOrMiddle)  => c != Coordinate{row: 1, col: 1},
            Some(BoardType::Middle)        => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 1, col: 1},
            Some(BoardType::RightOrMiddle) => c != Coordinate{row: 3, col: 0},
            Some(BoardType::Right)         => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 2, col: 0},
            None => true,
        }
    }

    fn frontier(&self) -> Vec<Coordinate> {
        let mut results = Vec::new();
        for row in 0..NUM_ROWS {
            for col in 0..NUM_COLS {
                let coord = Coordinate{row: row, col: col};
                if self.occupied(coord) || !self.compatible(coord) {
                    continue;
                }
                let have_neighbor = POSSIBLE_DIRECTIONS.iter().any(|dir| {
                    if let Some(dest) = coord.move_in(*dir, 1) { self.occupied(dest) } else { false }
                });
                if have_neighbor {
                    results.push(coord);
                }
            }
        }
        results
    }

    fn board_type_final(&self) -> bool {
        if let Some(x) = self.board_type { x.is_final() } else { false }
    }

    pub fn legal_moves(&self) -> Vec<Move> {
        let mut results = Vec::new();
        for frontier_space in self.frontier().iter() {
            for move_type in POSSIBLE_MOVE_TYPES.iter() {
                let mov = match Move::new(*frontier_space, *move_type, self.board_type) {
                    Some(x) => x,
                    None => continue,
                };
                let mut other_space_taken = false;
                let mut induces_board_type = frontier_space.induces_board_type();
                for other_space in mov.extensions().iter() {
                    if other_space.induces_board_type() {
                        induces_board_type = true;
                    }
                    if self.occupied(*other_space) || !self.compatible(*other_space) {
                        other_space_taken = true;
                        break;
                    }
                }
                if other_space_taken {
                    continue;
                }

                if !induces_board_type || self.board_type_final() {
                    results.push(mov);
                    continue;
                }

                let mut ok_board_types: BTreeSet<_> = POSSIBLE_BOARD_TYPES.iter().cloned().filter(|board_type| {
                    board_type.applies_to(self.board_type) &&
                        board_type.induced_by(*frontier_space) &&
                        mov.extensions().iter().all(|coord| board_type.induced_by(*coord))
                }).collect();

                // Dominated board types...
                if ok_board_types.contains(&BoardType::LeftOrMiddle) {
                    ok_board_types.remove(&BoardType::Left);
                    ok_board_types.remove(&BoardType::Middle);
                }
                if ok_board_types.contains(&BoardType::RightOrMiddle) {
                    ok_board_types.remove(&BoardType::Right);
                    ok_board_types.remove(&BoardType::Middle);
                }

                for board_type in ok_board_types.iter() {
                    results.push(mov.with_board_type(*board_type));
                }
            }
        }
        results
    }
}

impl Display for Board {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
        // Print header row
        try!(formatter.write_str("    "));
        for i in 0..NUM_COLS {
            try!(write!(formatter, " {}", i));
        }
        try!(formatter.write_str("\n"));

        // Print top box border
        try!(formatter.write_str("    ┌─"));
        for _ in 0..NUM_COLS - 1 {
            try!(formatter.write_str("┬─"));
        }
        try!(formatter.write_str("┐\n"));

        for (i, row) in self.board.iter().enumerate() {
            // Print cell content
            try!(write!(formatter, "{: >2}  │", i));
            for col in row.iter() {
                let chr = if *col { "x" } else { " " };
                try!(write!(formatter, "{}│", chr));
            }
            try!(formatter.write_str("\n"));

            // Print box border between rows
            if i != NUM_ROWS - 1 {
                try!(formatter.write_str("    ├─"));
                for _ in 0..NUM_COLS - 1 {
                    try!(formatter.write_str("┼─"));
                }
                try!(formatter.write_str("┤\n"));
            }
        }

        // Print bottom box border
        try!(formatter.write_str("    └─"));
        for _ in 0..NUM_COLS - 1 {
            try!(formatter.write_str("┴─"));
        }
        try!(formatter.write_str("┘\n"));

        write!(formatter, "{:?}", self.board_type)
    }
}
<commit_msg>Add fixed Orientations for the Yeonseung Junseok game<commit_after>use std::collections::BTreeSet;
use std::fmt::{Display, Error, Formatter};
use action::{POSSIBLE_DIRECTIONS,POSSIBLE_MOVE_TYPES,Coordinate,Move};

pub const NUM_COLS: usize = 5;
pub const NUM_ROWS: usize = 4;

// Hacks for the three states of the lower-left of the board in JunSeok vs YeonSeung game
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum BoardType {
    Left,
    LeftOrMiddle,
    Middle,
    RightOrMiddle,
    Right,
}

impl BoardType {
    fn is_final(&self) -> bool {
        match *self {
            BoardType::Left => true,
            BoardType::Middle => true,
            BoardType::Right => true,
            BoardType::LeftOrMiddle => false,
            BoardType::RightOrMiddle => false,
        }
    }

    // Can a board of type `current` become this type?
    fn applies_to(&self, current: Option<BoardType>) -> bool {
        match (current, *self) {
            // a none board type can change to anything.
            (None, _) => true,
            // LeftOrMiddle can change to itself, left, or middle.
            (Some(BoardType::LeftOrMiddle), BoardType::LeftOrMiddle) => true,
            (Some(BoardType::LeftOrMiddle), BoardType::Left) => true,
            (Some(BoardType::LeftOrMiddle), BoardType::Middle) => true,
            (Some(BoardType::LeftOrMiddle), _) => false,
            // RightOrMiddle can change to itself, right, or middle.
            (Some(BoardType::RightOrMiddle), BoardType::RightOrMiddle) => true,
            (Some(BoardType::RightOrMiddle), BoardType::Right) => true,
            (Some(BoardType::RightOrMiddle), BoardType::Middle) => true,
            (Some(BoardType::RightOrMiddle), _) => false,
            // Left, Middle, Right can change to themselves only.
            (Some(BoardType::Left), BoardType::Left) => true,
            (Some(BoardType::Left), _) => false,
            (Some(BoardType::Middle), BoardType::Middle) => true,
            (Some(BoardType::Middle), _) => false,
            (Some(BoardType::Right), BoardType::Right) => true,
            (Some(BoardType::Right), _) => false,
        }
    }

    fn induced_by(&self, c: Coordinate) -> bool {
        // Not in the lower left, so it's a free pass.
        if !c.induces_board_type() {
            return true;
        }

        match *self {
            BoardType::Left          => c != Coordinate{row: 2, col: 1} && c != Coordinate{row: 1, col: 1},
            BoardType::LeftOrMiddle  => c == Coordinate{row: 1, col: 0},
            BoardType::Middle        => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 1, col: 1},
            BoardType::RightOrMiddle => c == Coordinate{row: 3, col: 1},
            BoardType::Right         => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 2, col: 0},
        }
    }
}

#[derive(Copy, Clone)]
enum Orientation {
    UpDown,
    LeftRight,
    UpLeft,
    UpRight,
    DownLeft,
    DownRight,
}

impl Orientation {
    fn to_str(&self) -> &'static str {
        match *self {
            Orientation::UpDown => "║",
            Orientation::LeftRight => "═",
            Orientation::UpLeft => "╝",
            Orientation::UpRight => "╚",
            Orientation::DownLeft => "╗",
            Orientation::DownRight => "╔",
        }
    }
}

#[derive(Copy, Clone)]
enum OrientationOption {
    Fixed(Orientation),
    IfRight(Orientation, Orientation),
    IfLeft(Orientation, Orientation),
    LeftOrMiddle(Orientation, Orientation),
    RightOrMiddle(Orientation, Orientation),
}

impl OrientationOption {
    fn for_board(&self, board_type: Option<BoardType>) -> &'static str {
        let orientation = match (*self, board_type) {
            (OrientationOption::Fixed(orientation), _) => orientation,
            (OrientationOption::IfRight(ifright, _), Some(BoardType::Right)) => ifright,
            (OrientationOption::IfRight(_, notright), _) => notright,
            (OrientationOption::IfLeft(ifleft, _), Some(BoardType::Left)) => ifleft,
            (OrientationOption::IfLeft(_, notleft), _) => notleft,
            (OrientationOption::LeftOrMiddle(ifleft, _), Some(BoardType::Left)) => ifleft,
            (OrientationOption::LeftOrMiddle(_, ifmiddle), Some(BoardType::Middle)) => ifmiddle,
            (OrientationOption::LeftOrMiddle(_, _), _) => unreachable!(),
            (OrientationOption::RightOrMiddle(ifright, _), Some(BoardType::Right)) => ifright,
            (OrientationOption::RightOrMiddle(_, ifmiddle), Some(BoardType::Middle)) => ifmiddle,
            (OrientationOption::RightOrMiddle(_, _), _) => unreachable!(),
        };
        orientation.to_str()
    }
}

const ORIENTATIONS: [[OrientationOption; NUM_COLS]; NUM_ROWS] = [
    [
        OrientationOption::Fixed(Orientation::DownRight),
        OrientationOption::Fixed(Orientation::LeftRight),
        OrientationOption::Fixed(Orientation::LeftRight),
        OrientationOption::Fixed(Orientation::LeftRight),
        OrientationOption::Fixed(Orientation::DownLeft)
    ],
    [
        OrientationOption::IfRight(Orientation::UpRight, Orientation::UpDown),
        OrientationOption::Fixed(Orientation::DownLeft),
        OrientationOption::Fixed(Orientation::DownRight),
        OrientationOption::Fixed(Orientation::LeftRight),
        OrientationOption::Fixed(Orientation::UpLeft)
    ],
    [
        OrientationOption::LeftOrMiddle(Orientation::UpDown, Orientation::UpRight),
        OrientationOption::RightOrMiddle(Orientation::UpDown, Orientation::DownLeft),
        OrientationOption::Fixed(Orientation::UpRight),
        OrientationOption::Fixed(Orientation::LeftRight),
        OrientationOption::Fixed(Orientation::DownLeft)
    ],
    [
        OrientationOption::Fixed(Orientation::UpRight),
        OrientationOption::IfLeft(Orientation::LeftRight, Orientation::UpRight),
        OrientationOption::Fixed(Orientation::LeftRight),
        OrientationOption::Fixed(Orientation::LeftRight),
        OrientationOption::Fixed(Orientation::UpLeft)
    ],
];

const POSSIBLE_BOARD_TYPES: [BoardType; 5] = [
    BoardType::Left,
    BoardType::LeftOrMiddle,
    BoardType::Middle,
    BoardType::RightOrMiddle,
    BoardType::Right,
];

pub type BoardArray = [[bool; NUM_COLS]; NUM_ROWS];
pub struct Board {
    board: BoardArray,
    board_type: Option<BoardType>,
}

impl Board {
    pub fn new(array: BoardArray, board_type: Option<BoardType>) -> Board {
        Board{board: array, board_type: board_type}
    }

    pub fn make_move(&mut self, m: Move) {
        if let Some(bt) = m.new_board_type {
            if !bt.applies_to(self.board_type) {
                panic!("Board type is {:?}, not compatible with {:?}", self.board_type, bt);
            }
            self.board_type = m.new_board_type
        }
        self.set_squares(m, true)
    }

    pub fn undo_move(&mut self, m: Move) {
        self.board_type = m.old_board_type;
        self.set_squares(m, false)
    }

    fn set_squares(&mut self, m: Move, mode: bool) {
        self.board[m.coord.row][m.coord.col] = mode;
        for other_space in m.extensions().iter() {
            self.board[other_space.row][other_space.col] = mode;
        }
    }

    fn occupied(&self, c: Coordinate) -> bool {
        self.board[c.row][c.col]
    }

    // This assesses whether a coordinate can be placed on the board,
    // given the current type of the board.
    fn compatible(&self, c: Coordinate) -> bool {
        // Not in the lower left, so it's a free pass.
        if !c.induces_board_type() {
            return true;
        }

        match self.board_type {
            Some(BoardType::Left)          => c != Coordinate{row: 2, col: 1} && c != Coordinate{row: 1, col: 1},
            Some(BoardType::LeftOrMiddle)  => c != Coordinate{row: 1, col: 1},
            Some(BoardType::Middle)        => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 1, col: 1},
            Some(BoardType::RightOrMiddle) => c != Coordinate{row: 3, col: 0},
            Some(BoardType::Right)         => c != Coordinate{row: 3, col: 0} && c != Coordinate{row: 2, col: 0},
            None => true,
        }
    }

    fn frontier(&self) -> Vec<Coordinate> {
        let mut results = Vec::new();
        for row in 0..NUM_ROWS {
            for col in 0..NUM_COLS {
                let coord = Coordinate{row: row, col: col};
                if self.occupied(coord) || !self.compatible(coord) {
                    continue;
                }
                let have_neighbor = POSSIBLE_DIRECTIONS.iter().any(|dir| {
                    if let Some(dest) = coord.move_in(*dir, 1) { self.occupied(dest) } else { false }
                });
                if have_neighbor {
                    results.push(coord);
                }
            }
        }
        results
    }

    fn board_type_final(&self) -> bool {
        if let Some(x) = self.board_type { x.is_final() } else { false }
    }

    pub fn legal_moves(&self) -> Vec<Move> {
        let mut results = Vec::new();
        for frontier_space in self.frontier().iter() {
            for move_type in POSSIBLE_MOVE_TYPES.iter() {
                let mov = match Move::new(*frontier_space, *move_type, self.board_type) {
                    Some(x) => x,
                    None => continue,
                };
                let mut other_space_taken = false;
                let mut induces_board_type = frontier_space.induces_board_type();
                for other_space in mov.extensions().iter() {
                    if other_space.induces_board_type() {
                        induces_board_type = true;
                    }
                    if self.occupied(*other_space) || !self.compatible(*other_space) {
                        other_space_taken = true;
                        break;
                    }
                }
                if other_space_taken {
                    continue;
                }

                if !induces_board_type || self.board_type_final() {
                    results.push(mov);
                    continue;
                }

                let mut ok_board_types: BTreeSet<_> = POSSIBLE_BOARD_TYPES.iter().cloned().filter(|board_type| {
                    board_type.applies_to(self.board_type) &&
                        board_type.induced_by(*frontier_space) &&
                        mov.extensions().iter().all(|coord| board_type.induced_by(*coord))
                }).collect();

                // Dominated board types...
                if ok_board_types.contains(&BoardType::LeftOrMiddle) {
                    ok_board_types.remove(&BoardType::Left);
                    ok_board_types.remove(&BoardType::Middle);
                }
                if ok_board_types.contains(&BoardType::RightOrMiddle) {
                    ok_board_types.remove(&BoardType::Right);
                    ok_board_types.remove(&BoardType::Middle);
                }

                for board_type in ok_board_types.iter() {
                    results.push(mov.with_board_type(*board_type));
                }
            }
        }
        results
    }
}

impl Display for Board {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
        // Print header row
        try!(formatter.write_str("    "));
        for i in 0..NUM_COLS {
            try!(write!(formatter, " {}", i));
        }
        try!(formatter.write_str("\n"));

        // Print top box border
        try!(formatter.write_str("    ┌─"));
        for _ in 0..NUM_COLS - 1 {
            try!(formatter.write_str("┬─"));
        }
        try!(formatter.write_str("┐\n"));

        for (i, row) in self.board.iter().enumerate() {
            // Print cell content
            try!(write!(formatter, "{: >2}  │", i));
            for col in row.iter() {
                let chr = if *col { "x" } else { " " };
                try!(write!(formatter, "{}│", chr));
            }
            try!(formatter.write_str("\n"));

            // Print box border between rows
            if i != NUM_ROWS - 1 {
                try!(formatter.write_str("    ├─"));
                for _ in 0..NUM_COLS - 1 {
                    try!(formatter.write_str("┼─"));
                }
                try!(formatter.write_str("┤\n"));
            }
        }

        // Print bottom box border
        try!(formatter.write_str("    └─"));
        for _ in 0..NUM_COLS - 1 {
            try!(formatter.write_str("┴─"));
        }
        try!(formatter.write_str("┘\n"));

        write!(formatter, "{:?}", self.board_type)
    }
}
<|endoftext|>


<commit_before>use cmake;

// Additional parameters for Android build of BoringSSL.
const CMAKE_PARAMS_ANDROID: &[(&str, &[(&str, &str)])] = &[
    ("aarch64", &[
        ("ANDROID_TOOLCHAIN_NAME", "aarch64-linux-android-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
    ]),
    ("arm", &[
        ("ANDROID_TOOLCHAIN_NAME", "arm-linux-androideabi-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
    ]),
    ("x86", &[
        ("ANDROID_TOOLCHAIN_NAME", "x86-linux-android-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
    ]),
    ("x86_64", &[
        ("ANDROID_TOOLCHAIN_NAME", "x86_64-linux-android-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
    ]),
];

const CMAKE_PARAMS_IOS: &[(&str, &[(&str, &str)])] = &[
    ("aarch64", &[
        ("CMAKE_OSX_ARCHITECTURES", "arm64"),
        ("CMAKE_OSX_SYSROOT", "iphoneos"),
    ]),
    ("arm", &[
        ("CMAKE_OSX_ARCHITECTURES", "arm"),
        ("CMAKE_OSX_SYSROOT", "iphoneos"),
    ]),
    ("x86", &[
        ("CMAKE_OSX_ARCHITECTURES", "x86"),
        ("CMAKE_OSX_SYSROOT", "iphonesimulator"),
    ]),
    ("x86_64", &[
        ("CMAKE_OSX_ARCHITECTURES", "x86_64"),
        ("CMAKE_OSX_SYSROOT", "iphonesimulator"),
    ]),
];

/// Generate the platform-specific output path for lib
///
/// MSVC generator on Windows place static libs in a target sub-folder,
/// so adjust library location based on platform and build target.
/// See issue: https://github.com/alexcrichton/cmake-rs/issues/18
fn platform_output_path(lib: &str) -> String {
    if cfg!(windows) {
        if cfg!(debug_assertions) {
            return format!("{}/Debug", lib);
        } else {
            return format!("{}/RelWithDebInfo", lib);
        }
    } else {
        return format!("{}", lib);
    };
}

// Returns a new cmake::Config for building BoringSSL.
//
// It will add platform-specific parameters if needed.
fn get_boringssl_cmake_config() -> cmake::Config {
    let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
    let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();

    let mut boringssl_cmake = cmake::Config::new("deps/boringssl");

    // Add platform-specific parameters.
    return match os.as_ref() {
        "android" => {
            // We need ANDROID_NDK_HOME to be set properly.
            let android_ndk_home = std::env::var("ANDROID_NDK_HOME")
                .expect("Please set ANDROID_NDK_HOME for Android build");
            for (android_arch, params) in CMAKE_PARAMS_ANDROID {
                if *android_arch == arch {
                    for (name, value) in *params {
                        let value = value
                            .replace("${ANDROID_NDK_HOME}", &android_ndk_home);
                        eprintln!("android arch={} add {}={}", arch, name, value);
                        boringssl_cmake.define(name, value);
                    }
                }
            }

            boringssl_cmake
        },

        "ios" => {
            for (ios_arch, params) in CMAKE_PARAMS_IOS {
                if *ios_arch == arch {
                    for (name, value) in *params {
                        eprintln!("ios arch={} add {}={}", arch, name, value);
                        boringssl_cmake.define(name, value);
                    }
                }
            }

            // bitcode on
            boringssl_cmake.define("CMAKE_ASM_FLAGS", "-fembed-bitcode");
            boringssl_cmake.cflag("-fembed-bitcode");

            boringssl_cmake
        },

        _ => boringssl_cmake,
    };
}

fn main() {
    #[cfg(feature = "no_bssl")]
    return;

    let bssl_dir = std::env::var("QUICHE_BSSL_PATH").unwrap_or_else(|_| {
        get_boringssl_cmake_config()
            .cflag("-fPIC")
            .build_target("bssl")
            .build()
            .display()
            .to_string()
    });

    let crypto_dir =
        format!("{}/build/{}", bssl_dir, platform_output_path("crypto"));
    println!("cargo:rustc-link-search=native={}", crypto_dir);
    println!("cargo:rustc-link-lib=static=crypto");

    let ssl_dir = format!("{}/build/{}", bssl_dir, platform_output_path("ssl"));
    println!("cargo:rustc-link-search=native={}", ssl_dir);
    println!("cargo:rustc-link-lib=static=ssl");
}
<commit_msg>build: avoid unreachable code warning for no_bssl feature builds<commit_after>use cmake;

// Additional parameters for Android build of BoringSSL.
const CMAKE_PARAMS_ANDROID: &[(&str, &[(&str, &str)])] = &[
    ("aarch64", &[
        ("ANDROID_TOOLCHAIN_NAME", "aarch64-linux-android-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
    ]),
    ("arm", &[
        ("ANDROID_TOOLCHAIN_NAME", "arm-linux-androideabi-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
    ]),
    ("x86", &[
        ("ANDROID_TOOLCHAIN_NAME", "x86-linux-android-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
    ]),
    ("x86_64", &[
        ("ANDROID_TOOLCHAIN_NAME", "x86_64-linux-android-4.9"),
        ("ANDROID_NATIVE_API_LEVEL", "21"),
        (
            "CMAKE_TOOLCHAIN_FILE",
            "${ANDROID_NDK_HOME}/build/cmake/android.toolchain.cmake",
        ),
    ]),
];

const CMAKE_PARAMS_IOS: &[(&str, &[(&str, &str)])] = &[
    ("aarch64", &[
        ("CMAKE_OSX_ARCHITECTURES", "arm64"),
        ("CMAKE_OSX_SYSROOT", "iphoneos"),
    ]),
    ("arm", &[
        ("CMAKE_OSX_ARCHITECTURES", "arm"),
        ("CMAKE_OSX_SYSROOT", "iphoneos"),
    ]),
    ("x86", &[
        ("CMAKE_OSX_ARCHITECTURES", "x86"),
        ("CMAKE_OSX_SYSROOT", "iphonesimulator"),
    ]),
    ("x86_64", &[
        ("CMAKE_OSX_ARCHITECTURES", "x86_64"),
        ("CMAKE_OSX_SYSROOT", "iphonesimulator"),
    ]),
];

/// Generate the platform-specific output path for lib
///
/// MSVC generator on Windows place static libs in a target sub-folder,
/// so adjust library location based on platform and build target.
/// See issue: https://github.com/alexcrichton/cmake-rs/issues/18
fn platform_output_path(lib: &str) -> String {
    if cfg!(windows) {
        if cfg!(debug_assertions) {
            return format!("{}/Debug", lib);
        } else {
            return format!("{}/RelWithDebInfo", lib);
        }
    } else {
        return format!("{}", lib);
    };
}

// Returns a new cmake::Config for building BoringSSL.
//
// It will add platform-specific parameters if needed.
fn get_boringssl_cmake_config() -> cmake::Config {
    let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
    let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();

    let mut boringssl_cmake = cmake::Config::new("deps/boringssl");

    // Add platform-specific parameters.
    return match os.as_ref() {
        "android" => {
            // We need ANDROID_NDK_HOME to be set properly.
            let android_ndk_home = std::env::var("ANDROID_NDK_HOME")
                .expect("Please set ANDROID_NDK_HOME for Android build");
            for (android_arch, params) in CMAKE_PARAMS_ANDROID {
                if *android_arch == arch {
                    for (name, value) in *params {
                        let value = value
                            .replace("${ANDROID_NDK_HOME}", &android_ndk_home);
                        eprintln!("android arch={} add {}={}", arch, name, value);
                        boringssl_cmake.define(name, value);
                    }
                }
            }

            boringssl_cmake
        },

        "ios" => {
            for (ios_arch, params) in CMAKE_PARAMS_IOS {
                if *ios_arch == arch {
                    for (name, value) in *params {
                        eprintln!("ios arch={} add {}={}", arch, name, value);
                        boringssl_cmake.define(name, value);
                    }
                }
            }

            // bitcode on
            boringssl_cmake.define("CMAKE_ASM_FLAGS", "-fembed-bitcode");
            boringssl_cmake.cflag("-fembed-bitcode");

            boringssl_cmake
        },

        _ => boringssl_cmake,
    };
}

fn main() {
    if !cfg!(feature = "no_bssl") {
        let bssl_dir = std::env::var("QUICHE_BSSL_PATH").unwrap_or_else(|_| {
            get_boringssl_cmake_config()
                .cflag("-fPIC")
                .build_target("bssl")
                .build()
                .display()
                .to_string()
        });

        let crypto_dir =
            format!("{}/build/{}", bssl_dir, platform_output_path("crypto"));
        println!("cargo:rustc-link-search=native={}", crypto_dir);
        println!("cargo:rustc-link-lib=static=crypto");

        let ssl_dir =
            format!("{}/build/{}", bssl_dir, platform_output_path("ssl"));
        println!("cargo:rustc-link-search=native={}", ssl_dir);
        println!("cargo:rustc-link-lib=static=ssl");
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Richard Diamond & contributors.
//
// This file is part of the Rust PPApi project.
//
// Rust PPApi is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Rust PPApi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Rust PPApi. If not, see <http://www.gnu.org/licenses/>.

extern crate "pnacl-build-helper" as helper;

pub fn main() {
    let mut a = helper::Archive::new("helper");
    a.cxx("src/libhelper/helper.cpp", ["-Os".to_string()]);
    a.archive();
}
<commit_msg>Update for rust-lang changes.<commit_after>// Copyright (c) 2014 Richard Diamond & contributors.
//
// This file is part of the Rust PPApi project.
//
// Rust PPApi is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Rust PPApi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Rust PPApi. If not, see <http://www.gnu.org/licenses/>.

extern crate "pnacl-build-helper" as helper;

pub fn main() {
    let mut a = helper::Archive::new("helper");
    a.cxx("src/libhelper/helper.cpp", &["-Os".to_string()]);
    a.archive();
}
<|endoftext|>


<commit_before>use std::process::exit;
use std::path::Path;
use std::env;

use clap;
use cargo_shim::{
    Profile,
    CargoPackage,
    CargoProject,
    CargoTarget,
    BuildType,
    BuildConfig,
    TargetKind,
    CargoResult,
    MessageFormat,
    target_to_build_target
};

use config::Config;
use emscripten::initialize_emscripten;
use error::Error;
use wasm;

pub struct BuildArgsMatcher< 'a > {
    pub matches: &'a clap::ArgMatches< 'a >,
    pub project: &'a CargoProject
}

impl< 'a > BuildArgsMatcher< 'a > {
    fn requested_build_type( &self ) -> BuildType {
        if self.matches.is_present( "release" ) {
            BuildType::Release
        } else {
            BuildType::Debug
        }
    }

    pub fn targeting_emscripten_asmjs( &self ) -> bool {
        !self.targeting_emscripten_wasm() && !self.targeting_native_wasm()
    }

    pub fn targeting_emscripten_wasm( &self ) -> bool {
        self.matches.is_present( "target-webasm-emscripten" )
    }

    pub fn targeting_native_wasm( &self ) -> bool {
        self.matches.is_present( "target-webasm" )
    }

    pub fn targeting_wasm( &self ) -> bool {
        self.targeting_emscripten_wasm() || self.targeting_native_wasm()
    }

    pub fn targeting_emscripten( &self ) -> bool {
        self.targeting_emscripten_wasm() || self.targeting_emscripten_asmjs()
    }

    fn use_system_emscripten( &self ) -> bool {
        self.matches.is_present( "use-system-emscripten" )
    }

    fn message_format( &self ) -> MessageFormat {
        if let Some( name ) = self.matches.value_of( "message-format" ) {
            match name {
                "human" => MessageFormat::Human,
                "json" => MessageFormat::Json,
                _ => unreachable!()
            }
        } else {
            MessageFormat::Human
        }
    }

    fn is_verbose( &self ) -> bool {
        self.matches.is_present( "verbose" )
    }

    fn build_type( &self ) -> BuildType {
        let build_type = self.requested_build_type();
        if self.targeting_native_wasm() && build_type == BuildType::Debug {
            // TODO: Remove this in the future.
            println_err!( "warning: debug builds on the wasm-unknown-unknown are currently totally broken" );
            println_err!( "         forcing a release build" );
            return BuildType::Release;
        }

        build_type
    }

    fn package( &self ) -> Result< Option< &CargoPackage >, Error > {
        if let Some( name ) = self.matches.value_of( "package" ) {
            match self.project.packages.iter().find( |package| package.name == name ) {
                None => Err( Error::ConfigurationError( format!( "package `{}` not found", name ) ) ),
                package => Ok( package )
            }
        } else {
            Ok( None )
        }
    }

    pub fn package_or_default( &self ) -> Result< &CargoPackage, Error > {
        Ok( self.package()?.unwrap_or_else( || self.project.default_package() ) )
    }

    fn target( &'a self, package: &'a CargoPackage ) -> Result< Option< &'a CargoTarget >, Error > {
        let targets = &package.targets;
        if self.matches.is_present( "lib" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Lib ) {
                None => return Err( Error::ConfigurationError( format!( "no library targets found" ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "bin" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Bin && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no bin target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "example" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Example && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no example target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "bench" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Bench && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no bench target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else {
            Ok( None )
        }
    }

    pub fn target_or_select< F >( &'a self, package: &'a CargoPackage, filter: F ) -> Result< Vec< &'a CargoTarget >, Error >
        where for< 'r > F: Fn( &'r CargoTarget ) -> bool
    {
        Ok( self.target( package )?.map( |target| vec![ target ] ).unwrap_or_else( || {
            package.targets.iter().filter( |target| filter( target ) ).collect()
        }))
    }

    fn triplet_or_default( &self ) -> &str {
        if self.matches.is_present( "target-webasm") {
            "wasm32-unknown-unknown"
        } else if self.matches.is_present( "target-webasm-emscripten" ) {
            "wasm32-unknown-emscripten"
        } else {
            "asmjs-unknown-emscripten"
        }
    }

    fn features( &self ) -> Vec< &str > {
        if let Some( features ) = self.matches.value_of( "features" ) {
            features.split_whitespace().collect()
        } else {
            Vec::new()
        }
    }

    pub fn prepare_builder( &self, config: &Config, package: &CargoPackage, target: &CargoTarget, profile: Profile ) -> Builder {
        let mut extra_paths = Vec::new();
        let mut extra_rustflags = Vec::new();
        let mut extra_environment = Vec::new();

        if self.targeting_emscripten() {
            if let Some( emscripten ) = initialize_emscripten( self.use_system_emscripten(), self.targeting_wasm() ) {
                extra_paths.push( emscripten.emscripten_path.clone() );

                let emscripten_path = emscripten.emscripten_path.to_string_lossy().into_owned();
                let emscripten_llvm_path = emscripten.emscripten_llvm_path.to_string_lossy().into_owned();

                extra_environment.push( ("EMSCRIPTEN".to_owned(), emscripten_path) );
                extra_environment.push( ("EMSCRIPTEN_FASTCOMP".to_owned(), emscripten_llvm_path.clone()) );
                extra_environment.push( ("LLVM".to_owned(), emscripten_llvm_path) );
                if let Some( binaryen_path ) = emscripten.binaryen_path {
                    let binaryen_path = binaryen_path.to_string_lossy().into_owned();
                    extra_environment.push( ("BINARYEN".to_owned(), binaryen_path) );
                }
            }

            // When compiling tests we want the exit runtime,
            // when compiling for the Web we don't want it
            // since that's more efficient.
            let exit_runtime = profile == Profile::Main;

            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( "link-arg=-s".to_owned() );
            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( format!( "link-arg=NO_EXIT_RUNTIME={}", exit_runtime as u32 ) );
        }

        if let Some( ref link_args ) = config.link_args {
            for arg in link_args {
                if arg.contains( " " ) {
                    // Not sure how to handle spaces, as `-C link-arg="{}"` doesn't work.
                    println_err!( "error: you have a space in one of the entries in `link-args` in your `Web.toml`;" );
                    println_err!( "       this is currently unsupported - aborting!" );
                    exit( 101 );
                }

                extra_rustflags.push( "-C".to_owned() );
                extra_rustflags.push( format!( "link-arg={}", arg ) );
            }
        }

        if self.targeting_native_wasm() && self.requested_build_type() == BuildType::Debug {
            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( "debuginfo=2".to_owned() );
        }

        if self.targeting_native_wasm() {
            // Incremental compilation currently doesn't work very well with
            // this target, so disable it.
            if env::var_os( "CARGO_INCREMENTAL" ).is_some() {
                extra_environment.push( ("CARGO_INCREMENTAL".to_owned(), "0".to_owned()) );
            }
        }

        Builder::new( BuildConfig {
            build_target: target_to_build_target( target, profile ),
            build_type: self.build_type(),
            triplet: Some( self.triplet_or_default().into() ),
            package: Some( package.name.clone() ),
            features: self.features().into_iter().map( |feature| feature.to_owned() ).collect(),
            no_default_features: self.matches.is_present( "no-default-features" ),
            enable_all_features: self.matches.is_present( "all-features" ),
            extra_paths,
            extra_rustflags,
            extra_environment,
            message_format: self.message_format(),
            is_verbose: self.is_verbose()
        })
    }
}

pub struct Builder( BuildConfig );

impl Builder {
    pub fn new( build_config: BuildConfig ) -> Self {
        Builder( build_config )
    }

    pub fn run( &self ) -> Result< CargoResult, Error > {
        let result = self.0.build( Some( |path: &Path| {
            if let Some( artifact ) = wasm::process_wasm_file( &self.0, path ) {
                vec![ artifact ]
            } else {
                Vec::new()
            }
        }));

        if result.is_ok() == false {
            return Err( Error::BuildError );
        }

        Ok( result )
    }
}
<commit_msg>Set `ALLOW_MEMORY_GROWTH=1` when targetting WASM through Emscripten<commit_after>use std::process::exit;
use std::path::Path;
use std::env;

use clap;
use cargo_shim::{
    Profile,
    CargoPackage,
    CargoProject,
    CargoTarget,
    BuildType,
    BuildConfig,
    TargetKind,
    CargoResult,
    MessageFormat,
    target_to_build_target
};

use config::Config;
use emscripten::initialize_emscripten;
use error::Error;
use wasm;

pub struct BuildArgsMatcher< 'a > {
    pub matches: &'a clap::ArgMatches< 'a >,
    pub project: &'a CargoProject
}

impl< 'a > BuildArgsMatcher< 'a > {
    fn requested_build_type( &self ) -> BuildType {
        if self.matches.is_present( "release" ) {
            BuildType::Release
        } else {
            BuildType::Debug
        }
    }

    pub fn targeting_emscripten_asmjs( &self ) -> bool {
        !self.targeting_emscripten_wasm() && !self.targeting_native_wasm()
    }

    pub fn targeting_emscripten_wasm( &self ) -> bool {
        self.matches.is_present( "target-webasm-emscripten" )
    }

    pub fn targeting_native_wasm( &self ) -> bool {
        self.matches.is_present( "target-webasm" )
    }

    pub fn targeting_wasm( &self ) -> bool {
        self.targeting_emscripten_wasm() || self.targeting_native_wasm()
    }

    pub fn targeting_emscripten( &self ) -> bool {
        self.targeting_emscripten_wasm() || self.targeting_emscripten_asmjs()
    }

    fn use_system_emscripten( &self ) -> bool {
        self.matches.is_present( "use-system-emscripten" )
    }

    fn message_format( &self ) -> MessageFormat {
        if let Some( name ) = self.matches.value_of( "message-format" ) {
            match name {
                "human" => MessageFormat::Human,
                "json" => MessageFormat::Json,
                _ => unreachable!()
            }
        } else {
            MessageFormat::Human
        }
    }

    fn is_verbose( &self ) -> bool {
        self.matches.is_present( "verbose" )
    }

    fn build_type( &self ) -> BuildType {
        let build_type = self.requested_build_type();
        if self.targeting_native_wasm() && build_type == BuildType::Debug {
            // TODO: Remove this in the future.
            println_err!( "warning: debug builds on the wasm-unknown-unknown are currently totally broken" );
            println_err!( "         forcing a release build" );
            return BuildType::Release;
        }

        build_type
    }

    fn package( &self ) -> Result< Option< &CargoPackage >, Error > {
        if let Some( name ) = self.matches.value_of( "package" ) {
            match self.project.packages.iter().find( |package| package.name == name ) {
                None => Err( Error::ConfigurationError( format!( "package `{}` not found", name ) ) ),
                package => Ok( package )
            }
        } else {
            Ok( None )
        }
    }

    pub fn package_or_default( &self ) -> Result< &CargoPackage, Error > {
        Ok( self.package()?.unwrap_or_else( || self.project.default_package() ) )
    }

    fn target( &'a self, package: &'a CargoPackage ) -> Result< Option< &'a CargoTarget >, Error > {
        let targets = &package.targets;
        if self.matches.is_present( "lib" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Lib ) {
                None => return Err( Error::ConfigurationError( format!( "no library targets found" ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "bin" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Bin && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no bin target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "example" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Example && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no example target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else if let Some( name ) = self.matches.value_of( "bench" ) {
            match targets.iter().find( |target| target.kind == TargetKind::Bench && target.name == name ) {
                None => return Err( Error::ConfigurationError( format!( "no bench target named `{}`", name ) ) ),
                target => Ok( target )
            }
        } else {
            Ok( None )
        }
    }

    pub fn target_or_select< F >( &'a self, package: &'a CargoPackage, filter: F ) -> Result< Vec< &'a CargoTarget >, Error >
        where for< 'r > F: Fn( &'r CargoTarget ) -> bool
    {
        Ok( self.target( package )?.map( |target| vec![ target ] ).unwrap_or_else( || {
            package.targets.iter().filter( |target| filter( target ) ).collect()
        }))
    }

    fn triplet_or_default( &self ) -> &str {
        if self.matches.is_present( "target-webasm") {
            "wasm32-unknown-unknown"
        } else if self.matches.is_present( "target-webasm-emscripten" ) {
            "wasm32-unknown-emscripten"
        } else {
            "asmjs-unknown-emscripten"
        }
    }

    fn features( &self ) -> Vec< &str > {
        if let Some( features ) = self.matches.value_of( "features" ) {
            features.split_whitespace().collect()
        } else {
            Vec::new()
        }
    }

    pub fn prepare_builder( &self, config: &Config, package: &CargoPackage, target: &CargoTarget, profile: Profile ) -> Builder {
        let mut extra_paths = Vec::new();
        let mut extra_rustflags = Vec::new();
        let mut extra_environment = Vec::new();

        if self.targeting_emscripten() {
            if let Some( emscripten ) = initialize_emscripten( self.use_system_emscripten(), self.targeting_wasm() ) {
                extra_paths.push( emscripten.emscripten_path.clone() );

                let emscripten_path = emscripten.emscripten_path.to_string_lossy().into_owned();
                let emscripten_llvm_path = emscripten.emscripten_llvm_path.to_string_lossy().into_owned();

                extra_environment.push( ("EMSCRIPTEN".to_owned(), emscripten_path) );
                extra_environment.push( ("EMSCRIPTEN_FASTCOMP".to_owned(), emscripten_llvm_path.clone()) );
                extra_environment.push( ("LLVM".to_owned(), emscripten_llvm_path) );
                if let Some( binaryen_path ) = emscripten.binaryen_path {
                    let binaryen_path = binaryen_path.to_string_lossy().into_owned();
                    extra_environment.push( ("BINARYEN".to_owned(), binaryen_path) );
                }
            }

            // When compiling tests we want the exit runtime,
            // when compiling for the Web we don't want it
            // since that's more efficient.
            let exit_runtime = profile == Profile::Main;

            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( "link-arg=-s".to_owned() );
            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( format!( "link-arg=NO_EXIT_RUNTIME={}", exit_runtime as u32 ) );

            // This will allow the initially preallocated chunk
            // of memory to grow. On asm.js this has a performance
            // impact which is why we don't turn it on by default there,
            // however according to the Emscripten documentation the WASM
            // backend doesn't have that problem, so we enable it there.
            //
            // See more here:
            //   https://kripken.github.io/emscripten-site/docs/optimizing/Optimizing-Code.html#memory-growth
            let allow_memory_growth = self.targeting_emscripten_wasm();

            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( "link-arg=-s".to_owned() );
            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( format!( "link-arg=ALLOW_MEMORY_GROWTH={}", allow_memory_growth as u32 ) );
        }

        if let Some( ref link_args ) = config.link_args {
            for arg in link_args {
                if arg.contains( " " ) {
                    // Not sure how to handle spaces, as `-C link-arg="{}"` doesn't work.
                    println_err!( "error: you have a space in one of the entries in `link-args` in your `Web.toml`;" );
                    println_err!( "       this is currently unsupported - aborting!" );
                    exit( 101 );
                }

                extra_rustflags.push( "-C".to_owned() );
                extra_rustflags.push( format!( "link-arg={}", arg ) );
            }
        }

        if self.targeting_native_wasm() && self.requested_build_type() == BuildType::Debug {
            extra_rustflags.push( "-C".to_owned() );
            extra_rustflags.push( "debuginfo=2".to_owned() );
        }

        if self.targeting_native_wasm() {
            // Incremental compilation currently doesn't work very well with
            // this target, so disable it.
            if env::var_os( "CARGO_INCREMENTAL" ).is_some() {
                extra_environment.push( ("CARGO_INCREMENTAL".to_owned(), "0".to_owned()) );
            }
        }

        Builder::new( BuildConfig {
            build_target: target_to_build_target( target, profile ),
            build_type: self.build_type(),
            triplet: Some( self.triplet_or_default().into() ),
            package: Some( package.name.clone() ),
            features: self.features().into_iter().map( |feature| feature.to_owned() ).collect(),
            no_default_features: self.matches.is_present( "no-default-features" ),
            enable_all_features: self.matches.is_present( "all-features" ),
            extra_paths,
            extra_rustflags,
            extra_environment,
            message_format: self.message_format(),
            is_verbose: self.is_verbose()
        })
    }
}

pub struct Builder( BuildConfig );

impl Builder {
    pub fn new( build_config: BuildConfig ) -> Self {
        Builder( build_config )
    }

    pub fn run( &self ) -> Result< CargoResult, Error > {
        let result = self.0.build( Some( |path: &Path| {
            if let Some( artifact ) = wasm::process_wasm_file( &self.0, path ) {
                vec![ artifact ]
            } else {
                Vec::new()
            }
        }));

        if result.is_ok() == false {
            return Err( Error::BuildError );
        }

        Ok( result )
    }
}
<|endoftext|>