<commit_before>//! Facilities for implementing chess engines.

pub mod time_manager;

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 search::*;
use self::time_manager::*;

const NAME: &'static str = "Alcibiades";
const AUTHOR: &'static str = "Evgeni Pandurski";
const VERSION: &'static str = "0.1";
const START_FEN: &'static str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 1";

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

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

    // Average number of analyzed nodes per second.
    pub nps: u64,
}

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

enum PlayWhen {
    TimeManagement(TimeManager), // 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.
    Never, // An infinite search.
}

struct Engine<S: SearchExecutor<ReportData = Vec<Variation>>> {
    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,

    // 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,

    // Tells the engine if it will be allowed to ponder. This option
    // is needed because the engine might change its time management
    // algorithm when pondering is allowed.
    pondering_is_allowed: bool,
}

impl<S: SearchExecutor<ReportData = Vec<Variation>>> UciEngine for Engine<S> {
    fn name() -> String {
        format!("{} {}", NAME, VERSION)
    }

    fn author() -> String {
        AUTHOR.to_string()
    }

    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),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ];
        options.extend(S::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> {
        let tt = Arc::new(S::HashTable::new(tt_size_mb));
        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: SystemTime::now(),
            status: SearchStatus { done: true, ..Default::default() },
            silent_since: SystemTime::now(),
            is_pondering: false,
            play_when: PlayWhen::Never,
            pondering_is_allowed: false,
        }
    }

    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                // TODO: Can we remove this?
                self.pondering_is_allowed = value == "true";
            }
            "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);
    }

    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();

        // TODO: What should we do with "mate"?
        let GoParams { mut searchmoves,
                       ponder,
                       wtime,
                       btime,
                       winc,
                       binc,
                       movestogo,
                       depth,
                       nodes,
                       movetime,
                       infinite,
                       .. } = params;

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

        // Start a new search.
        self.tt.new_search();
        self.started_at = SystemTime::now();
        self.status = SearchStatus { nps: self.status.nps, ..Default::default() };
        self.silent_since = SystemTime::now();
        self.is_pondering = ponder;
        self.play_when = if infinite {
            PlayWhen::Never
        } else if movetime.is_some() {
            PlayWhen::MoveTime(movetime.unwrap())
        } else if nodes.is_some() {
            PlayWhen::Nodes(nodes.unwrap())
        } else if depth.is_some() {
            PlayWhen::Depth(min(depth.unwrap(), DEPTH_MAX as u64) as Depth)
        } else {
            PlayWhen::TimeManagement(TimeManager::new(self.position.board().to_move,
                                                      self.pondering_is_allowed,
                                                      wtime,
                                                      btime,
                                                      winc,
                                                      binc,
                                                      movestogo))
        };
        self.searcher.start_search(SearchParams {
            search_id: 0,
            position: self.position.clone(),
            depth: DEPTH_MAX,
            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 done = self.status.done;

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

            // See if we must play now.
            if !done {
                let &SearchStatus { done, depth, searched_nodes, duration_millis, .. } =
                    &self.status;
                if !self.is_pondering &&
                   match self.play_when {
                    PlayWhen::TimeManagement(ref tm) => done || tm.must_play(),
                    PlayWhen::MoveTime(t) => done || duration_millis >= t,
                    PlayWhen::Nodes(n) => done || searched_nodes >= n,
                    PlayWhen::Depth(d) => done || depth >= d,
                    PlayWhen::Never => false,
                } {
                    self.stop();
                }
            }
        }

        self.queue.pop_front()
    }

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

impl<S: SearchExecutor<ReportData = Vec<Variation>>> Engine<S> {
    fn queue_progress_report(&mut self) {
        let SearchStatus { ref depth, ref searched_nodes, ref nps, .. } = self.status;
        self.queue.push_back(EngineReply::Info(vec![
            InfoItem { info_type: "depth".to_string(), data: format!("{}", depth) },
            InfoItem { info_type: "nodes".to_string(), data: format!("{}", searched_nodes) },
            InfoItem { info_type: "nps".to_string(), data: format!("{}", nps) },
        ]));
        self.silent_since = SystemTime::now();
    }

    fn queue_pv(&mut self, variations: &Vec<Variation>) {
        let SearchStatus { ref depth, ref searched_nodes, ref duration_millis, ref nps, .. } =
            self.status;
        for (i, &Variation { ref moves, value, bound }) in variations.iter().enumerate() {
            let bound_suffix = match bound {
                BOUND_EXACT => "",
                BOUND_UPPER => " upperbound",
                BOUND_LOWER => " lowerbound",
                _ => panic!("unexpected bound type"),
            };
            let mut moves_string = String::new();
            for m in moves {
                moves_string.push_str(&m.notation());
                moves_string.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: format!("cp {}{}", value, bound_suffix) },
                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!("{}", nps) },
                InfoItem { info_type: "pv".to_string(), data: moves_string },
            ]));
        }
        if !variations.is_empty() {
            self.silent_since = SystemTime::now();
        }
    }

    fn queue_best_move(&mut self) {
        let pv = extract_pv(self.tt.deref(), &self.position, 2);
        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()),
        });
        self.silent_since = SystemTime::now();
    }

    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>>) {
        // Update the search status.
        let duration = self.started_at.elapsed().unwrap();
        self.status.duration_millis = 1000 * duration.as_secs() +
                                      (duration.subsec_nanos() / 1000000) as u64;
        self.status.searched_nodes = report.searched_nodes;
        self.status.nps = 1000 * (self.status.nps + self.status.searched_nodes) /
                          (1000 + self.status.duration_millis);
        self.status.depth = report.depth;
        self.status.done = report.done;

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

        // Show the primary variations provided with the report (if any).
        self.queue_pv(&report.data);

        // If nothing has happened for a while, show a progress report.
        if self.silent_since.elapsed().unwrap().as_secs() > 10 {
            self.queue_progress_report();
        }
    }
}

/// 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_server<S: SearchExecutor<ReportData = Vec<Variation>>>() -> io::Result<()> {
    run_engine::<Engine<S>>()
}
<commit_msg>calculate nps move intelligently<commit_after>//! Facilities for implementing chess engines.

pub mod time_manager;

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 search::*;
use self::time_manager::*;

const NAME: &'static str = "Alcibiades";
const AUTHOR: &'static str = "Evgeni Pandurski";
const VERSION: &'static str = "0.1";
const START_FEN: &'static str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 1";

struct SearchStatus {
    pub done: bool,
    pub depth: Depth,
    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,
            searched_nodes: 0,
            duration_millis: 0,
        }
    }
}

enum PlayWhen {
    TimeManagement(TimeManager), // 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.
    Never, // An infinite search.
}

struct Engine<S: SearchExecutor<ReportData = Vec<Variation>>> {
    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,

    // Tells the engine if it will be allowed to ponder. This option
    // is needed because the engine might change its time management
    // algorithm when pondering is allowed.
    pondering_is_allowed: bool,
}

impl<S: SearchExecutor<ReportData = Vec<Variation>>> UciEngine for Engine<S> {
    fn name() -> String {
        format!("{} {}", NAME, VERSION)
    }

    fn author() -> String {
        AUTHOR.to_string()
    }

    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),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ];
        options.extend(S::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> {
        let tt = Arc::new(S::HashTable::new(tt_size_mb));
        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: SystemTime::now(),
            status: SearchStatus { done: true, ..Default::default() },
            nps_stats: (0, 0, 0),
            silent_since: SystemTime::now(),
            is_pondering: false,
            play_when: PlayWhen::Never,
            pondering_is_allowed: false,
        }
    }

    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                // TODO: Can we remove this?
                self.pondering_is_allowed = value == "true";
            }
            "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);
    }

    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();

        // TODO: What should we do with "mate"?
        let GoParams { mut searchmoves,
                       ponder,
                       wtime,
                       btime,
                       winc,
                       binc,
                       movestogo,
                       depth,
                       nodes,
                       movetime,
                       infinite,
                       .. } = params;

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

        // Start a new search.
        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 = SystemTime::now();
        self.is_pondering = ponder;
        self.play_when = if infinite {
            PlayWhen::Never
        } else if movetime.is_some() {
            PlayWhen::MoveTime(movetime.unwrap())
        } else if nodes.is_some() {
            PlayWhen::Nodes(nodes.unwrap())
        } else if depth.is_some() {
            PlayWhen::Depth(min(depth.unwrap(), DEPTH_MAX as u64) as Depth)
        } else {
            PlayWhen::TimeManagement(TimeManager::new(self.position.board().to_move,
                                                      self.pondering_is_allowed,
                                                      wtime,
                                                      btime,
                                                      winc,
                                                      binc,
                                                      movestogo))
        };
        self.searcher.start_search(SearchParams {
            search_id: 0,
            position: self.position.clone(),
            depth: DEPTH_MAX,
            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 done = self.status.done;

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

            // See if we must play now.
            if !done {
                let &SearchStatus { done, depth, searched_nodes, duration_millis, .. } =
                    &self.status;
                if !self.is_pondering &&
                   match self.play_when {
                    PlayWhen::TimeManagement(ref tm) => done || tm.must_play(),
                    PlayWhen::MoveTime(t) => done || duration_millis >= t,
                    PlayWhen::Nodes(n) => done || searched_nodes >= n,
                    PlayWhen::Depth(d) => done || depth >= d,
                    PlayWhen::Never => false,
                } {
                    self.stop();
                }
            }
        }

        self.queue.pop_front()
    }

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

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

    fn queue_pv(&mut self, variations: &Vec<Variation>) {
        let SearchStatus { ref depth, ref searched_nodes, ref duration_millis, .. } = self.status;
        for (i, &Variation { ref moves, value, bound }) in variations.iter().enumerate() {
            let bound_suffix = match bound {
                BOUND_EXACT => "",
                BOUND_UPPER => " upperbound",
                BOUND_LOWER => " lowerbound",
                _ => panic!("unexpected bound type"),
            };
            let mut moves_string = String::new();
            for m in moves {
                moves_string.push_str(&m.notation());
                moves_string.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: format!("cp {}{}", value, bound_suffix) },
                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: moves_string },
            ]));
        }
        if !variations.is_empty() {
            self.silent_since = SystemTime::now();
        }
    }

    fn queue_best_move(&mut self) {
        let pv = extract_pv(self.tt.deref(), &self.position, 2);
        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()),
        });
        self.silent_since = SystemTime::now();
    }

    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 d = self.started_at.elapsed().unwrap();
        let duration_millis = 1000 * d.as_secs() + (d.subsec_nanos() / 1_000_000) as u64;
        self.status = SearchStatus {
            done: report.done,
            depth: report.depth,
            searched_nodes: report.searched_nodes,
            duration_millis: duration_millis,
        };

        // Update `self.nps_stats` each 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_status(&report);
        }

        // Show the primary variations provided with the report (if any).
        self.queue_pv(&report.data);

        // If nothing has happened for a while, show a progress report.
        if self.silent_since.elapsed().unwrap().as_secs() > 10 {
            self.queue_progress_report();
        }
    }
}

