<commit_before>//! Implements a generic UCI chess engine.

use std::cmp::max;
use std::marker::PhantomData;
use std::cell::UnsafeCell;
use std::collections::VecDeque;
use std::ops::Deref;
use std::sync::Arc;
use std::time::{SystemTime, Duration};
use std::cmp::min;
use std::io;
use uci::*;
use value::*;
use depth::*;
use hash_table::*;
use search_executor::{SearchParams, SearchReport, SearchExecutor};
use search_node::SearchNode;
use time_manager::{TimeManager, RemainingTime};
use pv::{Variation, extract_pv};

struct SearchStatus {
    pub done: bool,
    pub depth: Depth,
    pub value: Value,
    pub searched_nodes: u64,

    // The duration of the search in milliseconds.
    pub duration_millis: u64,
}

impl Default for SearchStatus {
    fn default() -> Self {
        SearchStatus {
            done: false,
            depth: 0,
            value: VALUE_UNKNOWN,
            searched_nodes: 0,
            duration_millis: 0,
        }
    }
}

enum PlayWhen<S, T>
    where S: SearchExecutor<ReportData = Vec<Variation>>,
          T: TimeManager<S>
{
    TimeManagement(T), // Stop when the time manager says so.
    MoveTime(u64), // Stop after the given number of milliseconds.
    Nodes(u64), // Stop when the given number of nodes has been searched.
    Depth(Depth), // Stop when the given search depth has been completed.
    Mate(i16), // Stop when a mate in the given number of moves is found.
    Never(PhantomData<S>), // An infinite search.
}

struct Engine<S, T>
    where S: SearchExecutor<ReportData = Vec<Variation>>,
          T: TimeManager<S>
{
    tt: Arc<S::HashTable>,
    position: S::SearchNode,
    searcher: S,
    queue: VecDeque<EngineReply>,

    // The starting time of the current/last search.
    started_at: SystemTime,

    // The status of the current/last search.
    status: SearchStatus,

    // Nodes per second statistics.
    nps_stats: (u64, u64, u64),

    // Helps the engine decide when to show periodic progress reports.
    silent_since: SystemTime,

    // Whether the engine is thinking in pondering mode at the moment.
    is_pondering: bool,

    // Tells the engine when it must stop thinking and play the best move.
    play_when: PlayWhen<S, T>,
}

impl<S, T> UciEngine for Engine<S, T>
    where S: SearchExecutor<ReportData = Vec<Variation>>,
          T: TimeManager<S>
{
    fn name() -> &'static str {
        ENGINE_IDENTITY.with(|e| unsafe { (&*e.get()).name })
    }

    fn author() -> &'static str {
        ENGINE_IDENTITY.with(|e| unsafe { (&*e.get()).author })
    }

    fn options() -> Vec<(String, OptionDescription)> {
        // Add up all suported options.
        let mut options = vec![
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 64 * 1024, default: 16 }),
            ("Clear Hash".to_string(), OptionDescription::Button),
        ];
        options.extend(S::options());
        options.extend(T::options());

        // Remove duplicated options.
        options.sort_by(|a, b| a.0.cmp(&b.0));
        let mut options_dedup = vec![];
        let mut prev_name = String::from("");
        for o in options.drain(..) {
            if o.0 == prev_name {
                continue;
            }
            prev_name = o.0.clone();
            options_dedup.push(o);
        }
        options_dedup
    }

    fn new(tt_size_mb: Option<usize>) -> Engine<S, T> {
        const START_FEN: &'static str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 1";
        let tt = Arc::new(S::HashTable::new(tt_size_mb));
        let started_at = SystemTime::now();
        Engine {
            tt: tt.clone(),
            position: S::SearchNode::from_history(START_FEN, &mut vec![].into_iter()).ok().unwrap(),
            searcher: S::new(tt),
            queue: VecDeque::new(),
            started_at: started_at,
            status: SearchStatus { done: true, ..Default::default() },
            nps_stats: (0, 0, 0),
            silent_since: started_at,
            is_pondering: false,
            play_when: PlayWhen::Never(PhantomData),
        }
    }

    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Hash" => {
                // We do not support re-sizing of the transposition
                // table once the engine has been started.
                return;
            }
            "Clear Hash" => {
                self.tt.clear();
            }
            _ => (),
        }
        S::set_option(name, value);
        T::set_option(name, value);
    }

    fn new_game(&mut self) {
        self.tt.clear();
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if let Ok(p) = S::SearchNode::from_history(fen, moves) {
            self.position = p;
        }
    }

    fn go(&mut self, params: &GoParams) {
        self.terminate();

        // Validate `params.searchmoves`.
        let searchmoves = {
            let mut moves = vec![];
            let legal_moves = self.position.legal_moves();
            if !params.searchmoves.is_empty() {
                let mut v = params.searchmoves.clone();
                v.sort();
                for m in legal_moves.iter() {
                    if v.binary_search(&m.notation()).is_ok() {
                        moves.push(*m);
                    }
                }
            };
            if moves.is_empty() {
                legal_moves
            } else {
                moves
            }
        };

        // Start a new search.
        let depth = params.depth.map_or(DEPTH_MAX, |x| min(x, DEPTH_MAX as u64) as Depth);
        self.tt.new_search();
        self.started_at = SystemTime::now();
        self.status = Default::default();
        self.nps_stats = (self.nps_stats.0, 0, 0);
        self.silent_since = self.started_at;
        self.is_pondering = params.ponder;
        self.play_when = if params.infinite {
            PlayWhen::Never(PhantomData)
        } else if params.movetime.is_some() {
            PlayWhen::MoveTime(params.movetime.unwrap())
        } else if params.nodes.is_some() {
            PlayWhen::Nodes(params.nodes.unwrap())
        } else if params.depth.is_some() {
            PlayWhen::Depth(depth)
        } else if params.mate.is_some() {
            PlayWhen::Mate(min(params.mate.unwrap(), (DEPTH_MAX + 1) as u64 / 2) as i16)
        } else {
            PlayWhen::TimeManagement(T::new(&self.position,
                                            RemainingTime {
                                                white_millis: params.wtime.unwrap_or(300_000),
                                                black_millis: params.btime.unwrap_or(300_000),
                                                winc_millis: params.winc.unwrap_or(0),
                                                binc_millis: params.binc.unwrap_or(0),
                                                movestogo: params.movestogo,
                                            }))
        };
        self.searcher.start_search(SearchParams {
            search_id: 0,
            position: self.position.clone(),
            depth: depth,
            lower_bound: VALUE_MIN,
            upper_bound: VALUE_MAX,
            searchmoves: searchmoves,
        });
    }

    fn ponder_hit(&mut self) {
        if self.status.done {
            self.queue_best_move();
        } else {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        self.terminate();
        self.queue_best_move();
    }

    fn wait_for_reply(&mut self, duration: Duration) -> Option<EngineReply> {
        if self.queue.is_empty() {
            let is_thinking = !self.status.done;

            // Wait for the search thread to do some work, and
            // hopefully update the status. (We must do this even when
            // the engine is not thinking -- in that case the next
            // line will just yield the CPU to another process.)
            self.wait_status_update(duration);

            // See if we must stop thinking and play.
            if is_thinking && !self.is_pondering &&
               match self.play_when {
                PlayWhen::TimeManagement(ref tm) => {
                    self.status.done || tm.must_play(&self.searcher)
                }
                PlayWhen::MoveTime(t) => self.status.done || self.status.duration_millis >= t,
                PlayWhen::Nodes(n) => self.status.done || self.status.searched_nodes >= n,
                PlayWhen::Depth(d) => self.status.done || self.status.depth >= d,
                PlayWhen::Mate(m) => self.status.done || self.status.value > VALUE_MAX - 2 * m,
                PlayWhen::Never(_) => false,
            } {
                self.stop();
            }
        }

        self.queue.pop_front()
    }

    fn exit(&mut self) {
        self.terminate();
    }
}

impl<S, T> Engine<S, T>
    where S: SearchExecutor<ReportData = Vec<Variation>>,
          T: TimeManager<S>
{
    fn queue_progress_info(&mut self) {
        let SearchStatus { ref depth, ref searched_nodes, ref duration_millis, .. } = self.status;
        self.queue.push_back(EngineReply::Info(vec![
            InfoItem { info_type: "depth".to_string(), data: format!("{}", depth) },
            InfoItem { info_type: "time".to_string(), data: format!("{}", duration_millis) },
            InfoItem { info_type: "nodes".to_string(), data: format!("{}", searched_nodes) },
            InfoItem { info_type: "nps".to_string(), data: format!("{}", self.nps_stats.0) },
        ]));
    }

    fn queue_pv(&mut self, variations: &Vec<Variation>) {
        fn suffix(bound: BoundType) -> &'static str {
            match bound {
                BOUND_UPPER => " upperbound",
                BOUND_LOWER => " lowerbound",
                BOUND_EXACT => "",
                _ => panic!("unexpected bound type"),
            }
        }

        let SearchStatus { ref depth, ref searched_nodes, ref duration_millis, .. } = self.status;
        for (i, &Variation { ref moves, value, bound }) in variations.iter().enumerate() {
            let score = match value {
                v if bound & BOUND_UPPER != 0 && VALUE_MIN < v && v < VALUE_EVAL_MIN => {
                    format!("mate {}", (VALUE_MIN - v - 1) / 2)
                }
                v if bound & BOUND_LOWER != 0 && VALUE_EVAL_MAX < v && v < VALUE_MAX => {
                    format!("mate {}", (VALUE_MAX - v + 1) / 2)
                }
                v if v <= -9999 => format!("cp -9999{}", suffix(bound | BOUND_LOWER)),
                v if v >= 9999 => format!("cp 9999{}", suffix(bound | BOUND_UPPER)),
                v => format!("cp {}{}", v, suffix(bound)),
            };
            let mut pv = String::new();
            for m in moves.iter().take(max(0, *depth) as usize) {
                pv.push_str(&m.notation());
                pv.push(' ');
            }
            self.queue.push_back(EngineReply::Info(vec![
                InfoItem { info_type: "depth".to_string(), data: format!("{}", depth) },
                InfoItem { info_type: "multipv".to_string(), data: format!("{}", i + 1) },
                InfoItem { info_type: "score".to_string(), data: score },
                InfoItem { info_type: "time".to_string(), data: format!("{}", duration_millis) },
                InfoItem { info_type: "nodes".to_string(), data: format!("{}", searched_nodes) },
                InfoItem { info_type: "nps".to_string(), data: format!("{}", self.nps_stats.0) },
                InfoItem { info_type: "pv".to_string(), data: pv },
            ]));
        }
    }

    fn queue_best_move(&mut self) {
        let pv = extract_pv(self.tt.deref(), &self.position);
        let best_move = if let Some(m) = pv.moves.get(0) {
            m.notation()
        } else {
            // If there is no best move, pick the first legal move.
            self.position.legal_moves().get(0).map_or("0000".to_string(), |m| m.notation())
        };
        self.queue.push_back(EngineReply::BestMove {
            best_move: best_move,
            ponder_move: pv.moves.get(1).map(|m| m.notation()),
        });
    }

    fn terminate(&mut self) {
        self.searcher.terminate_search();
        while !self.status.done {
            self.wait_status_update(Duration::from_millis(1000));
        }
    }

    fn wait_status_update(&mut self, duration: Duration) {
        self.searcher.wait_report(duration);
        while let Ok(r) = self.searcher.try_recv_report() {
            self.process_report(&r)
        }
    }

    fn process_report(&mut self, report: &SearchReport<Vec<Variation>>) {
        let duration_millis = {
            let d = self.started_at.elapsed().unwrap();
            1000 * d.as_secs() + (d.subsec_nanos() / 1_000_000) as u64
        };
        self.status = SearchStatus {
            done: report.done,
            depth: report.depth,
            value: report.value,
            searched_nodes: report.searched_nodes,
            duration_millis: duration_millis,
        };

        // Update `self.nps_stats` every 1000 milliseconds.
        let elapsed_millis = duration_millis - self.nps_stats.2;
        if elapsed_millis >= 1000 {
            let nodes = report.searched_nodes - self.nps_stats.1;
            self.nps_stats = (1000 * nodes / elapsed_millis, report.searched_nodes, duration_millis)
        }

        // Inform the time manager.
        if let PlayWhen::TimeManagement(ref mut tm) = self.play_when {
            tm.update(report);
        }

        // If principal variations are provided with the report, show them.
        if !report.data.is_empty() {
            self.queue_pv(&report.data);
            self.silent_since = SystemTime::now();
        }

        // If nothing has happened for a while, show progress info.
        if self.silent_since.elapsed().unwrap().as_secs() > 10 {
            self.queue_progress_info();
            self.silent_since = SystemTime::now();
        }
    }
}