/// 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_server<S: SearchExecutor<ReportData = Vec<Variation>>>() -> io::Result<()> {
    run_engine::<Engine<S>>()
}
<|endoftext|>


<commit_before>//! The forwarder module shall act as wrapper for the ffi mangled lib.rs
//! calls, which shall be very thin and spare there, but extensive here
//! to prepare clean calls to adbfflutter.
use crate::{
    common::paths::SearchPath,
    ctrl::{ForwardNetMsg, UiUpdateMsg},
    data::{collection::Collection, ipc::IPC},
    net::subs::peer_representation,
    shared,
};
use async_std::task;
use crossbeam::{sync::WaitGroup, unbounded};
use std::{
    sync::{mpsc::channel, Arc, Mutex},
    thread,
};

/// just return the number of audio files found for now
pub fn ffi_file_count_good(input_path: Vec<String>) -> u32 {
    // prepare data
    let cleaned_paths = SearchPath::new(&input_path);
    let search_path = Arc::new(Mutex::new(cleaned_paths));

    let (tx, _rx) = channel::<UiUpdateMsg>();
    let synced_to_ui_messages = Arc::new(Mutex::new(tx.clone()));
    let has_ui = false;

    // set up data
    let collection_protected = Arc::new(Mutex::new(Collection::new()));
    let output_data_return_handle = shared::collection_search(
        collection_protected,
        search_path,
        synced_to_ui_messages,
        has_ui,
    );

    // scope and block trickery for lifetime and mutability
    output_data_return_handle.nr_found_songs
}

/// return the peer hash for testing yet
pub async fn ffi_new_peer() -> u64 {
    // mock input parameters
    let dummy_wait_net_thread = WaitGroup::new();
    let (ui_sender, reactor) = channel::<UiUpdateMsg>();
    let (_, dummy_ipc_receive) = unbounded::<IPC>();

    // todo: make it a lazy static as RUNTIME, to also hold the same IP, otherwise it will
    //       always change its IP!
    let single_shot_net_thread = thread::Builder::new()
        .name("app_net".into())
        .spawn(move || {
            task::block_on(async move {
                let _ =
                    shared::net_search(dummy_wait_net_thread, Some(ui_sender), dummy_ipc_receive)
                        .await;
            });
        })
        .unwrap();

    // very interesting, the compiler is awesome!!
    let out;

    // loop over fixme: (very cheap version here, that could be done more elegantly) with poll
    loop {
        if let Ok(reaction) = reactor.try_recv() {
            match reaction {
                UiUpdateMsg::CollectionUpdate(_, _) => {}
                UiUpdateMsg::NetUpdate(net_message) => {
                    match net_message {
                        ForwardNetMsg::Add(peer) => {
                            // yet only id is interesting
                            out = peer_representation::peer_to_hash(&peer.id);
                            break;
                        }
                        ForwardNetMsg::Delete(_peer_id) => {}
                        ForwardNetMsg::Stats(_) => {}
                    }
                }
                UiUpdateMsg::PeerSearchFinished(_peer_id, _data) => {}
                UiUpdateMsg::StopUI => {}
            }
        }
    }
    // kill this big thread / fixme: very inefficent yet
    drop(single_shot_net_thread);
    out
}
<commit_msg>[version] trying release for android signing, macos<commit_after>//! The forwarder module shall act as wrapper for the ffi mangled lib.rs
//! calls, which shall be very thin and spare there, but extensive here
//! to prepare clean calls to adbfflutter.
use crate::{
    common::paths::SearchPath,
    ctrl::{ForwardNetMsg, UiUpdateMsg},
    data::{collection::Collection, ipc::IPC},
    net::subs::peer_representation,
    shared,
};
use async_std::task;
use crossbeam::{sync::WaitGroup, unbounded};
use std::{
    sync::{mpsc::channel, Arc, Mutex},
    thread,
};

/// just return the number of audio files found for now
pub fn ffi_file_count_good(input_path: Vec<String>) -> u32 {
    // prepare data
    let cleaned_paths = SearchPath::new(&input_path);
    let search_path = Arc::new(Mutex::new(cleaned_paths));

    let (tx, _rx) = channel::<UiUpdateMsg>();
    let synced_to_ui_messages = Arc::new(Mutex::new(tx.clone()));
    let has_ui = false;

    // set up data and run search
    let collection_protected = Arc::new(Mutex::new(Collection::new()));
    let output_data_return_handle = shared::collection_search(
        collection_protected,
        search_path,
        synced_to_ui_messages,
        has_ui,
    );

    // scope and block trickery for lifetime and mutability
    output_data_return_handle.nr_found_songs
}

/// return the peer hash for testing yet
pub async fn ffi_new_peer() -> u64 {
    // mock input parameters
    let dummy_wait_net_thread = WaitGroup::new();
    let (ui_sender, reactor) = channel::<UiUpdateMsg>();
    let (_, dummy_ipc_receive) = unbounded::<IPC>();

    // todo: make it a lazy static as RUNTIME, to also hold the same IP, otherwise it will
    //       always change its IP!
    let single_shot_net_thread = thread::Builder::new()
        .name("app_net".into())
        .spawn(move || {
            task::block_on(async move {
                let _ =
                    shared::net_search(dummy_wait_net_thread, Some(ui_sender), dummy_ipc_receive)
                        .await;
            });
        })
        .unwrap();

    // very interesting, the compiler is awesome!!
    let out;

    // loop over fixme: (very cheap version here, that could be done more elegantly) with poll
    loop {
        if let Ok(reaction) = reactor.try_recv() {
            match reaction {
                UiUpdateMsg::CollectionUpdate(_, _) => {}
                UiUpdateMsg::NetUpdate(net_message) => {
                    match net_message {
                        ForwardNetMsg::Add(peer) => {
                            // yet only id is interesting
                            out = peer_representation::peer_to_hash(&peer.id);
                            break;
                        }
                        ForwardNetMsg::Delete(_peer_id) => {}
                        ForwardNetMsg::Stats(_) => {}
                    }
                }
                UiUpdateMsg::PeerSearchFinished(_peer_id, _data) => {}
                UiUpdateMsg::StopUI => {}
            }
        }
    }
    // kill this big thread / fixme: very inefficent yet
    drop(single_shot_net_thread);
    out
}
<|endoftext|>