/// Serves UCI commands until a "quit" command is received.
///
/// The current thread will block until the UCI session is closed.
///
/// Returns `Err` if the handshake was unsuccessful, or if an IO error
/// occurred.
pub fn run<S, T>(name: &'static str, author: &'static str) -> io::Result<()>
    where S: SearchExecutor<ReportData = Vec<Variation>>,
          T: TimeManager<S>
{
    ENGINE_IDENTITY.with(|e| unsafe {
        let e = &mut *e.get();
        e.name = name;
        e.author = author;
    });
    run_engine::<Engine<S, T>>()
}

// Since `run_server` blocks the current thread, it can safely pass
// engine's name and author as thread-local statics. (This time,
// simplicity beats beauty.)
thread_local!(
    static ENGINE_IDENTITY: UnsafeCell<EngineIdentity> =
        UnsafeCell::new(EngineIdentity { name: "", author: ""})
);

struct EngineIdentity {
    name: &'static str,
    author: &'static str,
}
<commit_msg>use lock to ensure that only one engine is running<commit_after>//! Implements a generic UCI chess engine.

use std::marker::PhantomData;
use std::collections::VecDeque;
use std::ops::Deref;
use std::sync::{Arc, Mutex};
use std::time::{SystemTime, Duration};
use std::cmp::{min, max};
use std::io;
use uci::*;
use value::*;
use depth::*;
use hash_table::*;
use search_executor::{SearchParams, SearchReport, SearchExecutor};
use search_node::SearchNode;
use time_manager::{TimeManager, RemainingTime};
use pv::{Variation, extract_pv};

struct SearchStatus {
    pub done: bool,
    pub depth: Depth,
    pub value: Value,
    pub searched_nodes: u64,

    // The duration of the search in milliseconds.
    pub duration_millis: u64,
}

impl Default for SearchStatus {
    fn default() -> Self {
        SearchStatus {
            done: false,
            depth: 0,
            value: VALUE_UNKNOWN,
            searched_nodes: 0,
            duration_millis: 0,
        }
    }
}

enum PlayWhen<S, T>
    where S: SearchExecutor<ReportData = Vec<Variation>>,
          T: TimeManager<S>
{
    TimeManagement(T), // Stop when the time manager says so.
    MoveTime(u64), // Stop after the given number of milliseconds.
    Nodes(u64), // Stop when the given number of nodes has been searched.
    Depth(Depth), // Stop when the given search depth has been completed.
    Mate(i16), // Stop when a mate in the given number of moves is found.
    Never(PhantomData<S>), // An infinite search.
}

struct Engine<S, T>
    where S: SearchExecutor<ReportData = Vec<Variation>>,
          T: TimeManager<S>
{
    tt: Arc<S::HashTable>,
    position: S::SearchNode,
    searcher: S,
    queue: VecDeque<EngineReply>,

    // The starting time of the current/last search.
    started_at: SystemTime,

    // The status of the current/last search.
    status: SearchStatus,

    // Nodes per second statistics.
    nps_stats: (u64, u64, u64),

    // Helps the engine decide when to show periodic progress reports.
    silent_since: SystemTime,

    // Whether the engine is thinking in pondering mode at the moment.
    is_pondering: bool,

    // Tells the engine when it must stop thinking and play the best move.
    play_when: PlayWhen<S, T>,
}

impl<S, T> UciEngine for Engine<S, T>
    where S: SearchExecutor<ReportData = Vec<Variation>>,
          T: TimeManager<S>
{
    fn name() -> &'static str {
        ENGINE.lock().unwrap().as_ref().unwrap().name
    }

    fn author() -> &'static str {
        ENGINE.lock().unwrap().as_ref().unwrap().author
    }

    fn options() -> Vec<(String, OptionDescription)> {
        // Add up all suported options.
        let mut options = vec![
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 64 * 1024, default: 16 }),
            ("Clear Hash".to_string(), OptionDescription::Button),
        ];
        options.extend(S::options());
        options.extend(T::options());

        // Remove duplicated options.
        options.sort_by(|a, b| a.0.cmp(&b.0));
        let mut options_dedup = vec![];
        let mut prev_name = String::from("");
        for o in options.drain(..) {
            if o.0 == prev_name {
                continue;
            }
            prev_name = o.0.clone();
            options_dedup.push(o);
        }
        options_dedup
    }

    fn new(tt_size_mb: Option<usize>) -> Engine<S, T> {
        const START_FEN: &'static str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 1";
        let tt = Arc::new(S::HashTable::new(tt_size_mb));
        let started_at = SystemTime::now();
        Engine {
            tt: tt.clone(),
            position: S::SearchNode::from_history(START_FEN, &mut vec![].into_iter()).ok().unwrap(),
            searcher: S::new(tt),
            queue: VecDeque::new(),
            started_at: started_at,
            status: SearchStatus { done: true, ..Default::default() },
            nps_stats: (0, 0, 0),
            silent_since: started_at,
            is_pondering: false,
            play_when: PlayWhen::Never(PhantomData),
        }
    }

    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Hash" => {
                // We do not support re-sizing of the transposition
                // table once the engine has been started.
                return;
            }
            "Clear Hash" => {
                self.tt.clear();
            }
            _ => (),
        }
        S::set_option(name, value);
        T::set_option(name, value);
    }

    fn new_game(&mut self) {
        self.tt.clear();
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if let Ok(p) = S::SearchNode::from_history(fen, moves) {
            self.position = p;
        }
    }

    fn go(&mut self, params: &GoParams) {
        self.terminate();

        // Validate `params.searchmoves`.
        let searchmoves = {
            let mut moves = vec![];
            let legal_moves = self.position.legal_moves();
            if !params.searchmoves.is_empty() {
                let mut v = params.searchmoves.clone();
                v.sort();
                for m in legal_moves.iter() {
                    if v.binary_search(&m.notation()).is_ok() {
                        moves.push(*m);
                    }
                }
            };
            if moves.is_empty() {
                legal_moves
            } else {
                moves
            }
        };

        // Start a new search.
        let depth = params.depth.map_or(DEPTH_MAX, |x| min(x, DEPTH_MAX as u64) as Depth);
        self.tt.new_search();
        self.started_at = SystemTime::now();
        self.status = Default::default();
        self.nps_stats = (self.nps_stats.0, 0, 0);
        self.silent_since = self.started_at;
        self.is_pondering = params.ponder;
        self.play_when = if params.infinite {
            PlayWhen::Never(PhantomData)
        } else if params.movetime.is_some() {
            PlayWhen::MoveTime(params.movetime.unwrap())
        } else if params.nodes.is_some() {
            PlayWhen::Nodes(params.nodes.unwrap())
        } else if params.depth.is_some() {
            PlayWhen::Depth(depth)
        } else if params.mate.is_some() {
            PlayWhen::Mate(min(params.mate.unwrap(), (DEPTH_MAX + 1) as u64 / 2) as i16)
        } else {
            PlayWhen::TimeManagement(T::new(&self.position,
                                            RemainingTime {
                                                white_millis: params.wtime.unwrap_or(300_000),
                                                black_millis: params.btime.unwrap_or(300_000),
                                                winc_millis: params.winc.unwrap_or(0),
                                                binc_millis: params.binc.unwrap_or(0),
                                                movestogo: params.movestogo,
                                            }))
        };
        self.searcher.start_search(SearchParams {
            search_id: 0,
            position: self.position.clone(),
            depth: depth,
            lower_bound: VALUE_MIN,
            upper_bound: VALUE_MAX,
            searchmoves: searchmoves,
        });
    }

    fn ponder_hit(&mut self) {
        if self.status.done {
            self.queue_best_move();
        } else {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        self.terminate();
        self.queue_best_move();
    }

    fn wait_for_reply(&mut self, duration: Duration) -> Option<EngineReply> {
        if self.queue.is_empty() {
            let is_thinking = !self.status.done;

            // Wait for the search thread to do some work, and
            // hopefully update the status. (We must do this even when
            // the engine is not thinking -- in that case the next
            // line will just yield the CPU to another process.)
            self.wait_status_update(duration);

            // See if we must stop thinking and play.
            if is_thinking && !self.is_pondering &&
               match self.play_when {
                PlayWhen::TimeManagement(ref tm) => {
                    self.status.done || tm.must_play(&self.searcher)
                }
                PlayWhen::MoveTime(t) => self.status.done || self.status.duration_millis >= t,
                PlayWhen::Nodes(n) => self.status.done || self.status.searched_nodes >= n,
                PlayWhen::Depth(d) => self.status.done || self.status.depth >= d,
                PlayWhen::Mate(m) => self.status.done || self.status.value > VALUE_MAX - 2 * m,
                PlayWhen::Never(_) => false,
            } {
                self.stop();
            }
        }

        self.queue.pop_front()
    }

    fn exit(&mut self) {
        self.terminate();
    }
}

impl<S, T> Engine<S, T>
    where S: SearchExecutor<ReportData = Vec<Variation>>,
          T: TimeManager<S>
{
    fn queue_progress_info(&mut self) {
        let SearchStatus { ref depth, ref searched_nodes, ref duration_millis, .. } = self.status;
        self.queue.push_back(EngineReply::Info(vec![
            InfoItem { info_type: "depth".to_string(), data: format!("{}", depth) },
            InfoItem { info_type: "time".to_string(), data: format!("{}", duration_millis) },
            InfoItem { info_type: "nodes".to_string(), data: format!("{}", searched_nodes) },
            InfoItem { info_type: "nps".to_string(), data: format!("{}", self.nps_stats.0) },
        ]));
    }

    fn queue_pv(&mut self, variations: &Vec<Variation>) {
        fn suffix(bound: BoundType) -> &'static str {
            match bound {
                BOUND_UPPER => " upperbound",
                BOUND_LOWER => " lowerbound",
                BOUND_EXACT => "",
                _ => panic!("unexpected bound type"),
            }
        }

        let SearchStatus { ref depth, ref searched_nodes, ref duration_millis, .. } = self.status;
        for (i, &Variation { ref moves, value, bound }) in variations.iter().enumerate() {
            let score = match value {
                v if bound & BOUND_UPPER != 0 && VALUE_MIN < v && v < VALUE_EVAL_MIN => {
                    format!("mate {}", (VALUE_MIN - v - 1) / 2)
                }
                v if bound & BOUND_LOWER != 0 && VALUE_EVAL_MAX < v && v < VALUE_MAX => {
                    format!("mate {}", (VALUE_MAX - v + 1) / 2)
                }
                v if v <= -9999 => format!("cp -9999{}", suffix(bound | BOUND_LOWER)),
                v if v >= 9999 => format!("cp 9999{}", suffix(bound | BOUND_UPPER)),
                v => format!("cp {}{}", v, suffix(bound)),
            };
            let mut pv = String::new();
            for m in moves.iter().take(max(0, *depth) as usize) {
                pv.push_str(&m.notation());
                pv.push(' ');
            }
            self.queue.push_back(EngineReply::Info(vec![
                InfoItem { info_type: "depth".to_string(), data: format!("{}", depth) },
                InfoItem { info_type: "multipv".to_string(), data: format!("{}", i + 1) },
                InfoItem { info_type: "score".to_string(), data: score },
                InfoItem { info_type: "time".to_string(), data: format!("{}", duration_millis) },
                InfoItem { info_type: "nodes".to_string(), data: format!("{}", searched_nodes) },
                InfoItem { info_type: "nps".to_string(), data: format!("{}", self.nps_stats.0) },
                InfoItem { info_type: "pv".to_string(), data: pv },
            ]));
        }
    }

    fn queue_best_move(&mut self) {
        let pv = extract_pv(self.tt.deref(), &self.position);
        let best_move = if let Some(m) = pv.moves.get(0) {
            m.notation()
        } else {
            // If there is no best move, pick the first legal move.
            self.position.legal_moves().get(0).map_or("0000".to_string(), |m| m.notation())
        };
        self.queue.push_back(EngineReply::BestMove {
            best_move: best_move,
            ponder_move: pv.moves.get(1).map(|m| m.notation()),
        });
    }

    fn terminate(&mut self) {
        self.searcher.terminate_search();
        while !self.status.done {
            self.wait_status_update(Duration::from_millis(1000));
        }
    }

    fn wait_status_update(&mut self, duration: Duration) {
        self.searcher.wait_report(duration);
        while let Ok(r) = self.searcher.try_recv_report() {
            self.process_report(&r)
        }
    }

    fn process_report(&mut self, report: &SearchReport<Vec<Variation>>) {
        let duration_millis = {
            let d = self.started_at.elapsed().unwrap();
            1000 * d.as_secs() + (d.subsec_nanos() / 1_000_000) as u64
        };
        self.status = SearchStatus {
            done: report.done,
            depth: report.depth,
            value: report.value,
            searched_nodes: report.searched_nodes,
            duration_millis: duration_millis,
        };

        // Update `self.nps_stats` every 1000 milliseconds.
        let elapsed_millis = duration_millis - self.nps_stats.2;
        if elapsed_millis >= 1000 {
            let nodes = report.searched_nodes - self.nps_stats.1;
            self.nps_stats = (1000 * nodes / elapsed_millis, report.searched_nodes, duration_millis)
        }

        // Inform the time manager.
        if let PlayWhen::TimeManagement(ref mut tm) = self.play_when {
            tm.update(report);
        }

        // If principal variations are provided with the report, show them.
        if !report.data.is_empty() {
            self.queue_pv(&report.data);
            self.silent_since = SystemTime::now();
        }

        // If nothing has happened for a while, show progress info.
        if self.silent_since.elapsed().unwrap().as_secs() > 10 {
            self.queue_progress_info();
            self.silent_since = SystemTime::now();
        }
    }
}

/// Serves UCI commands until a "quit" command is received.
///
/// The current thread will block until the UCI session is closed.
///
/// Returns `Err` if the handshake was unsuccessful, or if an IO error
/// occurred.
pub fn run<S, T>(name: &'static str, author: &'static str) -> io::Result<()>
    where S: SearchExecutor<ReportData = Vec<Variation>>,
          T: TimeManager<S>
{
    // Obtain the lock.
    {
        let mut engine = ENGINE.lock().unwrap();
        assert!(engine.is_none(), "two engines can not run in parallel");
        *engine = Some(EngineIdentity {
            name: name,
            author: author,
        });
    }

    // Run the engine.
    let result = run_engine::<Engine<S, T>>();

    // Release the lock.
    *ENGINE.lock().unwrap() = None;
    result
}

struct EngineIdentity {
    name: &'static str,
    author: &'static str,
}

lazy_static! {
    static ref ENGINE: Mutex<Option<EngineIdentity>> = Mutex::new(None);
}
<|endoftext|>


<commit_before>use libc::{c_int, c_uint, c_ulonglong, size_t};
use ffi::{core, target};
use ffi::execution_engine as engine;
use ffi::execution_engine::*;
use ffi::target_machine::LLVMCodeModel;
use cbox::CBox;
use std::marker::PhantomData;
use std::{mem, ptr};
use std::ops::*;
use compile::Compile;
use context::{Context, GetContext};
use module::Module;
use ty::{StructType, Type};
use util::{self, CastFrom};
use value::{Function, Value};

/// An abstract interface for implementation execution of LLVM modules.
///
/// This is designed to support both interpreter and just-in-time (JIT) compiler implementations.
pub trait ExecutionEngine<'a, 'b:'a> where LLVMExecutionEngineRef:From<&'b Self> {
    /// The options given to this upon creation.
    type Options : Copy;
    /// Create a new execution engine with the given `Module` and options, or return a
    /// description of the error.
    fn new(module: &'a Module, options: Self::Options) -> Result<Self, CBox<str>>;

    /// Add a module to the list of modules to interpret or compile.
    fn add_module(&'b self, module: &'a Module) {
        unsafe { engine::LLVMAddModule(self.into(), (&*module).into()) }
    }
    /// Remove a module from the list of modules to interpret or compile.
    fn remove_module(&'b self, module: &'a Module) -> &'a Module {
        unsafe {
            let mut out = mem::uninitialized();
            engine::LLVMRemoveModule(self.into(), module.into(), &mut out, ptr::null_mut());
            out.into()
        }
    }
    /// Execute all of the static constructors for this program.
    fn run_static_constructors(&'b self) {
        unsafe { engine::LLVMRunStaticConstructors(self.into()) }
    }
    /// Execute all of the static destructors for this program.
    fn run_static_destructors(&'b self) {
        unsafe { engine::LLVMRunStaticDestructors(self.into()) }
    }
    /// Attempt to find a function with the name given, or `None` if there wasn't
    /// a function with that name.
    fn find_function(&'b self, name: &str) -> Option<&'a Function> {
        util::with_cstr(name, |c_name| unsafe {
            let mut out = mem::zeroed();
            engine::LLVMFindFunction(self.into(), c_name, &mut out);
            mem::transmute(out)
        })
    }
    /// Run `function` with the arguments given as ``GenericValue`s, then return the result as one.
    ///
    /// Note that if this engine is a `JitEngine`, it only supports a small fraction of combinations
    /// for the arguments and return value, so be warned.
    ///
    /// To convert the arguments to `GenericValue`s, you should use the `GenericValueCast::to_generic` method.
    /// To convert the return value from a `GenericValue`, you should use the `GenericValueCast::from_generic` method.
    fn run_function(&'b self, function: &'a Function, args: &[GenericValue<'a>]) -> GenericValue<'a> {
        let ptr = args.as_ptr() as *mut LLVMGenericValueRef;
        unsafe { engine::LLVMRunFunction(self.into(), function.into(), args.len() as c_uint, ptr).into() }
    }
    /// Returns a pointer to the global value given.
    ///
    /// This is marked as unsafe because the type cannot be guranteed to be the same as the
    /// type of the global value at this point.
    unsafe fn get_global<T>(&'b self, global: &'a Value) -> &'b T {
        mem::transmute(engine::LLVMGetPointerToGlobal(self.into(), global.into()))
    }
    /// Returns a pointer to the global value with the name given.
    ///
    /// This is marked as unsafe because the type cannot be guranteed to be the same as the
    /// type of the global value at this point.
    unsafe fn find_global<T>(&'b self, name: &str) -> Option<&'b T> {
        util::with_cstr(name, |ptr|
            mem::transmute(engine::LLVMGetGlobalValueAddress(self.into(), ptr))
        )
    }
}

/// The options to pass to the MCJIT backend.
#[derive(Copy, Clone)]
pub struct JitOptions {
    /// The degree to which optimizations should be done, between 0 and 3.
    ///
    /// 0 represents no optimizations, 3 represents maximum optimization
    pub opt_level: usize
}
/// The MCJIT backend, which compiles functions and values into machine code.
pub struct JitEngine<'a> {
    engine: LLVMExecutionEngineRef,
    marker: PhantomData<&'a ()>
}
native_ref!{contra JitEngine, engine: LLVMExecutionEngineRef}
impl<'a, 'b> JitEngine<'a> {
    /// Run the closure `cb` with the machine code for the function `function`.
    ///
    /// This will check that the types match at runtime when in debug mode, but not release mode.
    /// You should make sure to use debug mode if you want it to error when the types don't match.
    pub fn with_function<C, A, R>(&self, function: &'b Function, cb: C) where A:Compile<'b>, R:Compile<'b>, C:FnOnce(extern fn(A) -> R) {
        if cfg!(not(ndebug)) {
            let ctx = function.get_context();
            let sig = function.get_signature();
            assert_eq!(Type::get::<R>(ctx), sig.get_return());
            let arg = Type::get::<A>(ctx);
            if let Some(args) = StructType::cast(arg) {
                assert_eq!(sig.get_params(), args.get_elements());
            } else {
                let nparams = sig.get_params().len();
                if nparams == 1 {
                    assert_eq!(arg, sig.get_params()[0]);
                } else if nparams == 0 {
                    assert_eq!(arg, Type::get::<()>(ctx));
                } else {
                    panic!("array type arguments are not yet supported; use a tuple or struct instead");
                }
            }
        }
        unsafe {
            cb(self.get_function::<A, R>(function));
        }
    }
    /// Run the closure `cb` with the machine code for the function `function`.
    pub unsafe fn with_function_unchecked<C, A, R>(&self, function: &'b Function, cb: C) where A:Compile<'b>, R:Compile<'b>, C:FnOnce(extern fn(A) -> R) {
        cb(self.get_function::<A, R>(function));
    }
    /// Returns a pointer to the machine code for the function `function`.
    ///
    /// This is marked as unsafe because the types given as arguments and return could be different
    /// from their internal representation.
    pub unsafe fn get_function<A, R>(&self, function: &'b Function) -> extern fn(A) -> R {
        let ptr:&u8 = self.get_global(function);
        mem::transmute(ptr)
    }
}
impl<'a, 'b:'a> ExecutionEngine<'a, 'b> for JitEngine<'a> {
    type Options = JitOptions;
    fn new(module: &'a Module, options: JitOptions) -> Result<JitEngine<'a>, CBox<str>> {
        unsafe {
            let mut ee = mem::uninitialized();
            let mut out = mem::zeroed();
            engine::LLVMLinkInMCJIT();
            if target::LLVM_InitializeNativeTarget() == 1 {
                return Err("failed to initialize native target".into())
            }
            if target::LLVM_InitializeNativeAsmPrinter() == 1 {
                return Err("failed to initialize native asm printer".into())
            }
            let mut options = LLVMMCJITCompilerOptions {
                OptLevel: options.opt_level as c_uint,
                CodeModel: LLVMCodeModel::LLVMCodeModelJITDefault,
                NoFramePointerElim: 0,
                EnableFastISel: 1,
                MCJMM: ptr::null_mut()
            };
            let size = mem::size_of::<LLVMMCJITCompilerOptions>();
            let result = engine::LLVMCreateMCJITCompilerForModule(&mut ee, (&*module).into(), &mut options, size as size_t, &mut out);
            if result == 0 {
                Ok(ee.into())
            } else {
                Err(CBox::new(out))
            }
        }
    }
}
/// The interpreter backend
pub struct Interpreter<'a> {
    engine: LLVMExecutionEngineRef,
    marker: PhantomData<&'a ()>
}
native_ref!{contra Interpreter, engine: LLVMExecutionEngineRef}
impl<'a> Interpreter<'a> {
    /// Run `function` with the arguments given as ``GenericValue`s, then return the result as one.
    ///
    /// To convert the arguments to `GenericValue`s, you should use the `GenericValueCast::to_generic` method.
    /// To convert the return value from a `GenericValue`, you should use the `GenericValueCast::from_generic` method.
    pub fn run_function(&self, function: &'a Function, args: &[GenericValue<'a>]) -> GenericValue<'a> {
        let ptr = args.as_ptr() as *mut LLVMGenericValueRef;
        unsafe { engine::LLVMRunFunction(self.into(), function.into(), args.len() as c_uint, ptr).into() }
    }
}
impl<'a, 'b:'a> ExecutionEngine<'a, 'b> for Interpreter<'a> {
    type Options = ();
    fn new(module: &'a Module, _: ()) -> Result<Interpreter<'a>, CBox<str>> {
        unsafe {
            let mut ee = mem::uninitialized();
            let mut out = mem::zeroed();
            engine::LLVMLinkInInterpreter();
            let result = engine::LLVMCreateInterpreterForModule(&mut ee, (&*module).into(), &mut out);
            if result == 0 {
                Ok(ee.into())
            } else {
                Err(CBox::new(out))
            }
        }
    }
}
/// A wrapped value that can be passed to an interpreted function or returned from one
pub struct GenericValue<'a> {
    value: LLVMGenericValueRef,
    marker: PhantomData<&'a ()>
}
native_ref!(contra GenericValue, value: LLVMGenericValueRef);
impl<'a> Drop for GenericValue<'a> {
    fn drop(&mut self) {
        unsafe {
            engine::LLVMDisposeGenericValue(self.value)
        }
    }
}