<commit_before>pub mod window {
    use cocoa::base::id;
    use cocoa::foundation::NSUInteger;
    use cocoa::appkit::NSWindow;
    use core_graphics::geometry::{CGRect, CGPoint, CGSize};
    use objc::runtime::{BOOL, Class, YES};
    use raw::{FromRaw, FromRawError, IntoRaw};
    use std::error::Error;
    use std::fmt;
    use std::marker;
    use std::ops::{Deref, DerefMut};
    use sys::{MTLClearColor, MTLPixelFormat};
    use winit;
    use winit::os::macos::WindowExt;
    use {ClearColor, Device, PixelFormat, RenderPassDescriptor, Texture};

    pub use winit::{
        CursorState,
        Event,
        MonitorId,
        MouseCursor,
        PollEventsIterator,
        WaitEventsIterator,
        ElementState,
        MouseButton,
        MouseScrollDelta,
        Touch,
        TouchPhase,
        ScanCode,
        VirtualKeyCode
    };

    pub struct WindowBuilder {
        window: winit::WindowBuilder,
        device: Device
    }

    #[derive(Debug)]
    pub enum CreationError {
        ViewCreation(ViewError),
        Winit(winit::CreationError)
    }

    impl fmt::Display for CreationError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.description())
        }
    }

    impl Error for CreationError {
        fn description(&self) -> &str {
            match *self {
                CreationError::ViewCreation(ref e) => e.description(),
                CreationError::Winit(ref e) => e.description()
            }
        }

        fn cause(&self) -> Option<&Error> {
            match *self {
                CreationError::ViewCreation(ref e) => Some(e),
                CreationError::Winit(ref e) => Some(e)
            }
        }
    }

    impl From<winit::CreationError> for CreationError {
        fn from(error: winit::CreationError) -> Self {
            CreationError::Winit(error)
        }
    }

    impl From<ViewError> for CreationError {
        fn from(error: ViewError) -> Self {
            CreationError::ViewCreation(error)
        }
    }

    impl WindowBuilder {
        /// Initializes a new `WindowBuilder` with default values.
        #[inline]
        pub fn new(device: Device) -> Self {
            WindowBuilder {
                window: winit::WindowBuilder::new(),
                device: device
            }
        }

        /// Requests the window to be of specific dimensions.
        ///
        /// Width and height are in pixels.
        #[inline]
        pub fn with_dimensions(self, width: u32, height: u32) -> WindowBuilder {
            WindowBuilder {window: self.window.with_dimensions(width, height), ..self}
        }

        /// Sets a minimum dimension size for the window
        ///
        /// Width and height are in pixels.
        #[inline]
        pub fn with_min_dimensions(self, width: u32, height: u32) -> WindowBuilder {
            WindowBuilder {window: self.window.with_min_dimensions(width, height), ..self}
        }

        /// Sets a maximum dimension size for the window
        ///
        /// Width and height are in pixels.
        #[inline]
        pub fn with_max_dimensions(self, width: u32, height: u32) -> WindowBuilder {
            WindowBuilder {window: self.window.with_max_dimensions(width, height), ..self}
        }

        /// Requests a specific title for the window.
        #[inline]
        pub fn with_title(self, title: String) -> WindowBuilder {
            WindowBuilder {window: self.window.with_title(title), ..self}
        }

        /// Requests fullscreen mode.
        ///
        /// If you don't specify dimensions for the window, it will match the monitor's.
        #[inline]
        pub fn with_fullscreen(self, monitor: MonitorId) -> WindowBuilder {
            WindowBuilder {window: self.window.with_fullscreen(monitor), ..self}
        }

        /// Sets whether the window will be initially hidden or visible.
        #[inline]
        pub fn with_visibility(self, visible: bool) -> WindowBuilder {
            WindowBuilder {window: self.window.with_visibility(visible), ..self}
        }

        /// Sets whether the background of the window should be transparent.
        #[inline]
        pub fn with_transparency(self, transparent: bool) -> WindowBuilder {
            WindowBuilder {window: self.window.with_transparency(transparent), ..self}
        }

        /// Sets whether the window should have a border, a title bar, etc.
        #[inline]
        pub fn with_decorations(self, decorations: bool) -> WindowBuilder {
            WindowBuilder {window: self.window.with_decorations(decorations), ..self}
        }

        /// Enables multitouch
        #[inline]
        pub fn with_multitouch(self) -> WindowBuilder {
            WindowBuilder {window: self.window.with_multitouch(), ..self}
        }

        /// Builds the window.
        ///
        /// Error should be very rare and only occur in case of permission denied, incompatible system,
        /// out of memory, etc.
        pub fn build(self) -> Result<Window, CreationError> {
            let window = try!(self.window.build());
            let view = try!(View::new(&window, self.device));

            unsafe {
                let native_window: id = window.get_nswindow() as id;
                native_window.setContentView_(view.0);
            }

            Ok(Window {
                window: window,
                view: view
            })
        }

        /// Builds the window.
        ///
        /// The context is build in a *strict* way. That means that if the backend couldn't give
        /// you what you requested, an `Err` will be returned.
        #[inline]
        pub fn build_strict(self) -> Result<Window, CreationError> {
            self.build()
        }
    }

    pub struct Window {
        window: winit::Window,
        pub view: View
    }

    impl Window {
        pub fn poll_events(&self) -> PollEventsIterator {
            self.window.poll_events()
        }

        pub fn wait_events(&self) -> WaitEventsIterator {
            self.window.wait_events()
        }

        pub fn window(&self) -> Ref<winit::Window> {
            Ref(&self.window)
        }
    }

    pub struct View(id);
    impl_from_into_raw!(View, of class "MTKView");

    impl View {
        fn new(window: &winit::Window, device: Device) -> Result<Self, ViewError> {
            let window_origin = {
                let (x, y) = try!(window.get_position().ok_or(ViewError::no_window()));
                CGPoint { x: x as f64, y: y as f64 }
            };

            let window_size = {
                let (w, h) = try!(window.get_inner_size().ok_or(ViewError::no_window()));
                CGSize { width: w as f64, height: h as f64 }
            };

            let view_frame = CGRect { origin: window_origin, size: window_size };

            let view_object: id = unsafe {
                // Dummy function to ensure that we link against MetalKit
                #[allow(dead_code)]
                #[link(name = "MetalKit", kind = "framework")]
                extern "C" {
                    fn MTKModelIOVertexDescriptorFromMetal(metalDescriptor: id) -> id;
                }

                let view_class = Class::get("MTKView").expect("Could not find MTKView class");
                let view: id = msg_send![view_class, alloc];
                msg_send![view, initWithFrame:view_frame
                                       device:device.into_raw()]
            };

            View::from_raw(view_object).map_err(From::from)
        }

        pub fn device<'a>(&self) -> Option<PhantomRef<'a, Device>> {
            let device = unsafe {
                Device::from_raw(msg_send![self.0, device])
            };
            device.ok().map(|d| PhantomRef(d, marker::PhantomData))
        }

        pub fn device_mut<'a>(&mut self) -> Option<PhantomRefMut<'a, Device>> {
            let device = unsafe {
                Device::from_raw(msg_send![self.0, device])
            };
            device.ok().map(|d| PhantomRefMut(d, marker::PhantomData))
        }

        pub fn clear_color(&self) -> ClearColor {
            let color: MTLClearColor = unsafe {
                msg_send![self.0, clearColor]
            };
            color.into()
        }

        pub fn set_clear_color<C: Into<MTLClearColor>>(&mut self, clear_color: C) {
            unsafe { msg_send![self.0, setClearColor:clear_color.into()] }
        }

        pub fn clear_depth(&self) -> f64 {
            unsafe { msg_send![self.0, clearDepth] }
        }

        pub fn set_clear_depth(&mut self, clear_depth: f64) {
            unsafe { msg_send![self.0, setClearDepth:clear_depth] }
        }

        pub fn clear_stencil(&self) -> u32 {
            unsafe { msg_send![self.0, clearStencil] }
        }

        pub fn set_clear_stencil(&mut self, clear_stencil: u32) {
            unsafe { msg_send![self.0, setClearStencil:clear_stencil] }
        }

        pub fn color_pixel_format(&self) -> PixelFormat {
            let pixel_format: MTLPixelFormat = unsafe {
                msg_send![self.0, colorPixelFormat]
            };
            pixel_format.into()
        }

        pub fn set_color_pixel_format<P: Into<MTLPixelFormat>>(&mut self, color_pixel_format: P) {
            unsafe { msg_send![self.0, setColorPixelFormat:color_pixel_format.into()] }
        }

        pub fn depth_stencil_pixel_format(&self) -> PixelFormat {
            let pixel_format: MTLPixelFormat = unsafe { msg_send![self.0, depthStencilPixelFormat] };
            pixel_format.into()
        }

        pub fn set_depth_stencil_pixel_format<P: Into<MTLPixelFormat>>(&mut self, depth_stencil_pixel_format: P) {
            unsafe { msg_send![self.0, setDepthStencilPixelFormat:depth_stencil_pixel_format.into()] }
        }

        pub fn sample_count(&self) -> usize {
            let sample_count: NSUInteger = unsafe {
                msg_send![self.0, sampleCount]
            };
            sample_count as usize
        }

        pub fn set_sample_count(&mut self, sample_count: usize) {
            let sample_count = sample_count as NSUInteger;
            unsafe { msg_send![self.0, setSampleCount:sample_count] }
        }

        pub fn current_render_pass_descriptor(&self) -> Option<PhantomRef<RenderPassDescriptor>> {
            let descriptor: id = unsafe { msg_send![self.0, currentRenderPassDescriptor] };
            FromRaw::from_raw(descriptor).ok().map(|d| PhantomRef(d, marker::PhantomData))
        }

        pub fn current_depth_stencil_texture(&self) -> Option<PhantomRef<Texture>> {
            let texture: id = unsafe { msg_send![self.0, depthStencilTexture] };
            FromRaw::from_raw(texture).ok().map(|t| PhantomRef(t, marker::PhantomData))
        }

        pub fn multisample_color_texture(&self) -> Option<PhantomRef<Texture>> {
            let texture: id = unsafe { msg_send![self.0, multisampleColorTexture] };
            FromRaw::from_raw(texture).ok().map(|t| PhantomRef(t, marker::PhantomData))
        }

        pub fn preferred_frames_per_second(&self) -> usize {
            let fps: NSUInteger = unsafe { msg_send![self.0, sampleCount] };
            fps as usize
        }

        pub fn set_preferred_frames_per_second(&self, preferred_fps: usize) {
            let preferred_fps = preferred_fps as NSUInteger;
            unsafe { msg_send![self.0, setPreferredFramesPerSecond:preferred_fps] }
        }

        pub fn is_paused(&self) -> bool {
            let is_paused: BOOL = unsafe { msg_send![self.0, isPaused] };
            is_paused == YES
        }

        pub fn draw(&self) {
            unsafe { msg_send![self.0, draw] }
        }
    }

    #[derive(Clone, Debug)]
    pub struct ViewError(ViewErrorInner);

    #[derive(Clone, Debug)]
    enum ViewErrorInner {
        NoWindow,
        CreateError(FromRawError)
    }

    impl ViewError {
        fn no_window() -> Self {
            ViewError(ViewErrorInner::NoWindow)
        }
    }

    impl fmt::Display for ViewError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.description())
        }
    }

    impl Error for ViewError {
        fn description(&self) -> &str {
            match self.0 {
                ViewErrorInner::NoWindow => "The native window no longer exists",
                ViewErrorInner::CreateError(_) => "There was an issue creating the view",
            }
        }

        fn cause(&self) -> Option<&Error> {
            if let ViewErrorInner::CreateError(ref e) = self.0 {
                Some(e)
            } else {
                None
            }
        }
    }

    impl From<FromRawError> for ViewError {
        fn from(error: FromRawError) -> Self {
            ViewError(ViewErrorInner::CreateError(error))
        }
    }

    pub struct Ref<'a, T: 'a>(&'a T);

    impl<'a, T> Deref for Ref<'a, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            self.0
        }
    }

    pub struct PhantomRef<'a, T: 'a>(T, marker::PhantomData<&'a ()>);

    impl<'a, T> Deref for PhantomRef<'a, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    pub struct PhantomRefMut<'a, T: 'a>(T, marker::PhantomData<&'a mut ()>);

    impl<'a, T> Deref for PhantomRefMut<'a, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    impl<'a, T> DerefMut for PhantomRefMut<'a, T> {
        fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
            &mut self.0
        }
    }
}
<commit_msg>Add a method to set the device of a view<commit_after>pub mod window {
    use cocoa::base::id;
    use cocoa::foundation::NSUInteger;
    use cocoa::appkit::NSWindow;
    use core_graphics::geometry::{CGRect, CGPoint, CGSize};
    use objc::runtime::{BOOL, Class, YES};
    use raw::{FromRaw, FromRawError, IntoRaw};
    use std::error::Error;
    use std::fmt;
    use std::marker;
    use std::ops::{Deref, DerefMut};
    use sys::{MTLClearColor, MTLPixelFormat};
    use winit;
    use winit::os::macos::WindowExt;
    use {ClearColor, Device, PixelFormat, RenderPassDescriptor, Texture};

    pub use winit::{
        CursorState,
        Event,
        MonitorId,
        MouseCursor,
        PollEventsIterator,
        WaitEventsIterator,
        ElementState,
        MouseButton,
        MouseScrollDelta,
        Touch,
        TouchPhase,
        ScanCode,
        VirtualKeyCode
    };

    pub struct WindowBuilder {
        window: winit::WindowBuilder,
        device: Device
    }

    #[derive(Debug)]
    pub enum CreationError {
        ViewCreation(ViewError),
        Winit(winit::CreationError)
    }

    impl fmt::Display for CreationError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.description())
        }
    }

    impl Error for CreationError {
        fn description(&self) -> &str {
            match *self {
                CreationError::ViewCreation(ref e) => e.description(),
                CreationError::Winit(ref e) => e.description()
            }
        }

        fn cause(&self) -> Option<&Error> {
            match *self {
                CreationError::ViewCreation(ref e) => Some(e),
                CreationError::Winit(ref e) => Some(e)
            }
        }
    }

    impl From<winit::CreationError> for CreationError {
        fn from(error: winit::CreationError) -> Self {
            CreationError::Winit(error)
        }
    }

    impl From<ViewError> for CreationError {
        fn from(error: ViewError) -> Self {
            CreationError::ViewCreation(error)
        }
    }

    impl WindowBuilder {
        /// Initializes a new `WindowBuilder` with default values.
        #[inline]
        pub fn new(device: Device) -> Self {
            WindowBuilder {
                window: winit::WindowBuilder::new(),
                device: device
            }
        }

        /// Requests the window to be of specific dimensions.
        ///
        /// Width and height are in pixels.
        #[inline]
        pub fn with_dimensions(self, width: u32, height: u32) -> WindowBuilder {
            WindowBuilder {window: self.window.with_dimensions(width, height), ..self}
        }

        /// Sets a minimum dimension size for the window
        ///
        /// Width and height are in pixels.
        #[inline]
        pub fn with_min_dimensions(self, width: u32, height: u32) -> WindowBuilder {
            WindowBuilder {window: self.window.with_min_dimensions(width, height), ..self}
        }

        /// Sets a maximum dimension size for the window
        ///
        /// Width and height are in pixels.
        #[inline]
        pub fn with_max_dimensions(self, width: u32, height: u32) -> WindowBuilder {
            WindowBuilder {window: self.window.with_max_dimensions(width, height), ..self}
        }

        /// Requests a specific title for the window.
        #[inline]
        pub fn with_title(self, title: String) -> WindowBuilder {
            WindowBuilder {window: self.window.with_title(title), ..self}
        }

        /// Requests fullscreen mode.
        ///
        /// If you don't specify dimensions for the window, it will match the monitor's.
        #[inline]
        pub fn with_fullscreen(self, monitor: MonitorId) -> WindowBuilder {
            WindowBuilder {window: self.window.with_fullscreen(monitor), ..self}
        }

        /// Sets whether the window will be initially hidden or visible.
        #[inline]
        pub fn with_visibility(self, visible: bool) -> WindowBuilder {
            WindowBuilder {window: self.window.with_visibility(visible), ..self}
        }

        /// Sets whether the background of the window should be transparent.
        #[inline]
        pub fn with_transparency(self, transparent: bool) -> WindowBuilder {
            WindowBuilder {window: self.window.with_transparency(transparent), ..self}
        }

        /// Sets whether the window should have a border, a title bar, etc.
        #[inline]
        pub fn with_decorations(self, decorations: bool) -> WindowBuilder {
            WindowBuilder {window: self.window.with_decorations(decorations), ..self}
        }

        /// Enables multitouch
        #[inline]
        pub fn with_multitouch(self) -> WindowBuilder {
            WindowBuilder {window: self.window.with_multitouch(), ..self}
        }

        /// Builds the window.
        ///
        /// Error should be very rare and only occur in case of permission denied, incompatible system,
        /// out of memory, etc.
        pub fn build(self) -> Result<Window, CreationError> {
            let window = try!(self.window.build());
            let view = try!(View::new(&window, self.device));

            unsafe {
                let native_window: id = window.get_nswindow() as id;
                native_window.setContentView_(view.0);
            }

            Ok(Window {
                window: window,
                view: view
            })
        }

        /// Builds the window.
        ///
        /// The context is build in a *strict* way. That means that if the backend couldn't give
        /// you what you requested, an `Err` will be returned.
        #[inline]
        pub fn build_strict(self) -> Result<Window, CreationError> {
            self.build()
        }
    }

    pub struct Window {
        window: winit::Window,
        pub view: View
    }

    impl Window {
        pub fn poll_events(&self) -> PollEventsIterator {
            self.window.poll_events()
        }

        pub fn wait_events(&self) -> WaitEventsIterator {
            self.window.wait_events()
        }

        pub fn window(&self) -> Ref<winit::Window> {
            Ref(&self.window)
        }
    }

    pub struct View(id);
    impl_from_into_raw!(View, of class "MTKView");

    impl View {
        fn new(window: &winit::Window, device: Device) -> Result<Self, ViewError> {
            let window_origin = {
                let (x, y) = try!(window.get_position().ok_or(ViewError::no_window()));
                CGPoint { x: x as f64, y: y as f64 }
            };

            let window_size = {
                let (w, h) = try!(window.get_inner_size().ok_or(ViewError::no_window()));
                CGSize { width: w as f64, height: h as f64 }
            };

            let view_frame = CGRect { origin: window_origin, size: window_size };

            let view_object: id = unsafe {
                // Dummy function to ensure that we link against MetalKit
                #[allow(dead_code)]
                #[link(name = "MetalKit", kind = "framework")]
                extern "C" {
                    fn MTKModelIOVertexDescriptorFromMetal(metalDescriptor: id) -> id;
                }

                let view_class = Class::get("MTKView").expect("Could not find MTKView class");
                let view: id = msg_send![view_class, alloc];
                msg_send![view, initWithFrame:view_frame
                                       device:device.into_raw()]
            };

            View::from_raw(view_object).map_err(From::from)
        }

        pub fn device<'a>(&self) -> Option<PhantomRef<'a, Device>> {
            let device = unsafe {
                Device::from_raw(msg_send![self.0, device])
            };
            device.ok().map(|d| PhantomRef(d, marker::PhantomData))
        }

        pub fn device_mut<'a>(&mut self) -> Option<PhantomRefMut<'a, Device>> {
            let device = unsafe {
                Device::from_raw(msg_send![self.0, device])
            };
            device.ok().map(|d| PhantomRefMut(d, marker::PhantomData))
        }

        pub fn set_device(&mut self, device: Device) {
            unsafe { msg_send![self.0, setDevice:device] }
        }

        pub fn clear_color(&self) -> ClearColor {
            let color: MTLClearColor = unsafe {
                msg_send![self.0, clearColor]
            };
            color.into()
        }

        pub fn set_clear_color<C: Into<MTLClearColor>>(&mut self, clear_color: C) {
            unsafe { msg_send![self.0, setClearColor:clear_color.into()] }
        }

        pub fn clear_depth(&self) -> f64 {
            unsafe { msg_send![self.0, clearDepth] }
        }

        pub fn set_clear_depth(&mut self, clear_depth: f64) {
            unsafe { msg_send![self.0, setClearDepth:clear_depth] }
        }

        pub fn clear_stencil(&self) -> u32 {
            unsafe { msg_send![self.0, clearStencil] }
        }

        pub fn set_clear_stencil(&mut self, clear_stencil: u32) {
            unsafe { msg_send![self.0, setClearStencil:clear_stencil] }
        }

        pub fn color_pixel_format(&self) -> PixelFormat {
            let pixel_format: MTLPixelFormat = unsafe {
                msg_send![self.0, colorPixelFormat]
            };
            pixel_format.into()
        }

        pub fn set_color_pixel_format<P: Into<MTLPixelFormat>>(&mut self, color_pixel_format: P) {
            unsafe { msg_send![self.0, setColorPixelFormat:color_pixel_format.into()] }
        }

        pub fn depth_stencil_pixel_format(&self) -> PixelFormat {
            let pixel_format: MTLPixelFormat = unsafe { msg_send![self.0, depthStencilPixelFormat] };
            pixel_format.into()
        }

        pub fn set_depth_stencil_pixel_format<P: Into<MTLPixelFormat>>(&mut self, depth_stencil_pixel_format: P) {
            unsafe { msg_send![self.0, setDepthStencilPixelFormat:depth_stencil_pixel_format.into()] }
        }

        pub fn sample_count(&self) -> usize {
            let sample_count: NSUInteger = unsafe {
                msg_send![self.0, sampleCount]
            };
            sample_count as usize
        }

        pub fn set_sample_count(&mut self, sample_count: usize) {
            let sample_count = sample_count as NSUInteger;
            unsafe { msg_send![self.0, setSampleCount:sample_count] }
        }

        pub fn current_render_pass_descriptor(&self) -> Option<PhantomRef<RenderPassDescriptor>> {
            let descriptor: id = unsafe { msg_send![self.0, currentRenderPassDescriptor] };
            FromRaw::from_raw(descriptor).ok().map(|d| PhantomRef(d, marker::PhantomData))
        }

        pub fn current_depth_stencil_texture(&self) -> Option<PhantomRef<Texture>> {
            let texture: id = unsafe { msg_send![self.0, depthStencilTexture] };
            FromRaw::from_raw(texture).ok().map(|t| PhantomRef(t, marker::PhantomData))
        }

        pub fn multisample_color_texture(&self) -> Option<PhantomRef<Texture>> {
            let texture: id = unsafe { msg_send![self.0, multisampleColorTexture] };
            FromRaw::from_raw(texture).ok().map(|t| PhantomRef(t, marker::PhantomData))
        }

        pub fn preferred_frames_per_second(&self) -> usize {
            let fps: NSUInteger = unsafe { msg_send![self.0, sampleCount] };
            fps as usize
        }

        pub fn set_preferred_frames_per_second(&self, preferred_fps: usize) {
            let preferred_fps = preferred_fps as NSUInteger;
            unsafe { msg_send![self.0, setPreferredFramesPerSecond:preferred_fps] }
        }

        pub fn is_paused(&self) -> bool {
            let is_paused: BOOL = unsafe { msg_send![self.0, isPaused] };
            is_paused == YES
        }

        pub fn draw(&self) {
            unsafe { msg_send![self.0, draw] }
        }
    }

    #[derive(Clone, Debug)]
    pub struct ViewError(ViewErrorInner);

    #[derive(Clone, Debug)]
    enum ViewErrorInner {
        NoWindow,
        CreateError(FromRawError)
    }

    impl ViewError {
        fn no_window() -> Self {
            ViewError(ViewErrorInner::NoWindow)
        }
    }

    impl fmt::Display for ViewError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.description())
        }
    }

    impl Error for ViewError {
        fn description(&self) -> &str {
            match self.0 {
                ViewErrorInner::NoWindow => "The native window no longer exists",
                ViewErrorInner::CreateError(_) => "There was an issue creating the view",
            }
        }

        fn cause(&self) -> Option<&Error> {
            if let ViewErrorInner::CreateError(ref e) = self.0 {
                Some(e)
            } else {
                None
            }
        }
    }

    impl From<FromRawError> for ViewError {
        fn from(error: FromRawError) -> Self {
            ViewError(ViewErrorInner::CreateError(error))
        }
    }

    pub struct Ref<'a, T: 'a>(&'a T);

    impl<'a, T> Deref for Ref<'a, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            self.0
        }
    }

    pub struct PhantomRef<'a, T: 'a>(T, marker::PhantomData<&'a ()>);

    impl<'a, T> Deref for PhantomRef<'a, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    pub struct PhantomRefMut<'a, T: 'a>(T, marker::PhantomData<&'a mut ()>);

    impl<'a, T> Deref for PhantomRefMut<'a, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    impl<'a, T> DerefMut for PhantomRefMut<'a, T> {
        fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
            &mut self.0
        }
    }
}
<|endoftext|>


<commit_before>//! The types for moves and plies.

use std::str::FromStr;
use std::fmt;
use std::num::SignedInt;

use super::piece::{self, Piece, Queen, Bishop, Knight, Rook, King, Pawn};
use super::square::{Square, File};
use super::castle::{Side, Kingside, Queenside};
use super::pos::Position;

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Move {
    from: Square,
    to: Square,
	capture_normal: Option<Piece>,
    castle: Option<Side>,
    is_en_passant: bool,
    promote: Option<piece::Type>,
    is_pawn_double_move: bool,
}
impl Move {
    pub fn new(from: Square, to: Square) -> Move {
        Move {
            from: from,
            to: to,
            capture_normal: None,
            castle: None,
            is_en_passant: false,
            promote: None,
            is_pawn_double_move: false,
        }
    }

    pub fn from(&self) -> Square { self.from }
    pub fn to(&self) -> Square { self.to }

    pub fn capture_normal(&self) -> Option<Piece> { self.capture_normal }
    pub fn set_capture_normal(&mut self, val: Option<Piece>) {
        self.capture_normal = val;
    }

    pub fn castle(&self) -> Option<Side> { self.castle }
    pub fn set_castle(&mut self, val: Option<Side>) {
        self.castle = val;
    }

    pub fn is_en_passant(&self) -> bool { self.is_en_passant }
    pub fn set_en_passant(&mut self, val: bool) {
        self.is_en_passant = val;
    }