/// A value that can be cast into a `GenericValue` and that a `GenericValue` can be cast into.
///
/// Both these methods require contexts because some `Type` constructors are needed for the
/// conversion and these constructors need a context.
pub trait GenericValueCast<'a> {
    /// Create a `GenericValue` from this value.
    fn to_generic(self, context: &'a Context) -> GenericValue<'a>;
    /// Convert the `GenericValue` into a value of this type again.
    fn from_generic(value: GenericValue<'a>, context: &'a Context) -> Self;
}

impl<'a> GenericValueCast<'a> for f64 {
    fn to_generic(self, ctx: &'a Context) -> GenericValue<'a> {
        unsafe {
            let ty = core::LLVMDoubleTypeInContext(ctx.into());
            engine::LLVMCreateGenericValueOfFloat(ty, self).into()
        }
    }
    fn from_generic(value: GenericValue<'a>, ctx: &'a Context) -> f64 {
        unsafe {
            let ty = core::LLVMDoubleTypeInContext(ctx.into());
            engine::LLVMGenericValueToFloat(ty, value.into())
        }
    }
}
impl<'a> GenericValueCast<'a> for f32 {
    fn to_generic(self, ctx: &'a Context) -> GenericValue<'a> {
        unsafe {
            let ty = core::LLVMFloatTypeInContext(ctx.into());
            engine::LLVMCreateGenericValueOfFloat(ty, self as f64).into()
        }
    }
    fn from_generic(value: GenericValue<'a>, ctx: &'a Context) -> f32 {
        unsafe {
            let ty = core::LLVMFloatTypeInContext(ctx.into());
            engine::LLVMGenericValueToFloat(ty, value.into()) as f32
        }
    }
}
macro_rules! generic_int(
    ($ty:ty, $signed:expr) => (
        impl<'a> GenericValueCast<'a> for $ty {
            fn to_generic(self, ctx: &'a Context) -> GenericValue<'a> {
                unsafe {
                    let ty = <Self as Compile<'a>>::get_type(ctx);
                    engine::LLVMCreateGenericValueOfInt(ty.into(), self as c_ulonglong, $signed as c_int).into()
                }
            }
            fn from_generic(value: GenericValue<'a>, _: &'a Context) -> $ty {
                unsafe {
                    engine::LLVMGenericValueToInt(value.into(), $signed as c_int) as $ty
                }
            }
        }
    );
    (some $signed:ty, $unsigned:ty) => (
        generic_int!{$signed, true}
        generic_int!{$unsigned, false}
    );
);

impl<'a> GenericValueCast<'a> for bool {
    fn to_generic(self, ctx: &'a Context) -> GenericValue<'a> {
        unsafe {
            let ty = <Self as Compile<'a>>::get_type(ctx);
            engine::LLVMCreateGenericValueOfInt(ty.into(), self as c_ulonglong, 0).into()
        }
    }
    fn from_generic(value: GenericValue<'a>, _: &'a Context) -> bool {
        unsafe {
            engine::LLVMGenericValueToInt(value.into(), 0) != 0
        }
    }
}
generic_int!{some i8, u8}
generic_int!{some i16, u16}
generic_int!{some i32, u32}
generic_int!{some i64, u64}
<commit_msg>Add support for adding global mappings<commit_after>use libc::{c_int, c_uint, c_ulonglong, size_t};
use ffi::{core, target};
use ffi::execution_engine as engine;
use ffi::execution_engine::*;
use ffi::target_machine::LLVMCodeModel;
use cbox::CBox;
use std::marker::PhantomData;
use std::{mem, ptr};
use std::ops::*;
use compile::Compile;
use context::{Context, GetContext};
use module::Module;
use ty::{StructType, Type};
use util::{self, CastFrom};
use value::{Function, Value};

/// An abstract interface for implementation execution of LLVM modules.
///
/// This is designed to support both interpreter and just-in-time (JIT) compiler implementations.
pub trait ExecutionEngine<'a, 'b:'a> where LLVMExecutionEngineRef:From<&'b Self> {
    /// The options given to this upon creation.
    type Options : Copy;
    /// Create a new execution engine with the given `Module` and options, or return a
    /// description of the error.
    fn new(module: &'a Module, options: Self::Options) -> Result<Self, CBox<str>>;

    /// Add a module to the list of modules to interpret or compile.
    fn add_module(&'b self, module: &'a Module) {
        unsafe { engine::LLVMAddModule(self.into(), (&*module).into()) }
    }
    /// Remove a module from the list of modules to interpret or compile.
    fn remove_module(&'b self, module: &'a Module) -> &'a Module {
        unsafe {
            let mut out = mem::uninitialized();
            engine::LLVMRemoveModule(self.into(), module.into(), &mut out, ptr::null_mut());
            out.into()
        }
    }
    /// Execute all of the static constructors for this program.
    fn run_static_constructors(&'b self) {
        unsafe { engine::LLVMRunStaticConstructors(self.into()) }
    }
    /// Execute all of the static destructors for this program.
    fn run_static_destructors(&'b self) {
        unsafe { engine::LLVMRunStaticDestructors(self.into()) }
    }
    /// Attempt to find a function with the name given, or `None` if there wasn't
    /// a function with that name.
    fn find_function(&'b self, name: &str) -> Option<&'a Function> {
        util::with_cstr(name, |c_name| unsafe {
            let mut out = mem::zeroed();
            engine::LLVMFindFunction(self.into(), c_name, &mut out);
            mem::transmute(out)
        })
    }
    /// Run `function` with the arguments given as ``GenericValue`s, then return the result as one.
    ///
    /// Note that if this engine is a `JitEngine`, it only supports a small fraction of combinations
    /// for the arguments and return value, so be warned.
    ///
    /// To convert the arguments to `GenericValue`s, you should use the `GenericValueCast::to_generic` method.
    /// To convert the return value from a `GenericValue`, you should use the `GenericValueCast::from_generic` method.
    fn run_function(&'b self, function: &'a Function, args: &[GenericValue<'a>]) -> GenericValue<'a> {
        let ptr = args.as_ptr() as *mut LLVMGenericValueRef;
        unsafe { engine::LLVMRunFunction(self.into(), function.into(), args.len() as c_uint, ptr).into() }
    }
    /// Returns a pointer to the global value given.
    ///
    /// This is marked as unsafe because the type cannot be guranteed to be the same as the
    /// type of the global value at this point.
    unsafe fn get_global<T>(&'b self, global: &'a Value) -> &'b T {
        mem::transmute(engine::LLVMGetPointerToGlobal(self.into(), global.into()))
    }
    /// Returns a pointer to the global value with the name given.
    ///
    /// This is marked as unsafe because the type cannot be guranteed to be the same as the
    /// type of the global value at this point.
    unsafe fn find_global<T>(&'b self, name: &str) -> Option<&'b T> {
        util::with_cstr(name, |ptr|
            mem::transmute(engine::LLVMGetGlobalValueAddress(self.into(), ptr))
        )
    }
    /// Maps a global to a specific memory location.
    unsafe fn add_global_mapping<T>(&'b self, global: &'a Value, addr: *const T) {
        engine::LLVMAddGlobalMapping(self.into(), global.into(), mem::transmute(addr));
    }
}

/// The options to pass to the MCJIT backend.
#[derive(Copy, Clone)]
pub struct JitOptions {
    /// The degree to which optimizations should be done, between 0 and 3.
    ///
    /// 0 represents no optimizations, 3 represents maximum optimization
    pub opt_level: usize
}
/// The MCJIT backend, which compiles functions and values into machine code.
pub struct JitEngine<'a> {
    engine: LLVMExecutionEngineRef,
    marker: PhantomData<&'a ()>
}
native_ref!{contra JitEngine, engine: LLVMExecutionEngineRef}
impl<'a, 'b> JitEngine<'a> {
    /// Run the closure `cb` with the machine code for the function `function`.
    ///
    /// This will check that the types match at runtime when in debug mode, but not release mode.
    /// You should make sure to use debug mode if you want it to error when the types don't match.
    pub fn with_function<C, A, R>(&self, function: &'b Function, cb: C) where A:Compile<'b>, R:Compile<'b>, C:FnOnce(extern fn(A) -> R) {
        if cfg!(not(ndebug)) {
            let ctx = function.get_context();
            let sig = function.get_signature();
            assert_eq!(Type::get::<R>(ctx), sig.get_return());
            let arg = Type::get::<A>(ctx);
            if let Some(args) = StructType::cast(arg) {
                assert_eq!(sig.get_params(), args.get_elements());
            } else {
                let nparams = sig.get_params().len();
                if nparams == 1 {
                    assert_eq!(arg, sig.get_params()[0]);
                } else if nparams == 0 {
                    assert_eq!(arg, Type::get::<()>(ctx));
                } else {
                    panic!("array type arguments are not yet supported; use a tuple or struct instead");
                }
            }
        }
        unsafe {
            cb(self.get_function::<A, R>(function));
        }
    }
    /// Run the closure `cb` with the machine code for the function `function`.
    pub unsafe fn with_function_unchecked<C, A, R>(&self, function: &'b Function, cb: C) where A:Compile<'b>, R:Compile<'b>, C:FnOnce(extern fn(A) -> R) {
        cb(self.get_function::<A, R>(function));
    }
    /// Returns a pointer to the machine code for the function `function`.
    ///
    /// This is marked as unsafe because the types given as arguments and return could be different
    /// from their internal representation.
    pub unsafe fn get_function<A, R>(&self, function: &'b Function) -> extern fn(A) -> R {
        let ptr:&u8 = self.get_global(function);
        mem::transmute(ptr)
    }
}
impl<'a, 'b:'a> ExecutionEngine<'a, 'b> for JitEngine<'a> {
    type Options = JitOptions;
    fn new(module: &'a Module, options: JitOptions) -> Result<JitEngine<'a>, CBox<str>> {
        unsafe {
            let mut ee = mem::uninitialized();
            let mut out = mem::zeroed();
            engine::LLVMLinkInMCJIT();
            if target::LLVM_InitializeNativeTarget() == 1 {
                return Err("failed to initialize native target".into())
            }
            if target::LLVM_InitializeNativeAsmPrinter() == 1 {
                return Err("failed to initialize native asm printer".into())
            }
            let mut options = LLVMMCJITCompilerOptions {
                OptLevel: options.opt_level as c_uint,
                CodeModel: LLVMCodeModel::LLVMCodeModelJITDefault,
                NoFramePointerElim: 0,
                EnableFastISel: 1,
                MCJMM: ptr::null_mut()
            };
            let size = mem::size_of::<LLVMMCJITCompilerOptions>();
            let result = engine::LLVMCreateMCJITCompilerForModule(&mut ee, (&*module).into(), &mut options, size as size_t, &mut out);
            if result == 0 {
                Ok(ee.into())
            } else {
                Err(CBox::new(out))
            }
        }
    }
}
/// The interpreter backend
pub struct Interpreter<'a> {
    engine: LLVMExecutionEngineRef,
    marker: PhantomData<&'a ()>
}
native_ref!{contra Interpreter, engine: LLVMExecutionEngineRef}
impl<'a> Interpreter<'a> {
    /// Run `function` with the arguments given as ``GenericValue`s, then return the result as one.
    ///
    /// To convert the arguments to `GenericValue`s, you should use the `GenericValueCast::to_generic` method.
    /// To convert the return value from a `GenericValue`, you should use the `GenericValueCast::from_generic` method.
    pub fn run_function(&self, function: &'a Function, args: &[GenericValue<'a>]) -> GenericValue<'a> {
        let ptr = args.as_ptr() as *mut LLVMGenericValueRef;
        unsafe { engine::LLVMRunFunction(self.into(), function.into(), args.len() as c_uint, ptr).into() }
    }
}
impl<'a, 'b:'a> ExecutionEngine<'a, 'b> for Interpreter<'a> {
    type Options = ();
    fn new(module: &'a Module, _: ()) -> Result<Interpreter<'a>, CBox<str>> {
        unsafe {
            let mut ee = mem::uninitialized();
            let mut out = mem::zeroed();
            engine::LLVMLinkInInterpreter();
            let result = engine::LLVMCreateInterpreterForModule(&mut ee, (&*module).into(), &mut out);
            if result == 0 {
                Ok(ee.into())
            } else {
                Err(CBox::new(out))
            }
        }
    }
}
/// A wrapped value that can be passed to an interpreted function or returned from one
pub struct GenericValue<'a> {
    value: LLVMGenericValueRef,
    marker: PhantomData<&'a ()>
}
native_ref!(contra GenericValue, value: LLVMGenericValueRef);
impl<'a> Drop for GenericValue<'a> {
    fn drop(&mut self) {
        unsafe {
            engine::LLVMDisposeGenericValue(self.value)
        }
    }
}

/// A value that can be cast into a `GenericValue` and that a `GenericValue` can be cast into.
///
/// Both these methods require contexts because some `Type` constructors are needed for the
/// conversion and these constructors need a context.
pub trait GenericValueCast<'a> {
    /// Create a `GenericValue` from this value.
    fn to_generic(self, context: &'a Context) -> GenericValue<'a>;
    /// Convert the `GenericValue` into a value of this type again.
    fn from_generic(value: GenericValue<'a>, context: &'a Context) -> Self;
}

impl<'a> GenericValueCast<'a> for f64 {
    fn to_generic(self, ctx: &'a Context) -> GenericValue<'a> {
        unsafe {
            let ty = core::LLVMDoubleTypeInContext(ctx.into());
            engine::LLVMCreateGenericValueOfFloat(ty, self).into()
        }
    }
    fn from_generic(value: GenericValue<'a>, ctx: &'a Context) -> f64 {
        unsafe {
            let ty = core::LLVMDoubleTypeInContext(ctx.into());
            engine::LLVMGenericValueToFloat(ty, value.into())
        }
    }
}
impl<'a> GenericValueCast<'a> for f32 {
    fn to_generic(self, ctx: &'a Context) -> GenericValue<'a> {
        unsafe {
            let ty = core::LLVMFloatTypeInContext(ctx.into());
            engine::LLVMCreateGenericValueOfFloat(ty, self as f64).into()
        }
    }
    fn from_generic(value: GenericValue<'a>, ctx: &'a Context) -> f32 {
        unsafe {
            let ty = core::LLVMFloatTypeInContext(ctx.into());
            engine::LLVMGenericValueToFloat(ty, value.into()) as f32
        }
    }
}
macro_rules! generic_int(
    ($ty:ty, $signed:expr) => (
        impl<'a> GenericValueCast<'a> for $ty {
            fn to_generic(self, ctx: &'a Context) -> GenericValue<'a> {
                unsafe {
                    let ty = <Self as Compile<'a>>::get_type(ctx);
                    engine::LLVMCreateGenericValueOfInt(ty.into(), self as c_ulonglong, $signed as c_int).into()
                }
            }
            fn from_generic(value: GenericValue<'a>, _: &'a Context) -> $ty {
                unsafe {
                    engine::LLVMGenericValueToInt(value.into(), $signed as c_int) as $ty
                }
            }
        }
    );
    (some $signed:ty, $unsigned:ty) => (
        generic_int!{$signed, true}
        generic_int!{$unsigned, false}
    );
);

impl<'a> GenericValueCast<'a> for bool {
    fn to_generic(self, ctx: &'a Context) -> GenericValue<'a> {
        unsafe {
            let ty = <Self as Compile<'a>>::get_type(ctx);
            engine::LLVMCreateGenericValueOfInt(ty.into(), self as c_ulonglong, 0).into()
        }
    }
    fn from_generic(value: GenericValue<'a>, _: &'a Context) -> bool {
        unsafe {
            engine::LLVMGenericValueToInt(value.into(), 0) != 0
        }
    }
}
generic_int!{some i8, u8}
generic_int!{some i16, u16}
generic_int!{some i32, u32}
generic_int!{some i64, u64}
<|endoftext|>


<commit_before>//! String escaping.
//!
//! Although filenames in Linux are commonly represented as UTF-8
//! sequences, there is no system requirement that this be the case.  As a
//! consequence, this means that it is possible for filenames in Linux to
//! not be valid UTF-8, and therefore not representable as strings.
//!
//! To prevent encoding problems, as well as to allow certain characters,
//! such as space, to separate tokens in the sure file format, we escape
//! some bytes in strings by replacing them with "=xx" where "xx" is the
//! lower-cased hex version of the string.  The range of valid characters
//! is fairly straightforward, including all of the printable characters
//! from '!' to '~' except for the '=', which is always escaped.  This
//! means, for example, that a 2-byte encoded UTF-8 sequence will expand to
//! take 6 bytes.

use std::io::prelude::*;

pub trait Escape {
    fn escaped(&self) -> String;
}

pub trait Unescape {
    fn unescape(&self) -> Result<Vec<u8>, EscapeError>;
}

error_chain! {
    types {
        EscapeError, EscapeErrorKind, EscapChainError, EscapeResult;
    }

    links {
    }

    foreign_links {
    }

    errors {
        InvalidHexCharacter {
            description("Invalid hex character")
            display("Invalid hex character")
        }
        InvalidHexLength {
            description("Invalid hex length")
            display("Invalid hex length")
        }
    }
}

// The basic encoding converts a sequence of bytes into a string.
impl Escape for [u8] {
    fn escaped(&self) -> String {
        let mut result = vec![];
        for &ch in self.iter() {
            // TODO: Can be made more efficient.
            if b'!' <= ch && ch <= b'~' && ch != b'=' {
                result.push(ch);
            } else {
                write!(&mut result, "={:02x}", ch).unwrap();
            }
        }

        // TODO: String::from_utf8_unchecked(result)
        String::from_utf8(result).unwrap()
    }
}

impl Unescape for str {
    fn unescape(&self) -> Result<Vec<u8>, EscapeError> {
        // Will overestimate.
        let mut buf = Vec::with_capacity(self.len() / 2);
        let mut phase = 0;
        let mut tmp = 0;

        for byte in self.bytes() {
            if phase == 0 {
                if byte == b'=' {
                    phase = 1;
                } else {
                    buf.push(byte);
                }
            } else {
                tmp <<= 4;
                match byte {
                    b'A'...b'F' => tmp |= byte - b'A' + 10,
                    b'a'...b'f' => tmp |= byte - b'a' + 10,
                    b'0'...b'f' => tmp |= byte - b'0',
                    _ => return Err(EscapeErrorKind::InvalidHexCharacter.into()),
                }
                phase += 1;
                if phase == 3 {
                    buf.push(tmp);
                    phase = 0;
                    tmp = 0;
                }
            }
        }

        if phase != 0 {
            return Err(EscapeErrorKind::InvalidHexLength.into());
        }

        Ok(buf)
    }
}

#[test]
fn test_unescape() {
    macro_rules! assert_error_kind {
        ( $expr:expr, $kind:path ) => {
            match $expr.unwrap_err().into_kind() {
                $kind => (),
                _ => panic!("Unexpected error kind"),
            }
        }
    }

    assert_eq!("=00".unescape().unwrap(), vec![0]);
    assert_error_kind!("=00=0".unescape(), EscapeErrorKind::InvalidHexLength);
    assert_error_kind!("=00=".unescape(), EscapeErrorKind::InvalidHexLength);
    assert_error_kind!("=4g".unescape(), EscapeErrorKind::InvalidHexCharacter);
}

#[test]
fn test_escape() {
    let buf: Vec<u8> = (0u32..256).map(|i| i as u8).collect();
    let text = (&buf[..]).escaped();
    assert_eq!(text.unescape().unwrap(), buf);
}
<commit_msg>escape: Add the unexpected hex character to data<commit_after>//! String escaping.
//!
//! Although filenames in Linux are commonly represented as UTF-8
//! sequences, there is no system requirement that this be the case.  As a
//! consequence, this means that it is possible for filenames in Linux to
//! not be valid UTF-8, and therefore not representable as strings.
//!
//! To prevent encoding problems, as well as to allow certain characters,
//! such as space, to separate tokens in the sure file format, we escape
//! some bytes in strings by replacing them with "=xx" where "xx" is the
//! lower-cased hex version of the string.  The range of valid characters
//! is fairly straightforward, including all of the printable characters
//! from '!' to '~' except for the '=', which is always escaped.  This
//! means, for example, that a 2-byte encoded UTF-8 sequence will expand to
//! take 6 bytes.

use std::io::prelude::*;

pub trait Escape {
    fn escaped(&self) -> String;
}

pub trait Unescape {
    fn unescape(&self) -> Result<Vec<u8>, EscapeError>;
}

error_chain! {
    types {
        EscapeError, EscapeErrorKind, EscapChainError, EscapeResult;
    }

    links {
    }

    foreign_links {
    }

    errors {
        InvalidHexCharacter(ch: u8) {
            description("Invalid hex character")
            display("Invalid hex character: {:?}", ch)
        }
        InvalidHexLength {
            description("Invalid hex length")
            display("Invalid hex length")
        }
    }
}

// The basic encoding converts a sequence of bytes into a string.
impl Escape for [u8] {
    fn escaped(&self) -> String {
        let mut result = vec![];
        for &ch in self.iter() {
            // TODO: Can be made more efficient.
            if b'!' <= ch && ch <= b'~' && ch != b'=' {
                result.push(ch);
            } else {
                write!(&mut result, "={:02x}", ch).unwrap();
            }
        }

        // TODO: String::from_utf8_unchecked(result)
        String::from_utf8(result).unwrap()
    }
}

impl Unescape for str {
    fn unescape(&self) -> Result<Vec<u8>, EscapeError> {
        // Will overestimate.
        let mut buf = Vec::with_capacity(self.len() / 2);
        let mut phase = 0;
        let mut tmp = 0;

        for byte in self.bytes() {
            if phase == 0 {
                if byte == b'=' {
                    phase = 1;
                } else {
                    buf.push(byte);
                }
            } else {
                tmp <<= 4;
                match byte {
                    b'A'...b'F' => tmp |= byte - b'A' + 10,
                    b'a'...b'f' => tmp |= byte - b'a' + 10,
                    b'0'...b'f' => tmp |= byte - b'0',
                    _ => return Err(EscapeErrorKind::InvalidHexCharacter(byte).into()),
                }
                phase += 1;
                if phase == 3 {
                    buf.push(tmp);
                    phase = 0;
                    tmp = 0;
                }
            }
        }

        if phase != 0 {
            return Err(EscapeErrorKind::InvalidHexLength.into());
        }

        Ok(buf)
    }
}

#[test]
fn test_unescape() {
    macro_rules! assert_error_kind {
        ( $expr:expr, $kind:pat ) => {
            match $expr.unwrap_err().into_kind() {
                $kind => (),
                e => panic!("Unexpected error kind: {:?} (want {})", e, stringify!($kind)),
            }
        }
    }

    assert_eq!("=00".unescape().unwrap(), vec![0]);
    assert_error_kind!("=00=0".unescape(), EscapeErrorKind::InvalidHexLength);
    assert_error_kind!("=00=".unescape(), EscapeErrorKind::InvalidHexLength);
    assert_error_kind!("=4g".unescape(), EscapeErrorKind::InvalidHexCharacter(b'g'));
}

#[test]
fn test_escape() {
    let buf: Vec<u8> = (0u32..256).map(|i| i as u8).collect();
    let text = (&buf[..]).escaped();
    assert_eq!(text.unescape().unwrap(), buf);
}
<|endoftext|>


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

// Binop corner cases

fn test_nil() {
    assert_eq!((), ());
    assert!((!(() != ())));
    assert!((!(() < ())));
    assert!((() <= ()));
    assert!((!(() > ())));
    assert!((() >= ()));
}

fn test_bool() {
    assert!((!(true < false)));
    assert!((!(true <= false)));
    assert!((true > false));
    assert!((true >= false));

    assert!((false < true));
    assert!((false <= true));
    assert!((!(false > true)));
    assert!((!(false >= true)));

    // Bools support bitwise binops
    assert_eq!(false & false, false);
    assert_eq!(true & false, false);
    assert_eq!(true & true, true);
    assert_eq!(false | false, false);
    assert_eq!(true | false, true);
    assert_eq!(true | true, true);
    assert_eq!(false ^ false, false);
    assert_eq!(true ^ false, true);
    assert_eq!(true ^ true, false);
}

fn test_ptr() {
    unsafe {
        let p1: *const u8 = ::std::mem::transmute(0_usize);
        let p2: *const u8 = ::std::mem::transmute(0_usize);
        let p3: *const u8 = ::std::mem::transmute(1_usize);

        assert_eq!(p1, p2);
        assert!(p1 != p3);
        assert!(p1 < p3);
        assert!(p1 <= p3);
        assert!(p3 > p1);
        assert!(p3 >= p3);
        assert!(p1 <= p2);
        assert!(p1 >= p2);
    }
}

#[derive(PartialEq, Debug)]
struct P {
    x: isize,
    y: isize,
}

fn p(x: isize, y: isize) -> P {
    P {
        x: x,
        y: y
    }
}

fn test_class() {
  let q = p(1, 2);
  let mut r = p(1, 2);

  unsafe {
  println!("q = {:x}, r = {:x}",
         (::std::mem::transmute::<*const P, usize>(&q)),
         (::std::mem::transmute::<*const P, usize>(&r)));
  }
  assert_eq!(q, r);
  r.y = 17;
  assert!((r.y != q.y));
  assert_eq!(r.y, 17);
  assert!((q != r));
}

pub fn main() {
    test_nil();
    test_bool();
    test_ptr();
    test_class();
}
<commit_msg>don't print in the binop tests<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Binop corner cases

fn test_nil() {
    assert_eq!((), ());
    assert!((!(() != ())));
    assert!((!(() < ())));
    assert!((() <= ()));
    assert!((!(() > ())));
    assert!((() >= ()));
}

fn test_bool() {
    assert!((!(true < false)));
    assert!((!(true <= false)));
    assert!((true > false));
    assert!((true >= false));

    assert!((false < true));
    assert!((false <= true));
    assert!((!(false > true)));
    assert!((!(false >= true)));

    // Bools support bitwise binops
    assert_eq!(false & false, false);
    assert_eq!(true & false, false);
    assert_eq!(true & true, true);
    assert_eq!(false | false, false);
    assert_eq!(true | false, true);
    assert_eq!(true | true, true);
    assert_eq!(false ^ false, false);
    assert_eq!(true ^ false, true);
    assert_eq!(true ^ true, false);
}

fn test_ptr() {
    unsafe {
        let p1: *const u8 = ::std::mem::transmute(0_usize);
        let p2: *const u8 = ::std::mem::transmute(0_usize);
        let p3: *const u8 = ::std::mem::transmute(1_usize);

        assert_eq!(p1, p2);
        assert!(p1 != p3);
        assert!(p1 < p3);
        assert!(p1 <= p3);
        assert!(p3 > p1);
        assert!(p3 >= p3);
        assert!(p1 <= p2);
        assert!(p1 >= p2);
    }
}

#[derive(PartialEq, Debug)]
struct P {
    x: isize,
    y: isize,
}

fn p(x: isize, y: isize) -> P {
    P {
        x: x,
        y: y
    }
}

fn test_class() {
  let q = p(1, 2);
  let mut r = p(1, 2);

  assert_eq!(q, r);
  r.y = 17;
  assert!((r.y != q.y));
  assert_eq!(r.y, 17);
  assert!((q != r));
}

pub fn main() {
    test_nil();
    test_bool();
    test_ptr();
    test_class();
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser::RGBA;
use dom::attr::{Attr, AttrValue};
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::HTMLFontElementBinding;
use dom::bindings::codegen::Bindings::HTMLFontElementBinding::HTMLFontElementMethods;
use dom::bindings::conversions::Castable;
use dom::bindings::js::Root;
use dom::document::Document;
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
use dom::htmlelement::HTMLElement;
use dom::node::Node;
use dom::virtualmethods::VirtualMethods;
use std::cell::Cell;
use string_cache::Atom;
use style::values::specified;
use util::str::{self, DOMString, parse_legacy_font_size};

#[dom_struct]
pub struct HTMLFontElement {
    htmlelement: HTMLElement,
    color: Cell<Option<RGBA>>,
    face: DOMRefCell<Option<Atom>>,
}

impl HTMLFontElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: &Document) -> HTMLFontElement {
        HTMLFontElement {
            htmlelement: HTMLElement::new_inherited(localName, prefix, document),
            color: Cell::new(None),
            face: DOMRefCell::new(None),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString,
               prefix: Option<DOMString>,
               document: &Document) -> Root<HTMLFontElement> {
        let element = HTMLFontElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLFontElementBinding::Wrap)
    }
}

impl HTMLFontElementMethods for HTMLFontElement {
    // https://html.spec.whatwg.org/multipage/#dom-font-color
    make_getter!(Color, "color");

    // https://html.spec.whatwg.org/multipage/#dom-font-color
    make_setter!(SetColor, "color");

    // https://html.spec.whatwg.org/multipage/#dom-font-face
    make_getter!(Face);

    // https://html.spec.whatwg.org/multipage/#dom-font-face
    make_atomic_setter!(SetFace, "face");

    // https://html.spec.whatwg.org/multipage/#dom-font-size
    make_getter!(Size);

    // https://html.spec.whatwg.org/multipage/#dom-font-size
    fn SetSize(&self, value: DOMString) {
        let element = self.upcast::<Element>();
        let length = parse_length(&value);
        element.set_attribute(&Atom::from_slice("size"), AttrValue::Length(value, length));
    }
}

impl VirtualMethods for HTMLFontElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);
        match attr.local_name() {
            &atom!(color) => {
                self.color.set(mutation.new_value(attr).and_then(|value| {
                    str::parse_legacy_color(&value).ok()
                }));
            },
            &atom!(face) => {
                *self.face.borrow_mut() =
                    mutation.new_value(attr)
                            .map(|value| value.as_atom().clone())
            },
            _ => {},
        }
    }

    fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue {
        match name {
            &atom!("face") => AttrValue::from_atomic(value),
            &atom!("size") => {
                let length = parse_length(&value);
                AttrValue::Length(value, length)
            },
            _ => self.super_type().unwrap().parse_plain_attribute(name, value),
        }
    }
}

impl HTMLFontElement {
    pub fn get_color(&self) -> Option<RGBA> {
        self.color.get()
    }

    #[allow(unsafe_code)]
    pub fn get_face(&self) -> Option<Atom> {
        let face = unsafe { self.face.borrow_for_layout() };
        match *face {
            Some(ref s) => Some(s.clone()),
            None => None,
        }
    }

    #[allow(unsafe_code)]
    pub fn get_size(&self) -> Option<specified::Length> {
        unsafe {
            self.upcast::<Element>()
                .get_attr_for_layout(&ns!(""), &atom!("size"))
                .and_then(AttrValue::as_length)
                .cloned()
        }
    }
}

fn parse_length(value: &str) -> Option<specified::Length> {
    parse_legacy_font_size(&value).and_then(|parsed| specified::Length::from_str(&parsed))
}
<commit_msg>Remove struct field for <font> 'face' attribute<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser::RGBA;
use dom::attr::{Attr, AttrValue};
use dom::bindings::codegen::Bindings::HTMLFontElementBinding;
use dom::bindings::codegen::Bindings::HTMLFontElementBinding::HTMLFontElementMethods;
use dom::bindings::conversions::Castable;
use dom::bindings::js::Root;
use dom::document::Document;
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
use dom::htmlelement::HTMLElement;
use dom::node::Node;
use dom::virtualmethods::VirtualMethods;
use std::cell::Cell;
use string_cache::Atom;
use style::values::specified;
use util::str::{self, DOMString, parse_legacy_font_size};

#[dom_struct]
pub struct HTMLFontElement {
    htmlelement: HTMLElement,
    color: Cell<Option<RGBA>>,
}

impl HTMLFontElement {
    fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: &Document) -> HTMLFontElement {
        HTMLFontElement {
            htmlelement: HTMLElement::new_inherited(localName, prefix, document),
            color: Cell::new(None),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString,
               prefix: Option<DOMString>,
               document: &Document) -> Root<HTMLFontElement> {
        let element = HTMLFontElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLFontElementBinding::Wrap)
    }
}

impl HTMLFontElementMethods for HTMLFontElement {
    // https://html.spec.whatwg.org/multipage/#dom-font-color
    make_getter!(Color, "color");