    pub fn promote(&self) -> Option<piece::Type> { self.promote }
    pub fn set_promote(&mut self, val: Option<piece::Type>) {
        self.promote = val;
    }

    pub fn is_pawn_double_move(&self) -> bool { self.is_pawn_double_move }
    pub fn set_pawn_double_move(&mut self, val: bool) {
        self.is_pawn_double_move = val;
    }
}
impl fmt::Display for Move {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{}{}", self.from, self.to));
        if let Some(val) = self.promote() {
            try!(write!(f, "{}", match val {
                Queen  => 'q',
                Bishop => 'b',
                Knight => 'n',
                Rook   => 'r',
                _ => return Err(fmt::Error),
            }))
        }
        Ok(())
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct FromTo {
    from: Square,
    to: Square,
    promote: Option<piece::Type>,
}
impl FromTo {
    pub fn new(from: Square, to: Square) -> FromTo {
        FromTo { from: from, to: to, promote: None }
    }
    pub fn to_move_with_pos(&self, pos: &Position) -> Move {
        let mut ans = Move::new(self.from, self.to);
        ans.set_promote(self.promote);
        if !pos.is_empty_at(self.to) {
            ans.set_capture_normal(pos.at(self.to));
        }
        match pos.at(self.to).map(|x| x.piece_type()) {
            Some(King) => {
                match (self.from.file(), self.to.file()) {
                    (File(4), File(6)) => ans.set_castle(Some(Kingside)),
                    (File(4), File(2)) => ans.set_castle(Some(Queenside)),
                    _ => {},
                }
            },
            Some(Pawn) => {
                if self.from.file() != self.to.file() && ans.capture_normal().is_none() {
                    ans.set_en_passant(true);
                } else if ((self.from.rank().0) - (self.to.rank().0)).abs() != 1 {
                    ans.set_pawn_double_move(true);
                }
            },
            _ => {},
        }
        ans
    }
}
impl FromStr for FromTo {
    fn from_str(s: &str) -> Option<FromTo> {
        if s.len() != 4 && s.len() != 5 { return None; }
        let from: Square = match FromStr::from_str(&s[0..2]) {
            Some(val) => val, None => return None };
        let to:   Square = match FromStr::from_str(&s[2..4]) {
            Some(val) => val, None => return None };
        let mut ans = FromTo::new(from, to);
        if s.len() == 5 {
            ans.promote = Some( match s.as_bytes()[4] {
                b'q' => Queen,
                b'b' => Bishop,
                b'n' => Knight,
                b'r' => Rook,
                _ => return None,
            });
        }
        Some(ans)
    }
}
<commit_msg>Add debug logging in to_move_with_pos()<commit_after>//! The types for moves and plies.

use std::str::FromStr;
use std::fmt;
use std::num::SignedInt;

use super::piece::{self, Piece, Queen, Bishop, Knight, Rook, King, Pawn};
use super::square::{Square, File};
use super::castle::{Side, Kingside, Queenside};
use super::pos::Position;

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Move {
    from: Square,
    to: Square,
	capture_normal: Option<Piece>,
    castle: Option<Side>,
    is_en_passant: bool,
    promote: Option<piece::Type>,
    is_pawn_double_move: bool,
}
impl Move {
    pub fn new(from: Square, to: Square) -> Move {
        Move {
            from: from,
            to: to,
            capture_normal: None,
            castle: None,
            is_en_passant: false,
            promote: None,
            is_pawn_double_move: false,
        }
    }

    pub fn from(&self) -> Square { self.from }
    pub fn to(&self) -> Square { self.to }

    pub fn capture_normal(&self) -> Option<Piece> { self.capture_normal }
    pub fn set_capture_normal(&mut self, val: Option<Piece>) {
        self.capture_normal = val;
    }

    pub fn castle(&self) -> Option<Side> { self.castle }
    pub fn set_castle(&mut self, val: Option<Side>) {
        self.castle = val;
    }

    pub fn is_en_passant(&self) -> bool { self.is_en_passant }
    pub fn set_en_passant(&mut self, val: bool) {
        self.is_en_passant = val;
    }

    pub fn promote(&self) -> Option<piece::Type> { self.promote }
    pub fn set_promote(&mut self, val: Option<piece::Type>) {
        self.promote = val;
    }

    pub fn is_pawn_double_move(&self) -> bool { self.is_pawn_double_move }
    pub fn set_pawn_double_move(&mut self, val: bool) {
        self.is_pawn_double_move = val;
    }
}
impl fmt::Display for Move {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{}{}", self.from, self.to));
        if let Some(val) = self.promote() {
            try!(write!(f, "{}", match val {
                Queen  => 'q',
                Bishop => 'b',
                Knight => 'n',
                Rook   => 'r',
                _ => return Err(fmt::Error),
            }))
        }
        Ok(())
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct FromTo {
    from: Square,
    to: Square,
    promote: Option<piece::Type>,
}
impl FromTo {
    pub fn new(from: Square, to: Square) -> FromTo {
        FromTo { from: from, to: to, promote: None }
    }
    pub fn to_move_with_pos(&self, pos: &Position) -> Move {
        let mut ans = Move::new(self.from, self.to);
        ans.set_promote(self.promote);
        if !pos.is_empty_at(self.to) {
            ans.set_capture_normal(pos.at(self.to));
        }
        match pos.at(self.to).map(|x| x.piece_type()) {
            Some(King) => {
                match (self.from.file(), self.to.file()) {
                    (File(4), File(6)) => ans.set_castle(Some(Kingside)),
                    (File(4), File(2)) => ans.set_castle(Some(Queenside)),
                    _ => {},
                }
            },
            Some(Pawn) => {
                if self.from.file() != self.to.file() && ans.capture_normal().is_none() {
                    ans.set_en_passant(true);
                } else if ((self.from.rank().0) - (self.to.rank().0)).abs() != 1 {
                    ans.set_pawn_double_move(true);
                }
            },
            _ => {},
        }
        debug!("Converted {:?} into {:?}", *self, ans);
        ans
    }
}
impl FromStr for FromTo {
    fn from_str(s: &str) -> Option<FromTo> {
        if s.len() != 4 && s.len() != 5 { return None; }
        let from: Square = match FromStr::from_str(&s[0..2]) {
            Some(val) => val, None => return None };
        let to:   Square = match FromStr::from_str(&s[2..4]) {
            Some(val) => val, None => return None };
        let mut ans = FromTo::new(from, to);
        if s.len() == 5 {
            ans.promote = Some( match s.as_bytes()[4] {
                b'q' => Queen,
                b'b' => Bishop,
                b'n' => Knight,
                b'r' => Rook,
                _ => return None,
            });
        }
        Some(ans)
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 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.

//! This module implements the `Any` trait, which enables dynamic typing
//! of any type.

use cast::transmute;
use cmp::Eq;
use option::{Option, Some, None};
use to_str::ToStr;
use unstable::intrinsics;
use util::Void;

///////////////////////////////////////////////////////////////////////////////
// TypeId
///////////////////////////////////////////////////////////////////////////////

/// `TypeId` represents a globally unique identifier for a type
pub struct TypeId {
    priv t: u64,
}

impl TypeId {
    /// Returns the `TypeId` of the type this generic function has been instantiated with
    #[inline]
    pub fn of<T: 'static>() -> TypeId {
        TypeId{ t: unsafe { intrinsics::type_id::<T>() } }
    }
}

impl Eq for TypeId {
    #[inline]
    fn eq(&self, &other: &TypeId) -> bool {
        self.t == other.t
    }
}

///////////////////////////////////////////////////////////////////////////////
// Any trait
///////////////////////////////////////////////////////////////////////////////

/// The `Any` trait is implemented by all types, and can be used as a trait object
/// for dynamic typing
pub trait Any {
    /// Get the `TypeId` of `self`
    fn get_type_id(&self) -> TypeId;

    /// Get a void pointer to `self`
    fn as_void_ptr(&self) -> *Void;

    /// Get a mutable void pointer to `self`
    fn as_mut_void_ptr(&mut self) -> *mut Void;
}

impl<T: 'static> Any for T {
    /// Get the `TypeId` of `self`
    fn get_type_id(&self) -> TypeId {
        TypeId::of::<T>()
    }

    /// Get a void pointer to `self`
    fn as_void_ptr(&self) -> *Void {
        self as *T as *Void
    }

    /// Get a mutable void pointer to `self`
    fn as_mut_void_ptr(&mut self) -> *mut Void {
        self as *mut T as *mut Void
    }
}

///////////////////////////////////////////////////////////////////////////////
// Extension methods for Any trait objects.
// Implemented as three extension traits so that generics work.
///////////////////////////////////////////////////////////////////////////////

/// Extension methods for a referenced `Any` trait object
pub trait AnyRefExt<'self> {
    /// Returns true if the boxed type is the same as `T`
    fn is<T: 'static>(self) -> bool;

    /// Returns some reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    fn as_ref<T: 'static>(self) -> Option<&'self T>;
}

impl<'self> AnyRefExt<'self> for &'self Any {
    #[inline]
    fn is<T: 'static>(self) -> bool {
        // Get TypeId of the type this function is instantiated with
        let t = TypeId::of::<T>();

        // Get TypeId of the type in the trait object
        let boxed = self.get_type_id();

        // Compare both TypeIds on equality
        t == boxed
    }

    #[inline]
    fn as_ref<T: 'static>(self) -> Option<&'self T> {
        if self.is::<T>() {
            Some(unsafe { transmute(self.as_void_ptr()) })
        } else {
            None
        }
    }
}

/// Extension methods for a mutable referenced `Any` trait object
pub trait AnyMutRefExt<'self> {
    /// Returns some mutable reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    fn as_mut<T: 'static>(self) -> Option<&'self mut T>;
}

impl<'self> AnyMutRefExt<'self> for &'self mut Any {
    #[inline]
    fn as_mut<T: 'static>(self) -> Option<&'self mut T> {
        if self.is::<T>() {
            Some(unsafe { transmute(self.as_mut_void_ptr()) })
        } else {
            None
        }
    }
}

/// Extension methods for a owning `Any` trait object
pub trait AnyOwnExt {
    /// Returns the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    fn move<T: 'static>(self) -> Option<~T>;
}

impl AnyOwnExt for ~Any {
    #[inline]
    fn move<T: 'static>(self) -> Option<~T> {
        if self.is::<T>() {
            unsafe {
                // Extract the pointer to the boxed value, temporary alias with self
                let ptr: ~T = transmute(self.as_void_ptr());

                // Prevent destructor on self being run
                intrinsics::forget(self);

                Some(ptr)
            }
        } else {
            None
        }
    }
}

///////////////////////////////////////////////////////////////////////////////
// Trait implementations
///////////////////////////////////////////////////////////////////////////////

impl ToStr for ~Any {
    fn to_str(&self) -> ~str { ~"~Any" }
}

impl<'self> ToStr for &'self Any {
    fn to_str(&self) -> ~str { ~"&Any" }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::AnyRefExt;
    use option::{Some, None};

    #[deriving(Eq)]
    struct Test;

    static TEST: &'static str = "Test";

    #[test]
    fn type_id() {
        let (a, b, c) = (TypeId::of::<uint>(), TypeId::of::<&'static str>(),
                         TypeId::of::<Test>());
        let (d, e, f) = (TypeId::of::<uint>(), TypeId::of::<&'static str>(),
                         TypeId::of::<Test>());

        assert!(a != b);
        assert!(a != c);
        assert!(b != c);

        assert_eq!(a, d);
        assert_eq!(b, e);
        assert_eq!(c, f);
    }

    #[test]
    fn any_as_void_ptr() {
        let (a, b, c) = (~5u as ~Any, ~TEST as ~Any, ~Test as ~Any);
        let a_r: &Any = a;
        let b_r: &Any = b;
        let c_r: &Any = c;

        assert_eq!(a.as_void_ptr(), a_r.as_void_ptr());
        assert_eq!(b.as_void_ptr(), b_r.as_void_ptr());
        assert_eq!(c.as_void_ptr(), c_r.as_void_ptr());

        let (a, b, c) = (@5u as @Any, @TEST as @Any, @Test as @Any);
        let a_r: &Any = a;
        let b_r: &Any = b;
        let c_r: &Any = c;

        assert_eq!(a.as_void_ptr(), a_r.as_void_ptr());
        assert_eq!(b.as_void_ptr(), b_r.as_void_ptr());
        assert_eq!(c.as_void_ptr(), c_r.as_void_ptr());

        let (a, b, c) = (&5u as &Any, &TEST as &Any, &Test as &Any);
        let a_r: &Any = a;
        let b_r: &Any = b;
        let c_r: &Any = c;

        assert_eq!(a.as_void_ptr(), a_r.as_void_ptr());
        assert_eq!(b.as_void_ptr(), b_r.as_void_ptr());
        assert_eq!(c.as_void_ptr(), c_r.as_void_ptr());

        let mut x = Test;
        let mut y: &'static str = "Test";
        let (a, b, c) = (&mut 5u as &mut Any,
                         &mut y as &mut Any,
                         &mut x as &mut Any);
        let a_r: &Any = a;
        let b_r: &Any = b;
        let c_r: &Any = c;

        assert_eq!(a.as_void_ptr(), a_r.as_void_ptr());
        assert_eq!(b.as_void_ptr(), b_r.as_void_ptr());
        assert_eq!(c.as_void_ptr(), c_r.as_void_ptr());

        let (a, b, c) = (5u, "hello", Test);
        let (a_r, b_r, c_r) = (&a as &Any, &b as &Any, &c as &Any);

        assert_eq!(a.as_void_ptr(), a_r.as_void_ptr());
        assert_eq!(b.as_void_ptr(), b_r.as_void_ptr());
        assert_eq!(c.as_void_ptr(), c_r.as_void_ptr());
    }