    // https://html.spec.whatwg.org/multipage/#dom-font-color
    make_setter!(SetColor, "color");

    // https://html.spec.whatwg.org/multipage/#dom-font-face
    make_getter!(Face);

    // https://html.spec.whatwg.org/multipage/#dom-font-face
    make_atomic_setter!(SetFace, "face");

    // https://html.spec.whatwg.org/multipage/#dom-font-size
    make_getter!(Size);

    // https://html.spec.whatwg.org/multipage/#dom-font-size
    fn SetSize(&self, value: DOMString) {
        let element = self.upcast::<Element>();
        let length = parse_length(&value);
        element.set_attribute(&Atom::from_slice("size"), AttrValue::Length(value, length));
    }
}

impl VirtualMethods for HTMLFontElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);
        match attr.local_name() {
            &atom!(color) => {
                self.color.set(mutation.new_value(attr).and_then(|value| {
                    str::parse_legacy_color(&value).ok()
                }));
            },
            _ => {},
        }
    }

    fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue {
        match name {
            &atom!("face") => AttrValue::from_atomic(value),
            &atom!("size") => {
                let length = parse_length(&value);
                AttrValue::Length(value, length)
            },
            _ => self.super_type().unwrap().parse_plain_attribute(name, value),
        }
    }
}

impl HTMLFontElement {
    pub fn get_color(&self) -> Option<RGBA> {
        self.color.get()
    }

    #[allow(unsafe_code)]
    pub fn get_face(&self) -> Option<Atom> {
        unsafe {
            self.upcast::<Element>()
                .get_attr_for_layout(&ns!(""), &atom!("face"))
                .map(AttrValue::as_atom)
                .cloned()
        }
    }

    #[allow(unsafe_code)]
    pub fn get_size(&self) -> Option<specified::Length> {
        unsafe {
            self.upcast::<Element>()
                .get_attr_for_layout(&ns!(""), &atom!("size"))
                .and_then(AttrValue::as_length)
                .cloned()
        }
    }
}

fn parse_length(value: &str) -> Option<specified::Length> {
    parse_legacy_font_size(&value).and_then(|parsed| specified::Length::from_str(&parsed))
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(non_snake_case)]

use from_json;
use serialize;
use std::collections::HashMap;

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct Document {
    pub bones: Option<Vec<Bone>>,
    pub slots: Option<Vec<Slot>>,
    pub skins: Option<HashMap<String, HashMap<String, HashMap<String, Attachment>>>>,
    pub animations: Option<HashMap<String, Animation>>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct Bone {
    pub name: String,
    pub parent: Option<String>,
    pub length: Option<f64>,
    pub x: Option<f64>,
    pub y: Option<f64>,
    pub scaleX: Option<f64>,
    pub scaleY: Option<f64>,
    pub rotation: Option<f64>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct Slot {
    pub name: String,
    pub bone: String,
    pub color: Option<String>,
    pub attachment: Option<String>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct Attachment {
    pub name: Option<String>,
    #[from_json_name = "type"]
    pub type_: Option<AttachmentType>,
    pub x: Option<f64>,
    pub y: Option<f64>,
    pub scaleX: Option<f64>,
    pub scaleY: Option<f64>,
    pub rotation: Option<f64>,
    pub width: Option<f64>,
    pub height: Option<f64>,
    pub fps: Option<f64>,
    pub mode: Option<f64>,
    //vertices: Option<Vec<??>>     // TODO: ?
}

#[deriving(Show, Clone)]
pub enum AttachmentType {
    Region,
    RegionSequence,
    BoundingBox,
}

impl from_json::FromJson for AttachmentType {
    fn from_json(input: &serialize::json::Json) -> Result<AttachmentType, from_json::FromJsonError> {
        use from_json::FromJson;

        let string: String = try!(FromJson::from_json(input));

        match string.as_slice() {
            "region" => Ok(AttachmentType::Region),
            "regionsequence" => Ok(AttachmentType::RegionSequence),
            "boundingbox" => Ok(AttachmentType::BoundingBox),
            _ => Err(from_json::ExpectError("AttachmentType", input.clone()))
        }
    }
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct Event {
    pub name: String,
    #[from_json_name = "int"]
    pub int_: Option<int>,
    #[from_json_name = "float"]
    pub float_: Option<f64>,
    pub string: Option<String>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct Animation {
    pub bones: Option<HashMap<String, BoneTimeline>>,
    pub slots: Option<HashMap<String, SlotTimeline>>,
    pub events: Option<Vec<EventKeyframe>>,
    pub draworder: Option<Vec<DrawOrderTimeline>>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct BoneTimeline {
    pub translate: Option<Vec<BoneTranslateTimeline>>,
    pub rotate: Option<Vec<BoneRotateTimeline>>,
    pub scale: Option<Vec<BoneScaleTimeline>>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct BoneTranslateTimeline {
    pub time: f64,
    pub curve: Option<TimelineCurve>,
    pub x: Option<f64>,
    pub y: Option<f64>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct BoneRotateTimeline {
    pub time: f64,
    pub curve: Option<TimelineCurve>,
    pub angle: Option<f64>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct BoneScaleTimeline {
    pub time: f64,
    pub curve: Option<TimelineCurve>,
    pub x: Option<f64>,
    pub y: Option<f64>,
}

#[deriving(Show, Clone)]
pub enum TimelineCurve {
    CurveBezier(Vec<f64>),
    CurvePredefined(String),
}

impl from_json::FromJson for TimelineCurve {
    fn from_json(input: &serialize::json::Json) -> Result<TimelineCurve, from_json::FromJsonError> {
        use from_json::FromJson;

        if input.is_list() {
            Ok(TimelineCurve::CurveBezier(try!(FromJson::from_json(input))))
        } else {
            Ok(TimelineCurve::CurvePredefined(try!(FromJson::from_json(input))))
        }
    }
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct SlotTimeline {
    pub attachment: Option<Vec<SlotAttachmentTimeline>>,
    pub color: Option<Vec<SlotColorTimeline>>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct SlotAttachmentTimeline {
    pub time: f64,
    pub name: Option<String>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct SlotColorTimeline {
    pub time: f64,
    pub color: Option<String>,
    pub curve: Option<TimelineCurve>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct EventKeyframe {
    time: f64,
    name: String,
    #[from_json_name = "int"]
    int_: Option<int>,
    #[from_json_name = "float"]
    float_: Option<f64>,
    #[from_json_name = "string"]
    string_: Option<String>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct DrawOrderTimeline {
    time: f64,
    offsets: Option<Vec<DrawOrderTimelineOffset>>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct DrawOrderTimelineOffset {
    slot: String,
    offset: int,
}
<commit_msg>Update for rustc<commit_after>#![allow(dead_code)]
#![allow(non_snake_case)]

use from_json;
use serialize;
use std::collections::HashMap;

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct Document {
    pub bones: Option<Vec<Bone>>,
    pub slots: Option<Vec<Slot>>,
    pub skins: Option<HashMap<String, HashMap<String, HashMap<String, Attachment>>>>,
    pub animations: Option<HashMap<String, Animation>>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct Bone {
    pub name: String,
    pub parent: Option<String>,
    pub length: Option<f64>,
    pub x: Option<f64>,
    pub y: Option<f64>,
    pub scaleX: Option<f64>,
    pub scaleY: Option<f64>,
    pub rotation: Option<f64>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct Slot {
    pub name: String,
    pub bone: String,
    pub color: Option<String>,
    pub attachment: Option<String>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct Attachment {
    pub name: Option<String>,
    #[from_json_name = "type"]
    pub type_: Option<AttachmentType>,
    pub x: Option<f64>,
    pub y: Option<f64>,
    pub scaleX: Option<f64>,
    pub scaleY: Option<f64>,
    pub rotation: Option<f64>,
    pub width: Option<f64>,
    pub height: Option<f64>,
    pub fps: Option<f64>,
    pub mode: Option<f64>,
    //vertices: Option<Vec<??>>     // TODO: ?
}

#[deriving(Show, Clone)]
pub enum AttachmentType {
    Region,
    RegionSequence,
    BoundingBox,
}

impl from_json::FromJson for AttachmentType {
    fn from_json(input: &serialize::json::Json) -> Result<AttachmentType, from_json::FromJsonError> {
        use from_json::FromJson;

        let string: String = try!(FromJson::from_json(input));

        match string.as_slice() {
            "region" => Ok(AttachmentType::Region),
            "regionsequence" => Ok(AttachmentType::RegionSequence),
            "boundingbox" => Ok(AttachmentType::BoundingBox),
            _ => Err(from_json::ExpectError("AttachmentType", input.clone()))
        }
    }
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct Event {
    pub name: String,
    #[from_json_name = "int"]
    pub int_: Option<int>,
    #[from_json_name = "float"]
    pub float_: Option<f64>,
    pub string: Option<String>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct Animation {
    pub bones: Option<HashMap<String, BoneTimeline>>,
    pub slots: Option<HashMap<String, SlotTimeline>>,
    pub events: Option<Vec<EventKeyframe>>,
    pub draworder: Option<Vec<DrawOrderTimeline>>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct BoneTimeline {
    pub translate: Option<Vec<BoneTranslateTimeline>>,
    pub rotate: Option<Vec<BoneRotateTimeline>>,
    pub scale: Option<Vec<BoneScaleTimeline>>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct BoneTranslateTimeline {
    pub time: f64,
    pub curve: Option<TimelineCurve>,
    pub x: Option<f64>,
    pub y: Option<f64>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct BoneRotateTimeline {
    pub time: f64,
    pub curve: Option<TimelineCurve>,
    pub angle: Option<f64>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct BoneScaleTimeline {
    pub time: f64,
    pub curve: Option<TimelineCurve>,
    pub x: Option<f64>,
    pub y: Option<f64>,
}

#[deriving(Show, Clone)]
pub enum TimelineCurve {
    CurveBezier(Vec<f64>),
    CurvePredefined(String),
}

impl from_json::FromJson for TimelineCurve {
    fn from_json(input: &serialize::json::Json) -> Result<TimelineCurve, from_json::FromJsonError> {
        use from_json::FromJson;

        if input.is_array() {
            Ok(TimelineCurve::CurveBezier(try!(FromJson::from_json(input))))
        } else {
            Ok(TimelineCurve::CurvePredefined(try!(FromJson::from_json(input))))
        }
    }
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct SlotTimeline {
    pub attachment: Option<Vec<SlotAttachmentTimeline>>,
    pub color: Option<Vec<SlotColorTimeline>>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct SlotAttachmentTimeline {
    pub time: f64,
    pub name: Option<String>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct SlotColorTimeline {
    pub time: f64,
    pub color: Option<String>,
    pub curve: Option<TimelineCurve>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct EventKeyframe {
    time: f64,
    name: String,
    #[from_json_name = "int"]
    int_: Option<int>,
    #[from_json_name = "float"]
    float_: Option<f64>,
    #[from_json_name = "string"]
    string_: Option<String>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct DrawOrderTimeline {
    time: f64,
    offsets: Option<Vec<DrawOrderTimelineOffset>>,
}

#[deriving(Show, Clone)]
#[from_json_struct]
pub struct DrawOrderTimelineOffset {
    slot: String,
    offset: int,
}
<|endoftext|>


<commit_before>#![cfg(not(syn_disable_nightly_tests))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]

extern crate rustc_ast;
extern crate rustc_errors;
extern crate rustc_expand;
extern crate rustc_parse as parse;
extern crate rustc_session;
extern crate rustc_span;

use crate::common::eq::SpanlessEq;
use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use rustc_ast::ast;
use rustc_errors::PResult;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::FilePathMapping;
use rustc_span::FileName;
use std::fs::File;
use std::io::Read;
use std::panic;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Instant;
use walkdir::{DirEntry, WalkDir};

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

#[test]
fn test_round_trip() {
    common::rayon_init();
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all round_trip tests");
    }

    let failed = AtomicUsize::new(0);

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            let mut file = File::open(path).unwrap();
            let mut content = String::new();
            file.read_to_string(&mut content).unwrap();

            let start = Instant::now();
            let (krate, elapsed) = match syn::parse_file(&content) {
                Ok(krate) => (krate, start.elapsed()),
                Err(msg) => {
                    errorf!("=== {}: syn failed to parse\n{:?}\n", path.display(), msg);
                    let prev_failed = failed.fetch_add(1, Ordering::SeqCst);
                    if prev_failed + 1 >= abort_after {
                        process::exit(1);
                    }
                    return;
                }
            };
            let back = quote!(#krate).to_string();
            let edition = repo::edition(path).parse().unwrap();

            let equal = panic::catch_unwind(|| {
                rustc_span::with_session_globals(edition, || {
                    let sess = ParseSess::new(FilePathMapping::empty());
                    let before = match librustc_parse(content, &sess) {
                        Ok(before) => before,
                        Err(mut diagnostic) => {
                            diagnostic.cancel();
                            if diagnostic
                                .message()
                                .starts_with("file not found for module")
                            {
                                errorf!("=== {}: ignore\n", path.display());
                            } else {
                                errorf!(
                                "=== {}: ignore - librustc failed to parse original content: {}\n",
                                path.display(),
                                diagnostic.message()
                            );
                            }
                            return true;
                        }
                    };
                    let after = match librustc_parse(back, &sess) {
                        Ok(after) => after,
                        Err(mut diagnostic) => {
                            errorf!("=== {}: librustc failed to parse", path.display());
                            diagnostic.emit();
                            return false;
                        }
                    };

                    if SpanlessEq::eq(&before, &after) {
                        errorf!(
                            "=== {}: pass in {}ms\n",
                            path.display(),
                            elapsed.as_secs() * 1000
                                + u64::from(elapsed.subsec_nanos()) / 1_000_000
                        );
                        true
                    } else {
                        errorf!(
                            "=== {}: FAIL\nbefore: {:#?}\nafter: {:#?}\n",
                            path.display(),
                            before,
                            after,
                        );
                        false
                    }
                })
            });
            match equal {
                Err(_) => errorf!("=== {}: ignoring librustc panic\n", path.display()),
                Ok(true) => {}
                Ok(false) => {
                    let prev_failed = failed.fetch_add(1, Ordering::SeqCst);
                    if prev_failed + 1 >= abort_after {
                        process::exit(1);
                    }
                }
            }
        });

    let failed = failed.load(Ordering::SeqCst);
    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn librustc_parse(content: String, sess: &ParseSess) -> PResult<ast::Crate> {
    let name = FileName::Custom("test_round_trip".to_string());
    parse::parse_crate_from_source_str(name, content, sess)
}
<commit_msg>Move SpanlessEq check outside of catch_unwind<commit_after>#![cfg(not(syn_disable_nightly_tests))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]

extern crate rustc_ast;
extern crate rustc_errors;
extern crate rustc_expand;
extern crate rustc_parse as parse;
extern crate rustc_session;
extern crate rustc_span;

use crate::common::eq::SpanlessEq;
use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use rustc_ast::ast;
use rustc_errors::PResult;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::FilePathMapping;
use rustc_span::FileName;
use std::fs::File;
use std::io::Read;
use std::panic;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Instant;
use walkdir::{DirEntry, WalkDir};

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

#[test]
fn test_round_trip() {
    common::rayon_init();
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all round_trip tests");
    }

    let failed = AtomicUsize::new(0);

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if path.is_dir() {
                return;
            }

            let mut file = File::open(path).unwrap();
            let mut content = String::new();
            file.read_to_string(&mut content).unwrap();

            let start = Instant::now();
            let (krate, elapsed) = match syn::parse_file(&content) {
                Ok(krate) => (krate, start.elapsed()),
                Err(msg) => {
                    errorf!("=== {}: syn failed to parse\n{:?}\n", path.display(), msg);
                    let prev_failed = failed.fetch_add(1, Ordering::SeqCst);
                    if prev_failed + 1 >= abort_after {
                        process::exit(1);
                    }
                    return;
                }
            };
            let back = quote!(#krate).to_string();
            let edition = repo::edition(path).parse().unwrap();

            rustc_span::with_session_globals(edition, || {
                let equal = match panic::catch_unwind(|| {
                    let sess = ParseSess::new(FilePathMapping::empty());
                    let before = match librustc_parse(content, &sess) {
                        Ok(before) => before,
                        Err(mut diagnostic) => {
                            diagnostic.cancel();
                            if diagnostic
                                .message()
                                .starts_with("file not found for module")
                            {
                                errorf!("=== {}: ignore\n", path.display());
                            } else {
                                errorf!(
                                    "=== {}: ignore - librustc failed to parse original content: {}\n",
                                    path.display(),
                                    diagnostic.message(),
                                );
                            }
                            return Err(true);
                        }
                    };
                    let after = match librustc_parse(back, &sess) {
                        Ok(after) => after,
                        Err(mut diagnostic) => {
                            errorf!("=== {}: librustc failed to parse", path.display());
                            diagnostic.emit();
                            return Err(false);
                        }
                    };
                    Ok((before, after))
                }) {
                    Err(_) => {
                        errorf!("=== {}: ignoring librustc panic\n", path.display());
                        true
                    }
                    Ok(Err(equal)) => equal,
                    Ok(Ok((before, after))) => if SpanlessEq::eq(&before, &after) {
                        errorf!(
                            "=== {}: pass in {}ms\n",
                            path.display(),
                            elapsed.as_secs() * 1000
                                + u64::from(elapsed.subsec_nanos()) / 1_000_000
                        );
                        true
                    } else {
                        errorf!(
                            "=== {}: FAIL\nbefore: {:#?}\nafter: {:#?}\n",
                            path.display(),
                            before,
                            after,
                        );
                        false
                    },
                };
                if !equal {
                    let prev_failed = failed.fetch_add(1, Ordering::SeqCst);
                    if prev_failed + 1 >= abort_after {
                        process::exit(1);
                    }
                }
            });
        });

    let failed = failed.load(Ordering::SeqCst);
    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn librustc_parse(content: String, sess: &ParseSess) -> PResult<ast::Crate> {
    let name = FileName::Custom("test_round_trip".to_string());
    parse::parse_crate_from_source_str(name, content, sess)
}
<|endoftext|>