    #[test]
    fn any_as_mut_void_ptr() {
        let y: &'static str = "Test";
        let mut a = ~5u as ~Any;
        let mut b = ~y as ~Any;
        let mut c = ~Test as ~Any;

        let a_ptr = a.as_mut_void_ptr();
        let b_ptr = b.as_mut_void_ptr();
        let c_ptr = c.as_mut_void_ptr();

        let a_r: &mut Any = a;
        let b_r: &mut Any = b;
        let c_r: &mut Any = c;

        assert_eq!(a_ptr, a_r.as_mut_void_ptr());
        assert_eq!(b_ptr, b_r.as_mut_void_ptr());
        assert_eq!(c_ptr, c_r.as_mut_void_ptr());

        let mut x = Test;
        let mut y: &'static str = "Test";
        let a = &mut 5u as &mut Any;
        let b = &mut y as &mut Any;
        let c = &mut x as &mut Any;

        let a_ptr = a.as_mut_void_ptr();
        let b_ptr = b.as_mut_void_ptr();
        let c_ptr = c.as_mut_void_ptr();

        let a_r: &mut Any = a;
        let b_r: &mut Any = b;
        let c_r: &mut Any = c;

        assert_eq!(a_ptr, a_r.as_mut_void_ptr());
        assert_eq!(b_ptr, b_r.as_mut_void_ptr());
        assert_eq!(c_ptr, c_r.as_mut_void_ptr());

        let y: &'static str = "Test";
        let mut a = 5u;
        let mut b = y;
        let mut c = Test;

        let a_ptr = a.as_mut_void_ptr();
        let b_ptr = b.as_mut_void_ptr();
        let c_ptr = c.as_mut_void_ptr();

        let (a_r, b_r, c_r) = (&mut a as &mut Any, &mut b as &mut Any, &mut c as &mut Any);

        assert_eq!(a_ptr, a_r.as_mut_void_ptr());
        assert_eq!(b_ptr, b_r.as_mut_void_ptr());
        assert_eq!(c_ptr, c_r.as_mut_void_ptr());
    }

    #[test]
    fn any_referenced() {
        let (a, b, c) = (&5u as &Any, &TEST as &Any, &Test as &Any);

        assert!(a.is::<uint>());
        assert!(!b.is::<uint>());
        assert!(!c.is::<uint>());

        assert!(!a.is::<&'static str>());
        assert!(b.is::<&'static str>());
        assert!(!c.is::<&'static str>());

        assert!(!a.is::<Test>());
        assert!(!b.is::<Test>());
        assert!(c.is::<Test>());
    }

    #[test]
    fn any_owning() {
        let (a, b, c) = (~5u as ~Any, ~TEST as ~Any, ~Test as ~Any);

        assert!(a.is::<uint>());
        assert!(!b.is::<uint>());
        assert!(!c.is::<uint>());

        assert!(!a.is::<&'static str>());
        assert!(b.is::<&'static str>());
        assert!(!c.is::<&'static str>());

        assert!(!a.is::<Test>());
        assert!(!b.is::<Test>());
        assert!(c.is::<Test>());
    }

    #[test]
    fn any_managed() {
        let (a, b, c) = (@5u as @Any, @TEST as @Any, @Test as @Any);

        assert!(a.is::<uint>());
        assert!(!b.is::<uint>());
        assert!(!c.is::<uint>());

        assert!(!a.is::<&'static str>());
        assert!(b.is::<&'static str>());
        assert!(!c.is::<&'static str>());

        assert!(!a.is::<Test>());
        assert!(!b.is::<Test>());
        assert!(c.is::<Test>());
    }

    #[test]
    fn any_as_ref() {
        let a = &5u as &Any;

        match a.as_ref::<uint>() {
            Some(&5) => {}
            x => fail!("Unexpected value {:?}", x)
        }

        match a.as_ref::<Test>() {
            None => {}
            x => fail!("Unexpected value {:?}", x)
        }
    }

    #[test]
    fn any_as_mut() {
        let mut a = 5u;
        let mut b = ~7u;

        let a_r = &mut a as &mut Any;
        let tmp: &mut uint = b;
        let b_r = tmp as &mut Any;

        match a_r.as_mut::<uint>() {
            Some(x) => {
                assert_eq!(*x, 5u);
                *x = 612;
            }
            x => fail!("Unexpected value {:?}", x)
        }

        match b_r.as_mut::<uint>() {
            Some(x) => {
                assert_eq!(*x, 7u);
                *x = 413;
            }
            x => fail!("Unexpected value {:?}", x)
        }

        match a_r.as_mut::<Test>() {
            None => (),
            x => fail!("Unexpected value {:?}", x)
        }

        match b_r.as_mut::<Test>() {
            None => (),
            x => fail!("Unexpected value {:?}", x)
        }

        match a_r.as_mut::<uint>() {
            Some(&612) => {}
            x => fail!("Unexpected value {:?}", x)
        }

        match b_r.as_mut::<uint>() {
            Some(&413) => {}
            x => fail!("Unexpected value {:?}", x)
        }
    }

    #[test]
    fn any_move() {
        let a = ~8u as ~Any;
        let b = ~Test as ~Any;

        assert_eq!(a.move(), Some(~8u));
        assert_eq!(b.move(), Some(~Test));

        let a = ~8u as ~Any;
        let b = ~Test as ~Any;

        assert_eq!(a.move(), None::<~Test>);
        assert_eq!(b.move(), None::<~uint>);
    }
}
<commit_msg>auto merge of #10359 : tomassedovic/rust/typeid-iterbytes, r=pcwalton<commit_after>// Copyright 2013 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.

//! This module implements the `Any` trait, which enables dynamic typing
//! of any type.

use cast::transmute;
use cmp::Eq;
use option::{Option, Some, None};
use to_bytes::{IterBytes, Cb};
use to_str::ToStr;
use unstable::intrinsics;
use util::Void;

///////////////////////////////////////////////////////////////////////////////
// TypeId
///////////////////////////////////////////////////////////////////////////////

/// `TypeId` represents a globally unique identifier for a type
pub struct TypeId {
    priv t: u64,
}

impl TypeId {
    /// Returns the `TypeId` of the type this generic function has been instantiated with
    #[inline]
    pub fn of<T: 'static>() -> TypeId {
        TypeId{ t: unsafe { intrinsics::type_id::<T>() } }
    }
}

impl Eq for TypeId {
    #[inline]
    fn eq(&self, &other: &TypeId) -> bool {
        self.t == other.t
    }
}

impl IterBytes for TypeId {
    fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
        self.t.iter_bytes(lsb0, f)
    }
}

///////////////////////////////////////////////////////////////////////////////
// Any trait
///////////////////////////////////////////////////////////////////////////////

/// The `Any` trait is implemented by all types, and can be used as a trait object
/// for dynamic typing
pub trait Any {
    /// Get the `TypeId` of `self`
    fn get_type_id(&self) -> TypeId;

    /// Get a void pointer to `self`
    fn as_void_ptr(&self) -> *Void;

    /// Get a mutable void pointer to `self`
    fn as_mut_void_ptr(&mut self) -> *mut Void;
}

impl<T: 'static> Any for T {
    /// Get the `TypeId` of `self`
    fn get_type_id(&self) -> TypeId {
        TypeId::of::<T>()
    }

    /// Get a void pointer to `self`
    fn as_void_ptr(&self) -> *Void {
        self as *T as *Void
    }

    /// Get a mutable void pointer to `self`
    fn as_mut_void_ptr(&mut self) -> *mut Void {
        self as *mut T as *mut Void
    }
}

///////////////////////////////////////////////////////////////////////////////
// Extension methods for Any trait objects.
// Implemented as three extension traits so that generics work.
///////////////////////////////////////////////////////////////////////////////

/// Extension methods for a referenced `Any` trait object
pub trait AnyRefExt<'self> {
    /// Returns true if the boxed type is the same as `T`
    fn is<T: 'static>(self) -> bool;

    /// Returns some reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    fn as_ref<T: 'static>(self) -> Option<&'self T>;
}

impl<'self> AnyRefExt<'self> for &'self Any {
    #[inline]
    fn is<T: 'static>(self) -> bool {
        // Get TypeId of the type this function is instantiated with
        let t = TypeId::of::<T>();

        // Get TypeId of the type in the trait object
        let boxed = self.get_type_id();

        // Compare both TypeIds on equality
        t == boxed
    }

    #[inline]
    fn as_ref<T: 'static>(self) -> Option<&'self T> {
        if self.is::<T>() {
            Some(unsafe { transmute(self.as_void_ptr()) })
        } else {
            None
        }
    }
}

/// Extension methods for a mutable referenced `Any` trait object
pub trait AnyMutRefExt<'self> {
    /// Returns some mutable reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    fn as_mut<T: 'static>(self) -> Option<&'self mut T>;
}

impl<'self> AnyMutRefExt<'self> for &'self mut Any {
    #[inline]
    fn as_mut<T: 'static>(self) -> Option<&'self mut T> {
        if self.is::<T>() {
            Some(unsafe { transmute(self.as_mut_void_ptr()) })
        } else {
            None
        }
    }
}

/// Extension methods for a owning `Any` trait object
pub trait AnyOwnExt {
    /// Returns the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    fn move<T: 'static>(self) -> Option<~T>;
}

impl AnyOwnExt for ~Any {
    #[inline]
    fn move<T: 'static>(self) -> Option<~T> {
        if self.is::<T>() {
            unsafe {
                // Extract the pointer to the boxed value, temporary alias with self
                let ptr: ~T = transmute(self.as_void_ptr());

                // Prevent destructor on self being run
                intrinsics::forget(self);

                Some(ptr)
            }
        } else {
            None
        }
    }
}

///////////////////////////////////////////////////////////////////////////////
// Trait implementations
///////////////////////////////////////////////////////////////////////////////

impl ToStr for ~Any {
    fn to_str(&self) -> ~str { ~"~Any" }
}

impl<'self> ToStr for &'self Any {
    fn to_str(&self) -> ~str { ~"&Any" }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::AnyRefExt;
    use option::{Some, None};
    use hash::Hash;

    #[deriving(Eq)]
    struct Test;

    static TEST: &'static str = "Test";

    #[test]
    fn type_id() {
        let (a, b, c) = (TypeId::of::<uint>(), TypeId::of::<&'static str>(),
                         TypeId::of::<Test>());
        let (d, e, f) = (TypeId::of::<uint>(), TypeId::of::<&'static str>(),
                         TypeId::of::<Test>());

        assert!(a != b);
        assert!(a != c);
        assert!(b != c);

        assert_eq!(a, d);
        assert_eq!(b, e);
        assert_eq!(c, f);
    }

    #[test]
    fn type_id_hash() {
        let (a, b) = (TypeId::of::<uint>(), TypeId::of::<uint>::());

        assert_eq!(a.hash(), b.hash());
    }

    #[test]
    fn any_as_void_ptr() {
        let (a, b, c) = (~5u as ~Any, ~TEST as ~Any, ~Test as ~Any);
        let a_r: &Any = a;
        let b_r: &Any = b;
        let c_r: &Any = c;

        assert_eq!(a.as_void_ptr(), a_r.as_void_ptr());
        assert_eq!(b.as_void_ptr(), b_r.as_void_ptr());
        assert_eq!(c.as_void_ptr(), c_r.as_void_ptr());

        let (a, b, c) = (@5u as @Any, @TEST as @Any, @Test as @Any);
        let a_r: &Any = a;
        let b_r: &Any = b;
        let c_r: &Any = c;

        assert_eq!(a.as_void_ptr(), a_r.as_void_ptr());
        assert_eq!(b.as_void_ptr(), b_r.as_void_ptr());
        assert_eq!(c.as_void_ptr(), c_r.as_void_ptr());

        let (a, b, c) = (&5u as &Any, &TEST as &Any, &Test as &Any);
        let a_r: &Any = a;
        let b_r: &Any = b;
        let c_r: &Any = c;

        assert_eq!(a.as_void_ptr(), a_r.as_void_ptr());
        assert_eq!(b.as_void_ptr(), b_r.as_void_ptr());
        assert_eq!(c.as_void_ptr(), c_r.as_void_ptr());

        let mut x = Test;
        let mut y: &'static str = "Test";
        let (a, b, c) = (&mut 5u as &mut Any,
                         &mut y as &mut Any,
                         &mut x as &mut Any);
        let a_r: &Any = a;
        let b_r: &Any = b;
        let c_r: &Any = c;

        assert_eq!(a.as_void_ptr(), a_r.as_void_ptr());
        assert_eq!(b.as_void_ptr(), b_r.as_void_ptr());
        assert_eq!(c.as_void_ptr(), c_r.as_void_ptr());

        let (a, b, c) = (5u, "hello", Test);
        let (a_r, b_r, c_r) = (&a as &Any, &b as &Any, &c as &Any);

        assert_eq!(a.as_void_ptr(), a_r.as_void_ptr());
        assert_eq!(b.as_void_ptr(), b_r.as_void_ptr());
        assert_eq!(c.as_void_ptr(), c_r.as_void_ptr());
    }

    #[test]
    fn any_as_mut_void_ptr() {
        let y: &'static str = "Test";
        let mut a = ~5u as ~Any;
        let mut b = ~y as ~Any;
        let mut c = ~Test as ~Any;

        let a_ptr = a.as_mut_void_ptr();
        let b_ptr = b.as_mut_void_ptr();
        let c_ptr = c.as_mut_void_ptr();

        let a_r: &mut Any = a;
        let b_r: &mut Any = b;
        let c_r: &mut Any = c;

        assert_eq!(a_ptr, a_r.as_mut_void_ptr());
        assert_eq!(b_ptr, b_r.as_mut_void_ptr());
        assert_eq!(c_ptr, c_r.as_mut_void_ptr());

        let mut x = Test;
        let mut y: &'static str = "Test";
        let a = &mut 5u as &mut Any;
        let b = &mut y as &mut Any;
        let c = &mut x as &mut Any;

        let a_ptr = a.as_mut_void_ptr();
        let b_ptr = b.as_mut_void_ptr();
        let c_ptr = c.as_mut_void_ptr();

        let a_r: &mut Any = a;
        let b_r: &mut Any = b;
        let c_r: &mut Any = c;

        assert_eq!(a_ptr, a_r.as_mut_void_ptr());
        assert_eq!(b_ptr, b_r.as_mut_void_ptr());
        assert_eq!(c_ptr, c_r.as_mut_void_ptr());

        let y: &'static str = "Test";
        let mut a = 5u;
        let mut b = y;
        let mut c = Test;

        let a_ptr = a.as_mut_void_ptr();
        let b_ptr = b.as_mut_void_ptr();
        let c_ptr = c.as_mut_void_ptr();

        let (a_r, b_r, c_r) = (&mut a as &mut Any, &mut b as &mut Any, &mut c as &mut Any);

        assert_eq!(a_ptr, a_r.as_mut_void_ptr());
        assert_eq!(b_ptr, b_r.as_mut_void_ptr());
        assert_eq!(c_ptr, c_r.as_mut_void_ptr());
    }

    #[test]
    fn any_referenced() {
        let (a, b, c) = (&5u as &Any, &TEST as &Any, &Test as &Any);

        assert!(a.is::<uint>());
        assert!(!b.is::<uint>());
        assert!(!c.is::<uint>());

        assert!(!a.is::<&'static str>());
        assert!(b.is::<&'static str>());
        assert!(!c.is::<&'static str>());

        assert!(!a.is::<Test>());
        assert!(!b.is::<Test>());
        assert!(c.is::<Test>());
    }

    #[test]
    fn any_owning() {
        let (a, b, c) = (~5u as ~Any, ~TEST as ~Any, ~Test as ~Any);

        assert!(a.is::<uint>());
        assert!(!b.is::<uint>());
        assert!(!c.is::<uint>());

        assert!(!a.is::<&'static str>());
        assert!(b.is::<&'static str>());
        assert!(!c.is::<&'static str>());

        assert!(!a.is::<Test>());
        assert!(!b.is::<Test>());
        assert!(c.is::<Test>());
    }

    #[test]
    fn any_managed() {
        let (a, b, c) = (@5u as @Any, @TEST as @Any, @Test as @Any);

        assert!(a.is::<uint>());
        assert!(!b.is::<uint>());
        assert!(!c.is::<uint>());

        assert!(!a.is::<&'static str>());
        assert!(b.is::<&'static str>());
        assert!(!c.is::<&'static str>());

        assert!(!a.is::<Test>());
        assert!(!b.is::<Test>());
        assert!(c.is::<Test>());
    }

    #[test]
    fn any_as_ref() {
        let a = &5u as &Any;

        match a.as_ref::<uint>() {
            Some(&5) => {}
            x => fail!("Unexpected value {:?}", x)
        }

        match a.as_ref::<Test>() {
            None => {}
            x => fail!("Unexpected value {:?}", x)
        }
    }

    #[test]
    fn any_as_mut() {
        let mut a = 5u;
        let mut b = ~7u;

        let a_r = &mut a as &mut Any;
        let tmp: &mut uint = b;
        let b_r = tmp as &mut Any;

        match a_r.as_mut::<uint>() {
            Some(x) => {
                assert_eq!(*x, 5u);
                *x = 612;
            }
            x => fail!("Unexpected value {:?}", x)
        }

        match b_r.as_mut::<uint>() {
            Some(x) => {
                assert_eq!(*x, 7u);
                *x = 413;
            }
            x => fail!("Unexpected value {:?}", x)
        }

        match a_r.as_mut::<Test>() {
            None => (),
            x => fail!("Unexpected value {:?}", x)
        }

        match b_r.as_mut::<Test>() {
            None => (),
            x => fail!("Unexpected value {:?}", x)
        }

        match a_r.as_mut::<uint>() {
            Some(&612) => {}
            x => fail!("Unexpected value {:?}", x)
        }

        match b_r.as_mut::<uint>() {
            Some(&413) => {}
            x => fail!("Unexpected value {:?}", x)
        }
    }

    #[test]
    fn any_move() {
        let a = ~8u as ~Any;
        let b = ~Test as ~Any;

        assert_eq!(a.move(), Some(~8u));
        assert_eq!(b.move(), Some(~Test));

        let a = ~8u as ~Any;
        let b = ~Test as ~Any;

        assert_eq!(a.move(), None::<~Test>);
        assert_eq!(b.move(), None::<~uint>);
    }
}
<|endoftext|>