<commit_before>pub mod search;

use std::thread;
use std::cmp::min;
use std::collections::VecDeque;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::time::SystemTime;
use std::num::Wrapping;
use basetypes::*;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use position::Position;
use chess_move::*;
use tt::*;

const VERSION: &'static str = "0.1";
const MAX_DEPTH: u8 = 126;

/// Implements `UciEngine` trait.
pub struct Engine {
    tt: Arc<TranspositionTable>,
    reply_queue: VecDeque<EngineReply>,
    position: Position,
    is_thinking: bool,
    is_pondering: bool,

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

    // A channel for sending commands to the search thread.
    commands: Sender<search::Command>,

    // A channel for receiving reports from the search thread.
    reports: Receiver<search::Report>,

    // Search status info
    search_id: usize,
    thinking_since: SystemTime,
    no_reports_since: SystemTime,
    current_depth: u8,
    searched_nodes: NodeCount,
    searched_time: u64, // milliseconds
    nps: u64, // nodes per second
    mangled_pv: bool, // `true` if the primary variation is imperfect
    stop_when: TimeManagement,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        let tt2 = tt.clone();
        thread::spawn(move || {
            search::run_deepening(tt2, commands_rx, reports_tx);
        });

        Engine {
            tt: tt,
            reply_queue: VecDeque::new(),
            position: Position::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 \
                                          1")
                          .ok()
                          .unwrap(),
            is_thinking: false,
            is_pondering: false,
            pondering_is_allowed: false,
            commands: commands_tx,
            reports: reports_rx,
            search_id: 0,
            thinking_since: SystemTime::now(),
            no_reports_since: SystemTime::now(),
            current_depth: 0,
            searched_nodes: 0,
            searched_time: 0,
            nps: 0,
            mangled_pv: false,
            stop_when: TimeManagement::Infinite,
        }
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // An invalid option. Notice that we do not support
            // re-sizing of the transposition table once the engine
            // had started.
            _ => (),
        }
    }

    fn new_game(&mut self) {
        // Clearing the transposition table would not change anything,
        // so we do nothing.
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if !self.is_thinking {
            if let Ok(p) = Position::from_history(fen, moves) {
                self.position = p;
                self.tt.new_search();
            }
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        if !self.is_thinking {
            // Note: We ignore "searchmoves" and "mate" parameters.

            self.is_thinking = true;
            self.is_pondering = ponder;
            self.search_id = (Wrapping(self.search_id) + Wrapping(1)).0;
            self.thinking_since = SystemTime::now();
            self.no_reports_since = SystemTime::now();
            self.current_depth = 0;
            self.searched_nodes = 0;
            self.searched_time = 0;
            self.mangled_pv = false;

            // Figure out when we should stop thinking.
            let (time, inc) = if self.position.board().to_move() == WHITE {
                (wtime, winc.unwrap_or(0))
            } else {
                (btime, binc.unwrap_or(0))
            };
            self.stop_when = if infinite {
                TimeManagement::Infinite
            } else if movetime.is_some() {
                TimeManagement::MoveTime(movetime.unwrap())
            } else if nodes.is_some() {
                TimeManagement::Nodes(nodes.unwrap())
            } else if depth.is_some() {
                TimeManagement::Depth(depth.unwrap() as u8)
            } else {
                let time = time.unwrap_or(0);
                let movestogo = movestogo.unwrap_or(40);
                let movetime = (time + inc * movestogo) / movestogo;
                TimeManagement::MoveTimeHint(min(movetime, time / 2))
            };

            // Start deepening search to the maximum possible depth.
            self.commands
                .send(search::Command::Search {
                    search_id: self.search_id,
                    position: self.position.clone(),
                    depth: MAX_DEPTH,
                    lower_bound: -20000,
                    upper_bound: 20000,
                })
                .unwrap();
        }
    }

    fn ponder_hit(&mut self) {
        if self.is_thinking && self.is_pondering {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        if self.is_thinking {
            self.commands.send(search::Command::Stop).unwrap();

            // TODO: send ponder move as well.
            let best_move = self.get_best_move();
            self.reply_queue.push_back(EngineReply::BestMove {
                best_move: best_move,
                ponder_move: None,
            });

            self.is_thinking = false;
        }
    }

    fn is_thinking(&self) -> bool {
        self.is_thinking
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        // Check if we should stop thinking.
        if self.is_thinking && !self.is_pondering {
            if match self.stop_when {
                TimeManagement::MoveTime(t) => self.searched_time >= t,
                TimeManagement::MoveTimeHint(t) => self.searched_time >= t,
                TimeManagement::Nodes(n) => self.searched_nodes >= n,
                TimeManagement::Depth(d) => self.current_depth > d,
                TimeManagement::Infinite => false,
            } {
                self.stop();
            }
        }

        // Check the reports queue.
        while let Ok(report) = self.reports.try_recv() {
            if self.is_thinking {
                match report {
                    search::Report::Progress { search_id, searched_nodes, depth }
                        if search_id == self.search_id => {
                        // Register search progress.
                        self.register_progress(depth, searched_nodes);
                        if self.no_reports_since.elapsed().unwrap().as_secs() > 20 {
                            if self.mangled_pv {
                                self.report_pv(depth - 1);
                            } else {
                                self.report_progress();
                            }
                        }
                    }
                    search::Report::Done { search_id, .. } if search_id == self.search_id => {
                        // Terminate the search (unless pondering of infinite).
                        if !self.is_pondering {
                            self.stop_when = if let TimeManagement::Infinite = self.stop_when {
                                TimeManagement::Infinite
                            } else {
                                TimeManagement::MoveTime(0)
                            };
                        }
                    }

                    // Stale reports from stopped searches.
                    _ => (),
                }
            }
        }

        self.reply_queue.pop_front()
    }
}

impl Engine {
    // A helper method.
    fn register_progress(&mut self, depth: u8, searched_nodes: NodeCount) {
        let thinking_duration = self.thinking_since.elapsed().unwrap();
        self.searched_nodes = searched_nodes;
        self.searched_time = 1000 * thinking_duration.as_secs() +
                             (thinking_duration.subsec_nanos() / 1000000) as u64;
        self.nps = 1000 * (self.nps + self.searched_nodes) / (1000 + self.searched_time);
        if self.current_depth < depth {
            self.current_depth = depth;
            self.report_pv(depth - 1);
            if !self.mangled_pv {
                self.report_progress();
            }
        }
    }

    // A helper method. It extracts the primary variation (PV) from
    // the transposition table (TT) and sends it to the GUI.
    fn report_pv(&mut self, depth: u8) {
        let mut prev_move = None;
        let mut p = self.position.clone();

        // Extract the PV, the value, and the bound from the TT.
        let mut pv = Vec::new();
        let mut value = -20000;
        let mut bound = BOUND_LOWER;
        while let Some(entry) = self.tt.probe(p.hash()) {
            if pv.len() < depth as usize && entry.bound() != BOUND_NONE {
                if let Some(m) = prev_move {
                    pv.push(m);
                }
                if pv.len() & 1 == 0 {
                    value = entry.value();
                    bound = entry.bound();
                } else {
                    // In this case the value stored in `entry` is
                    // from other side's perspective.
                    value = -entry.value();
                    bound = match entry.bound() {
                        BOUND_UPPER => BOUND_LOWER,
                        BOUND_LOWER => BOUND_UPPER,
                        x => x,
                    };
                }
                if bound == BOUND_EXACT {
                    if let Some(m) = p.try_move_digest(entry.move16()) {
                        if p.do_move(m) && !p.is_repeated() {
                            // Try to extend the PV.
                            prev_move = Some(m);
                            continue;
                        }
                    }
                }
            }
            break;
        }
        self.mangled_pv = bound != BOUND_EXACT || pv.len() < depth as usize;

        // Send the extracted info to the GUI.
        let value_suffix = match bound {
            BOUND_EXACT => "",
            BOUND_UPPER => " upperbound",
            BOUND_LOWER => " lowerbound",
            _ => panic!("unexpected bound type"),
        };
        let mut pv_string = String::new();
        for m in pv {
            pv_string.push(' ');
            pv_string.push_str(&m.notation());
        }
        self.reply_queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", depth)),
            ("score".to_string(), format!("cp {}{}", value, value_suffix)),
            ("time".to_string(), format!("{}", self.searched_time)),
            ("nodes".to_string(), format!("{}", self.searched_nodes)),
            ("nps".to_string(), format!("{}", self.nps)),
            ("pv".to_string(), pv_string),
        ]));
        self.no_reports_since = SystemTime::now();
    }

    // A helper method. It reports the depth, the node count, and
    // nodes per second to the GUI.
    fn report_progress(&mut self) {
        self.reply_queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", self.current_depth)),
            ("nodes".to_string(), format!("{}", self.searched_nodes)),
            ("nps".to_string(), format!("{}", self.nps)),
        ]));
        self.no_reports_since = SystemTime::now();
    }

    fn get_best_move(&mut self) -> String {
        let mut m = match self.tt.probe(self.position.hash()) {
            Some(entry) => entry.move16(),
            None => 0,
        };
        if m == 0 {
            // Pick the first legal move.
            let mut first_legal_move = Move::invalid();
            let mut v = MoveStack::new();
            self.position.generate_moves(&mut v);
            while let Some(x) = v.pop() {
                if self.position.do_move(x) {
                    self.position.undo_move();
                    first_legal_move = x;
                    break;
                }
            }
            m = first_legal_move.digest();
        }
        if m != 0 {
            let move_type = move_type(m);
            let orig_square = orig_square(m);
            let dest_square = dest_square(m);
            let promoted_piece = match aux_data(m) {
                0 => "q",
                1 => "r",
                2 => "b",
                3 => "n",
                _ => panic!("invalid promoted piece code"),
            };
            format!("{}{}{}",
                    notation(orig_square),
                    notation(dest_square),
                    if move_type == MOVE_PROMOTION {
                        promoted_piece
                    } else {
                        ""
                    })

        } else {
            "0000".to_string()
        }
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("Alcibiades {}", VERSION)
    }

    fn author(&self) -> String {
        "Evgeni Pandurski".to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}

enum TimeManagement {
    MoveTime(u64),
    MoveTimeHint(u64),
    Nodes(NodeCount),
    Depth(u8),
    Infinite,
}
<commit_msg>beautifications<commit_after>pub mod search;

use std::thread;
use std::cmp::min;
use std::collections::VecDeque;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::time::SystemTime;
use std::num::Wrapping;
use basetypes::*;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use position::Position;
use chess_move::*;
use tt::*;

const VERSION: &'static str = "0.1";
const MAX_DEPTH: u8 = 126;

/// Implements `UciEngine` trait.
pub struct Engine {
    tt: Arc<TranspositionTable>,
    reply_queue: VecDeque<EngineReply>,
    position: Position,
    is_thinking: bool,
    is_pondering: bool,

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

    // A channel for sending commands to the search thread.
    commands: Sender<search::Command>,

    // A channel for receiving reports from the search thread.
    reports: Receiver<search::Report>,

    // Search status info
    search_id: usize,
    thinking_since: SystemTime,
    no_reports_since: SystemTime,
    current_depth: u8,
    searched_nodes: NodeCount,
    searched_time: u64, // milliseconds
    nps: u64, // nodes per second
    mangled_pv: bool, // `true` if the primary variation is imperfect
    stop_when: TimeManagement,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        let tt2 = tt.clone();
        thread::spawn(move || {
            search::run_deepening(tt2, commands_rx, reports_tx);
        });

        Engine {
            tt: tt,
            reply_queue: VecDeque::new(),
            position: Position::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 \
                                          1")
                          .ok()
                          .unwrap(),
            is_thinking: false,
            is_pondering: false,
            pondering_is_allowed: false,
            commands: commands_tx,
            reports: reports_rx,
            search_id: 0,
            thinking_since: SystemTime::now(),
            no_reports_since: SystemTime::now(),
            current_depth: 0,
            searched_nodes: 0,
            searched_time: 0,
            nps: 0,
            mangled_pv: false,
            stop_when: TimeManagement::Infinite,
        }
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // An invalid option. Notice that we do not support
            // re-sizing of the transposition table once the engine
            // had started.
            _ => (),
        }
    }

    fn new_game(&mut self) {
        // Clearing the transposition table would not change anything,
        // so we do nothing.
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if !self.is_thinking {
            if let Ok(p) = Position::from_history(fen, moves) {
                self.position = p;
                self.tt.new_search();
            }
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        if !self.is_thinking {
            // Note: We ignore "searchmoves" and "mate" parameters.

            self.is_thinking = true;
            self.is_pondering = ponder;
            self.search_id = (Wrapping(self.search_id) + Wrapping(1)).0;
            self.thinking_since = SystemTime::now();
            self.no_reports_since = SystemTime::now();
            self.current_depth = 0;
            self.searched_nodes = 0;
            self.searched_time = 0;
            self.mangled_pv = false;

            // Figure out when we should stop thinking.
            let (time, inc) = if self.position.board().to_move() == WHITE {
                (wtime, winc.unwrap_or(0))
            } else {
                (btime, binc.unwrap_or(0))
            };
            self.stop_when = if infinite {
                TimeManagement::Infinite
            } else if movetime.is_some() {
                TimeManagement::MoveTime(movetime.unwrap())
            } else if nodes.is_some() {
                TimeManagement::Nodes(nodes.unwrap())
            } else if depth.is_some() {
                TimeManagement::Depth(depth.unwrap() as u8)
            } else {
                let time = time.unwrap_or(0);
                let movestogo = movestogo.unwrap_or(40);
                let movetime = (time + inc * movestogo) / movestogo;
                TimeManagement::MoveTimeHint(min(movetime, time / 2))
            };

            // Start deepening search to the maximum possible depth.
            self.commands
                .send(search::Command::Search {
                    search_id: self.search_id,
                    position: self.position.clone(),
                    depth: MAX_DEPTH,
                    lower_bound: -20000,
                    upper_bound: 20000,
                })
                .unwrap();
        }
    }

    fn ponder_hit(&mut self) {
        if self.is_thinking && self.is_pondering {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        if self.is_thinking {
            self.commands.send(search::Command::Stop).unwrap();

            // TODO: send ponder move as well.
            let best_move = self.get_best_move();
            self.reply_queue.push_back(EngineReply::BestMove {
                best_move: best_move,
                ponder_move: None,
            });

            self.is_thinking = false;
        }
    }

    fn is_thinking(&self) -> bool {
        self.is_thinking
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        // Check if we should stop thinking.
        if self.is_thinking && !self.is_pondering {
            if match self.stop_when {
                TimeManagement::MoveTime(t) => self.searched_time >= t,
                TimeManagement::MoveTimeHint(t) => self.searched_time >= t,
                TimeManagement::Nodes(n) => self.searched_nodes >= n,
                TimeManagement::Depth(d) => self.current_depth > d,
                TimeManagement::Infinite => false,
            } {
                self.stop();
            }
        }

        // Check the reports queue.
        while let Ok(report) = self.reports.try_recv() {
            if self.is_thinking {
                match report {
                    search::Report::Progress { search_id, searched_nodes, depth }
                        if search_id == self.search_id => {
                        // Register search progress.
                        self.register_progress(depth, searched_nodes);
                        if self.no_reports_since.elapsed().unwrap().as_secs() > 20 {
                            if self.mangled_pv {
                                self.report_pv(depth - 1);
                            } else {
                                self.report_progress();
                            }
                        }
                    }
                    search::Report::Done { search_id, .. } if search_id == self.search_id => {
                        // Terminate the search (unless pondering of infinite).
                        if !self.is_pondering {
                            self.stop_when = match self.stop_when {
                                TimeManagement::Infinite => TimeManagement::Infinite,
                                _ => TimeManagement::MoveTime(0),
                            };
                        }
                    }
                    // We may still receive stale reports from already
                    // stopped searches.
                    _ => (),
                }
            }
        }

        self.reply_queue.pop_front()
    }
}

impl Engine {
    // A helper method.
    fn register_progress(&mut self, depth: u8, searched_nodes: NodeCount) {
        let thinking_duration = self.thinking_since.elapsed().unwrap();
        self.searched_nodes = searched_nodes;
        self.searched_time = 1000 * thinking_duration.as_secs() +
                             (thinking_duration.subsec_nanos() / 1000000) as u64;
        self.nps = 1000 * (self.nps + self.searched_nodes) / (1000 + self.searched_time);
        if self.current_depth < depth {
            self.current_depth = depth;
            self.report_pv(depth - 1);
            if !self.mangled_pv {
                self.report_progress();
            }
        }
    }

    // A helper method. It extracts the primary variation (PV) from
    // the transposition table (TT) and sends it to the GUI.
    fn report_pv(&mut self, depth: u8) {
        let mut prev_move = None;
        let mut p = self.position.clone();

        // Extract the PV, the value, and the bound from the TT.
        let mut pv = Vec::new();
        let mut value = -20000;
        let mut bound = BOUND_LOWER;
        while let Some(entry) = self.tt.probe(p.hash()) {
            if pv.len() < depth as usize && entry.bound() != BOUND_NONE {
                if let Some(m) = prev_move {
                    pv.push(m);
                }
                if pv.len() & 1 == 0 {
                    value = entry.value();
                    bound = entry.bound();
                } else {
                    // In this case the value stored in `entry` is
                    // from other side's perspective.
                    value = -entry.value();
                    bound = match entry.bound() {
                        BOUND_UPPER => BOUND_LOWER,
                        BOUND_LOWER => BOUND_UPPER,
                        x => x,
                    };
                }
                if bound == BOUND_EXACT {
                    if let Some(m) = p.try_move_digest(entry.move16()) {
                        if p.do_move(m) && !p.is_repeated() {
                            // Try to extend the PV.
                            prev_move = Some(m);
                            continue;
                        }
                    }
                }
            }
            break;
        }
        self.mangled_pv = bound != BOUND_EXACT || pv.len() < depth as usize;

        // Send the extracted info to the GUI.
        let value_suffix = match bound {
            BOUND_EXACT => "",
            BOUND_UPPER => " upperbound",
            BOUND_LOWER => " lowerbound",
            _ => panic!("unexpected bound type"),
        };
        let mut pv_string = String::new();
        for m in pv {
            pv_string.push(' ');
            pv_string.push_str(&m.notation());
        }
        self.reply_queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", depth)),
            ("score".to_string(), format!("cp {}{}", value, value_suffix)),
            ("time".to_string(), format!("{}", self.searched_time)),
            ("nodes".to_string(), format!("{}", self.searched_nodes)),
            ("nps".to_string(), format!("{}", self.nps)),
            ("pv".to_string(), pv_string),
        ]));
        self.no_reports_since = SystemTime::now();
    }

    // A helper method. It reports the depth, the node count, and
    // nodes per second to the GUI.
    fn report_progress(&mut self) {
        self.reply_queue.push_back(EngineReply::Info(vec![
            ("depth".to_string(), format!("{}", self.current_depth)),
            ("nodes".to_string(), format!("{}", self.searched_nodes)),
            ("nps".to_string(), format!("{}", self.nps)),
        ]));
        self.no_reports_since = SystemTime::now();
    }

    fn get_best_move(&mut self) -> String {
        let mut m = match self.tt.probe(self.position.hash()) {
            Some(entry) => entry.move16(),
            None => 0,
        };
        if m == 0 {
            // Pick the first legal move.
            let mut first_legal_move = Move::invalid();
            let mut v = MoveStack::new();
            self.position.generate_moves(&mut v);
            while let Some(x) = v.pop() {
                if self.position.do_move(x) {
                    self.position.undo_move();
                    first_legal_move = x;
                    break;
                }
            }
            m = first_legal_move.digest();
        }
        if m != 0 {
            let move_type = move_type(m);
            let orig_square = orig_square(m);
            let dest_square = dest_square(m);
            let promoted_piece = match aux_data(m) {
                0 => "q",
                1 => "r",
                2 => "b",
                3 => "n",
                _ => panic!("invalid promoted piece code"),
            };
            format!("{}{}{}",
                    notation(orig_square),
                    notation(dest_square),
                    if move_type == MOVE_PROMOTION {
                        promoted_piece
                    } else {
                        ""
                    })

        } else {
            "0000".to_string()
        }
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("Alcibiades {}", VERSION)
    }

    fn author(&self) -> String {
        "Evgeni Pandurski".to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}

enum TimeManagement {
    MoveTime(u64),
    MoveTimeHint(u64),
    Nodes(NodeCount),
    Depth(u8),
    Infinite,
}
<|endoftext|>


<commit_before>
#[macro_export]
macro_rules! read_u8 {
    ($elf:ident, $io:ident) => (
        match $elf.ehdr.data {
            types::ELFDATA2LSB => { $io.read_le_u8() }
            types::ELFDATA2MSB => { $io.read_be_u8() }
            types::ELFDATANONE => { panic!("Unable to resolve file endianness"); }
            _ => { panic!("Unable to resolve file endianness"); }
        }
    );
}

#[macro_export]
macro_rules! read_u16 {
    ($elf:ident, $io:ident) => (
        match $elf.ehdr.data {
            types::ELFDATA2LSB => { $io.read_le_u16() }
            types::ELFDATA2MSB => { $io.read_be_u16() }
            types::ELFDATANONE => { panic!("Unable to resolve file endianness"); }
            _ => { panic!("Unable to resolve file endianness"); }
        }
    );
}

#[macro_export]
macro_rules! read_u32 {
    ($elf:ident, $io:ident) => (
        match $elf.ehdr.data {
            types::ELFDATA2LSB => { $io.read_le_u32() }
            types::ELFDATA2MSB => { $io.read_be_u32() }
            types::ELFDATANONE => { panic!("Unable to resolve file endianness"); }
            _ => { panic!("Unable to resolve file endianness"); }
        }
    );
}

#[macro_export]
macro_rules! read_u64 {
    ($elf:ident, $io:ident) => (
        match $elf.ehdr.data {
            types::ELFDATA2LSB => { $io.read_le_u64() }
            types::ELFDATA2MSB => { $io.read_be_u64() }
            types::ELFDATANONE => { panic!("Unable to resolve file endianness"); }
            _ => { panic!("Unable to resolve file endianness"); }
        }
    );
}

use std;
pub fn get_string(data: &Vec<u8>, start: usize) -> Result<String, std::string::FromUtf8Error> {
    let mut end: usize = 0;
    for i in start..data.len() {
        if data[i] == 0u8 {
            end = i;
            break;
        }
    }
    let mut rtn = String::with_capacity(end - start);
    for i in start..end {
        rtn.push(data[i] as char);
    }
    Ok(rtn)
}

<commit_msg>Remove utils macro.<commit_after><|endoftext|>


<commit_before>//! Useful stuff related to the spaceapi.

/// An ``Optional`` can contain ``Optional::Value<T>`` or ``Optional::Absent``.
/// It is similar to an ``Option``, but ``Optional::Absent`` means it will be
/// omitted when serialized, while ``None`` will be serialized to ``null``.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum Optional<T> {
    Value(T),
    Absent,
}

impl<T> Optional<T> {

    /// Moves the value `v` out of the `Optional<T>` if it is `Value(v)`.
    ///
    /// # Panics
    ///
    /// Panics if the self value equals `Absent`.
    ///
    /// # Safety note
    ///
    /// In general, because this function may panic, its use is discouraged.
    /// Instead, prefer to use pattern matching and handle the `Absent`
    /// case explicitly.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let x = Value("air");
    /// assert_eq!(x.unwrap(), "air");
    /// ```
    ///
    /// ```{.should_panic}
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let x: Optional<&str> = Absent;
    /// assert_eq!(x.unwrap(), "air"); // fails
    /// ```
    pub fn unwrap(self) -> T {
        match self {
            Optional::Value(val) => val,
            Optional::Absent => panic!("called `Optional::unwrap()` on a `Absent` value"),
        }
    }

    /// Returns the contained value or computes it from a closure.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let k = 10;
    /// assert_eq!(Value(4).unwrap_or_else(|| 2 * k), 4);
    /// assert_eq!(Absent.unwrap_or_else(|| 2 * k), 20);
    /// ```
    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
        match self {
            Optional::Value(x) => x,
            Optional::Absent => f()
        }
    }

    /// Maps an `Optional<T>` to `Optional<U>` by applying a function to a contained value
    ///
    /// # Examples
    ///
    /// Convert an `Optional<String>` into an `Optional<usize>`, consuming the original:
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let num_as_str: Optional<String> = Value("10".to_string());
    /// // `Optional::map` takes self *by value*, consuming `num_as_str`
    /// let num_as_int: Optional<usize> = num_as_str.map(|n| n.len());
    /// ```
    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Optional<U> {
        match self {
            Optional::Value(x) => Optional::Value(f(x)),
            Optional::Absent => Optional::Absent
        }
    }

    /// Applies a function to the contained value or returns a default.  see
    /// [`std::option::Option<T>::map_or`](http://doc.rust-lang.org/std/option/enum.Option.html#method.map_or)
    pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
        match self {
            Optional::Value(v) => f(v),
            Optional::Absent => def,
        }
    }

    /// Converts from `Optional<T>` to `Optional<&mut T>`
    pub fn as_mut<'r>(&'r mut self) -> Optional<&'r mut T> {
        match *self {
            Optional::Value(ref mut x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    /// Converts from `Optional<T>` to `Optional<&T>`
    pub fn as_ref<'r>(&'r self) -> Optional<&'r T> {
        match *self {
            Optional::Value(ref x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    /// Returns `Absent` if the optional is `Absent`, otherwise calls `f` with the
    /// wrapped value and returns the result.
    ///
    /// Some languages call this operation flatmap.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// fn sq(x: u32) -> Optional<u32> { Value(x * x) }
    /// fn nope(_: u32) -> Optional<u32> { Absent }
    ///
    /// assert_eq!(Value(2).and_then(sq).and_then(sq), Value(16));
    /// assert_eq!(Value(2).and_then(sq).and_then(nope), Absent);
    /// assert_eq!(Value(2).and_then(nope).and_then(sq), Absent);
    /// assert_eq!(Absent.and_then(sq).and_then(sq), Absent);
    /// ```
    pub fn and_then<U, F: FnOnce(T) -> Optional<U>>(self, f: F) -> Optional<U> {
        match self {
            Optional::Value(x) => f(x),
            Optional::Absent => Optional::Absent,
        }
    }

    /// Returns `true` if the optional is a `Absent` value
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let x: Optional<u32> = Value(2);
    /// assert_eq!(x.is_absent(), false);
    ///
    /// let x: Optional<u32> = Absent;
    /// assert_eq!(x.is_absent(), true);
    /// ```
    pub fn is_absent(&self) -> bool {
        match *self {
            Optional::Absent => true,
            _ => false
        }
    }

}
<commit_msg>Optional: Implement Into<Option<T>><commit_after>//! Useful stuff related to the spaceapi.

/// An ``Optional`` can contain ``Optional::Value<T>`` or ``Optional::Absent``.
/// It is similar to an ``Option``, but ``Optional::Absent`` means it will be
/// omitted when serialized, while ``None`` will be serialized to ``null``.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum Optional<T> {
    Value(T),
    Absent,
}

impl<T> Optional<T> {

    /// Moves the value `v` out of the `Optional<T>` if it is `Value(v)`.
    ///
    /// # Panics
    ///
    /// Panics if the self value equals `Absent`.
    ///
    /// # Safety note
    ///
    /// In general, because this function may panic, its use is discouraged.
    /// Instead, prefer to use pattern matching and handle the `Absent`
    /// case explicitly.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let x = Value("air");
    /// assert_eq!(x.unwrap(), "air");
    /// ```
    ///
    /// ```{.should_panic}
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let x: Optional<&str> = Absent;
    /// assert_eq!(x.unwrap(), "air"); // fails
    /// ```
    pub fn unwrap(self) -> T {
        match self {
            Optional::Value(val) => val,
            Optional::Absent => panic!("called `Optional::unwrap()` on a `Absent` value"),
        }
    }

    /// Returns the contained value or computes it from a closure.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let k = 10;
    /// assert_eq!(Value(4).unwrap_or_else(|| 2 * k), 4);
    /// assert_eq!(Absent.unwrap_or_else(|| 2 * k), 20);
    /// ```
    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
        match self {
            Optional::Value(x) => x,
            Optional::Absent => f()
        }
    }

    /// Maps an `Optional<T>` to `Optional<U>` by applying a function to a contained value
    ///
    /// # Examples
    ///
    /// Convert an `Optional<String>` into an `Optional<usize>`, consuming the original:
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let num_as_str: Optional<String> = Value("10".to_string());
    /// // `Optional::map` takes self *by value*, consuming `num_as_str`
    /// let num_as_int: Optional<usize> = num_as_str.map(|n| n.len());
    /// ```
    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Optional<U> {
        match self {
            Optional::Value(x) => Optional::Value(f(x)),
            Optional::Absent => Optional::Absent
        }
    }

    /// Applies a function to the contained value or returns a default.  see
    /// [`std::option::Option<T>::map_or`](http://doc.rust-lang.org/std/option/enum.Option.html#method.map_or)
    pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
        match self {
            Optional::Value(v) => f(v),
            Optional::Absent => def,
        }
    }

    /// Converts from `Optional<T>` to `Optional<&mut T>`
    pub fn as_mut<'r>(&'r mut self) -> Optional<&'r mut T> {
        match *self {
            Optional::Value(ref mut x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    /// Converts from `Optional<T>` to `Optional<&T>`
    pub fn as_ref<'r>(&'r self) -> Optional<&'r T> {
        match *self {
            Optional::Value(ref x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    /// Returns `Absent` if the optional is `Absent`, otherwise calls `f` with the
    /// wrapped value and returns the result.
    ///
    /// Some languages call this operation flatmap.
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// fn sq(x: u32) -> Optional<u32> { Value(x * x) }
    /// fn nope(_: u32) -> Optional<u32> { Absent }
    ///
    /// assert_eq!(Value(2).and_then(sq).and_then(sq), Value(16));
    /// assert_eq!(Value(2).and_then(sq).and_then(nope), Absent);
    /// assert_eq!(Value(2).and_then(nope).and_then(sq), Absent);
    /// assert_eq!(Absent.and_then(sq).and_then(sq), Absent);
    /// ```
    pub fn and_then<U, F: FnOnce(T) -> Optional<U>>(self, f: F) -> Optional<U> {
        match self {
            Optional::Value(x) => f(x),
            Optional::Absent => Optional::Absent,
        }
    }

    /// Returns `true` if the optional is a `Absent` value
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let x: Optional<u32> = Value(2);
    /// assert_eq!(x.is_absent(), false);
    ///
    /// let x: Optional<u32> = Absent;
    /// assert_eq!(x.is_absent(), true);
    /// ```
    pub fn is_absent(&self) -> bool {
        match *self {
            Optional::Absent => true,
            _ => false
        }
    }
}

impl<T> Into<Option<T>> for Optional<T> {
    /// Convert Optional<T> into Option<T>
    ///
    /// # Examples
    ///
    /// ```
    /// # use spaceapi::utils::Optional;
    /// # use spaceapi::utils::Optional::{Value,Absent};
    /// let x: Optional<u32> = Value(2);
    /// assert_eq!(Some(2), x.into());
    ///
    /// let x: Optional<u32> = Absent;
    /// assert_eq!(None, x.into());
    /// ```
    fn into(self) -> Option<T> {
        match self {
            Optional::Value(x) => Some(x),
            Optional::Absent => None,
        }
    }
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use libc::{c_void, c_int, c_char, c_double, c_ulong, c_uint};

#[repr(C)]
#[allow(dead_code)]
#[allow(non_camel_case_types)]
#[derive(Debug)]
pub enum op_stat_t {
    OP_STAT_UNKNOWN = 0,
    OP_STAT_OPERATIONAL,    // Operational           [+]
    OP_STAT_NONOP,          // Nonoperational        [-]
    OP_STAT_PARTIAL,        // Partially operational [P]
    OP_STAT_STDBY,          // Backup/Standby        [B]
    OP_STAT_SPARE,          // Spare                 [S]
    OP_STAT_EXTENDED,       // Extended Mission      [X]
}

#[repr(C)]
#[allow(dead_code)]
#[allow(non_camel_case_types)]
#[derive(Debug)]
pub enum orbit_type_t {
    ORBIT_TYPE_UNKNOWN = 0,
    ORBIT_TYPE_LEO,         // Low Earth orbit, up to 1200 km
    ORBIT_TYPE_ICO,         // Intermediate Circular Orbit, up to 1400 km
    ORBIT_TYPE_GEO,         // Geostationary
    ORBIT_TYPE_GSO,         // Geosynchronuous
    ORBIT_TYPE_MOLNIYA,
    ORBIT_TYPE_TUNDRA,
    ORBIT_TYPE_POLAR,
    ORBIT_TYPE_SUNSYNC,
    ORBIT_TYPE_DECAYED
}

#[repr(C)]
#[allow(dead_code, raw_pointer_derive)]
#[derive(Debug)]
pub struct qth_t {
    pub name:       *const c_char,  // Name, eg. callsign
    pub loc:        *const c_char,  // Location, eg City, Country
    pub desc:       *const c_char,  // Short description
    pub lat:        c_double,       // Latitude in dec. deg. North
    pub lon:        c_double,       // Longitude in dec. deg. East
    pub alt:        c_int,          // Altitude above sea level in meters
    pub qra:        *const c_char,  // QRA locator
    pub wx:         *const c_char,  // Weather station code (4 chars)
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Debug)]
pub struct tle_t {
    pub epoch:      c_double,       // Epoch Time in NORAD TLE format YYDDD.FFFFFFFF
    pub epoch_year: c_uint,         // Epoch: year
    pub epoch_day:  c_uint,         // Epoch: day of year
    pub epoch_fod:  c_double,       // Epoch: Fraction of day
    pub xndt2o:     c_double,       // 1. time derivative of mean motion
    pub xndd6o:     c_double,       // 2. time derivative of mean motion
    pub bstar:      c_double,       // Bstar drag coefficient
    pub xincl:      c_double,       // Inclination
    pub xnodeo:     c_double,       // R.A.A.N.
    pub eo:         c_double,       // Eccentricity
    pub omegao:     c_double,       // argument of perigee
    pub xmo:        c_double,       // mean anomaly
    pub xno:        c_double,       // mean motion

    pub catnr:      c_int,          // Catalogue Number
    pub elset:      c_int,          // Element Set number
    pub revnum:     c_int,          // Revolution Number at epoch

    pub sat_name:   [c_char; 25],   // Satellite name string
    pub idesg:      [c_char; 9],    // International Designator
    pub status:     op_stat_t,      // Operational status

    // values needed for squint calculations
    pub xincl1:     c_double,
    pub xnodeo1:    c_double,
    pub omegao1:    c_double,
}

#[repr(C)]
#[derive(Default, Debug)]
#[allow(dead_code)]
pub struct vector_t {
    pub x:          c_double,   // X component
    pub y:          c_double,   // Y component
    pub z:          c_double,   // Z component
    pub w:          c_double,   // Magnitude
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Default, Debug)]
/// Common arguments between deep-space functions
pub struct deep_arg_t {
    // Used by dpinit part of Deep()
    pub eosq:       c_double,
    pub sinio:      c_double,
    pub cosio:      c_double,
    pub betao:      c_double,
    pub aodp:       c_double,
    pub theta2:     c_double,
    pub sing:       c_double,
    pub cosg:       c_double,
    pub betao2:     c_double,
    pub xmdot:      c_double,
    pub omgdot:     c_double,
    pub xnodot:     c_double,
    pub xnodp:      c_double,

    // Used by dpsec and dpper parts of Deep()
    pub xll:        c_double,
    pub omgadf:     c_double,
    pub xnode:      c_double,
    pub em:         c_double,
    pub xinc:       c_double,
    pub xn:         c_double,
    pub t:          c_double,

    // Used by thetg and Deep()
    pub ds50:       c_double,
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Default, Debug)]
/// static data for SGP4 and SDP4
pub struct sgpsdp_static_t {
    pub aodp:       c_double,
    pub aycof:      c_double,
    pub c1:         c_double,
    pub c4:         c_double,
    pub c5:         c_double,
    pub cosio:      c_double,
    pub d2:         c_double,
    pub d3:         c_double,
    pub d4:         c_double,
    pub delmo:      c_double,
    pub omgcof:     c_double,

    pub eta:        c_double,
    pub omgdot:     c_double,
    pub sinio:      c_double,
    pub xnodp:      c_double,
    pub sinmo:      c_double,
    pub t2cof:      c_double,
    pub t3cof:      c_double,
    pub t4cof:      c_double,
    pub t5cof:      c_double,

    pub x1mth2:     c_double,
    pub x3thm1:     c_double,
    pub x7thm1:     c_double,
    pub xmcof:      c_double,
    pub xmdot:      c_double,
    pub xnodcf:     c_double,
    pub xnodot:     c_double,
    pub xlcof:      c_double,
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Default, Debug)]
/// static data for DEEP
pub struct deep_static_t {
    pub thgr:       c_double,
    pub xnq:        c_double,
    pub xqncl:      c_double,
    pub omegaq:     c_double,
    pub zmol:       c_double,
    pub zmos:       c_double,
    pub savtsn:     c_double,
    pub ee2:        c_double,
    pub e3:         c_double,
    pub xi2:        c_double,

    pub xl2:        c_double,
    pub xl3:        c_double,
    pub xl4:        c_double,
    pub xgh2:       c_double,
    pub xgh3:       c_double,
    pub xgh4:       c_double,
    pub xh2:        c_double,
    pub xh3:        c_double,
    pub sse:        c_double,
    pub ssi:        c_double,
    pub ssg:        c_double,
    pub xi3:        c_double,

    pub se2:        c_double,
    pub si2:        c_double,
    pub sl2:        c_double,
    pub sgh2:       c_double,
    pub sh2:        c_double,
    pub se3:        c_double,
    pub si3:        c_double,
    pub sl3:        c_double,
    pub sgh3:       c_double,
    pub sh3:        c_double,
    pub sl4:        c_double,
    pub sgh4:       c_double,

    pub ssl:        c_double,
    pub ssh:        c_double,
    pub d3210:      c_double,
    pub d3222:      c_double,
    pub d4410:      c_double,
    pub d4422:      c_double,
    pub d5220:      c_double,
    pub d5232:      c_double,
    pub d5421:      c_double,

    pub d5433:      c_double,
    pub del1:       c_double,
    pub del2:       c_double,
    pub del3:       c_double,
    pub fasx2:      c_double,
    pub fasx4:      c_double,
    pub fasx6:      c_double,
    pub xlamo:      c_double,
    pub xfact:      c_double,

    pub xni:        c_double,
    pub atime:      c_double,
    pub stepp:      c_double,
    pub stepn:      c_double,
    pub step2:      c_double,
    pub preep:      c_double,
    pub pl:         c_double,
    pub sghs:       c_double,
    pub xli:        c_double,

    pub d2201:      c_double,
    pub d2211:      c_double,
    pub sghl:       c_double,
    pub sh1:        c_double,
    pub pinc:       c_double,
    pub pe:         c_double,
    pub shs:        c_double,
    pub zsingl:     c_double,
    pub zcosgl:     c_double,

    pub zsinhl:     c_double,
    pub zcoshl:     c_double,
    pub zsinil:     c_double,
    pub zcosil:     c_double,

}

#[repr(C)]
#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct sat_t {
    pub name:       *const c_char,
    pub nickname:   *const c_char,
    pub website:    *const c_char,
    pub tle:        tle_t,          // Keplerian elements
    pub flags:      c_int,          // Flags for algo ctrl
    pub sgps:       sgpsdp_static_t,
    pub dps:        deep_static_t,
    pub deep_arg:   deep_arg_t,
    pub pos:        vector_t,       // Raw position and range
    pub vel:        vector_t,       // Raw velocity

    pub jul_epoch:  c_double,
    pub jul_utc:    c_double,
    pub tsince:     c_double,
    pub aos:        c_double,       // Next AOS
    pub los:        c_double,       // Next LO

    pub az:         c_double,       // Azimuth [deg]
    pub el:         c_double,       // Elevation [deg]
    pub range:      c_double,       // Range [km]
    pub range_rate: c_double,       // Range Rate [km/sec]
    pub ra:         c_double,       // Right Ascension [deg]
    pub dec:        c_double,       // Declination [deg]
    pub ssplat:     c_double,       // SSP latitude [deg]
    pub ssplon:     c_double,       // SSP longitude [deg]
    pub alt:        c_double,       // altitude [km]
    pub velo:       c_double,       // velocity [km/s]
    pub ma:         c_double,       // mean anomaly
    pub footprint:  c_double,       // footprint
    pub phase:      c_double,       // orbit phase
    pub meanmo:     c_double,       // mean motion kept in rev/day
    pub orbit:      c_ulong,        // orbit number
    pub otype:      orbit_type_t    // orbit type
}

#[link(name = "gpredict")]
extern {
    pub fn get_current_daynum() -> c_double;
    pub fn predict_calc(sat: *mut sat_t, qth: *mut qth_t, t: c_double) -> c_void;
    pub fn find_aos(sat: *mut sat_t, qth: *mut qth_t, start: c_double, maxdt: c_double) -> c_double;
    pub fn find_los(sat: *mut sat_t, qth: *mut qth_t, start: c_double, maxdt: c_double) -> c_double;

    pub fn Get_Next_Tle_Set(line: *const c_char, tle: *mut tle_t) -> c_int;
    pub fn select_ephemeris(sat: *mut sat_t) -> c_void;
    pub fn gtk_sat_data_init_sat(sat: *mut sat_t, sat: *mut qth_t) -> c_void;
}
<commit_msg>add Clone to all ffi structs<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

use libc::{c_void, c_int, c_char, c_double, c_ulong, c_uint};

#[repr(C)]
#[allow(dead_code)]
#[allow(non_camel_case_types)]
#[derive(Debug, Clone)]
pub enum op_stat_t {
    OP_STAT_UNKNOWN = 0,
    OP_STAT_OPERATIONAL,    // Operational           [+]
    OP_STAT_NONOP,          // Nonoperational        [-]
    OP_STAT_PARTIAL,        // Partially operational [P]
    OP_STAT_STDBY,          // Backup/Standby        [B]
    OP_STAT_SPARE,          // Spare                 [S]
    OP_STAT_EXTENDED,       // Extended Mission      [X]
}

#[repr(C)]
#[allow(dead_code)]
#[allow(non_camel_case_types)]
#[derive(Debug, Clone)]
pub enum orbit_type_t {
    ORBIT_TYPE_UNKNOWN = 0,
    ORBIT_TYPE_LEO,         // Low Earth orbit, up to 1200 km
    ORBIT_TYPE_ICO,         // Intermediate Circular Orbit, up to 1400 km
    ORBIT_TYPE_GEO,         // Geostationary
    ORBIT_TYPE_GSO,         // Geosynchronuous
    ORBIT_TYPE_MOLNIYA,
    ORBIT_TYPE_TUNDRA,
    ORBIT_TYPE_POLAR,
    ORBIT_TYPE_SUNSYNC,
    ORBIT_TYPE_DECAYED
}

#[repr(C)]
#[allow(dead_code, raw_pointer_derive)]
#[derive(Debug, Clone)]
pub struct qth_t {
    pub name:       *const c_char,  // Name, eg. callsign
    pub loc:        *const c_char,  // Location, eg City, Country
    pub desc:       *const c_char,  // Short description
    pub lat:        c_double,       // Latitude in dec. deg. North
    pub lon:        c_double,       // Longitude in dec. deg. East
    pub alt:        c_int,          // Altitude above sea level in meters
    pub qra:        *const c_char,  // QRA locator
    pub wx:         *const c_char,  // Weather station code (4 chars)
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct tle_t {
    pub epoch:      c_double,       // Epoch Time in NORAD TLE format YYDDD.FFFFFFFF
    pub epoch_year: c_uint,         // Epoch: year
    pub epoch_day:  c_uint,         // Epoch: day of year
    pub epoch_fod:  c_double,       // Epoch: Fraction of day
    pub xndt2o:     c_double,       // 1. time derivative of mean motion
    pub xndd6o:     c_double,       // 2. time derivative of mean motion
    pub bstar:      c_double,       // Bstar drag coefficient
    pub xincl:      c_double,       // Inclination
    pub xnodeo:     c_double,       // R.A.A.N.
    pub eo:         c_double,       // Eccentricity
    pub omegao:     c_double,       // argument of perigee
    pub xmo:        c_double,       // mean anomaly
    pub xno:        c_double,       // mean motion

    pub catnr:      c_int,          // Catalogue Number
    pub elset:      c_int,          // Element Set number
    pub revnum:     c_int,          // Revolution Number at epoch

    pub sat_name:   [c_char; 25],   // Satellite name string
    pub idesg:      [c_char; 9],    // International Designator
    pub status:     op_stat_t,      // Operational status

    // values needed for squint calculations
    pub xincl1:     c_double,
    pub xnodeo1:    c_double,
    pub omegao1:    c_double,
}

#[repr(C)]
#[derive(Default, Debug, Clone)]
#[allow(dead_code)]
pub struct vector_t {
    pub x:          c_double,   // X component
    pub y:          c_double,   // Y component
    pub z:          c_double,   // Z component
    pub w:          c_double,   // Magnitude
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Default, Debug, Clone)]
/// Common arguments between deep-space functions
pub struct deep_arg_t {
    // Used by dpinit part of Deep()
    pub eosq:       c_double,
    pub sinio:      c_double,
    pub cosio:      c_double,
    pub betao:      c_double,
    pub aodp:       c_double,
    pub theta2:     c_double,
    pub sing:       c_double,
    pub cosg:       c_double,
    pub betao2:     c_double,
    pub xmdot:      c_double,
    pub omgdot:     c_double,
    pub xnodot:     c_double,
    pub xnodp:      c_double,

    // Used by dpsec and dpper parts of Deep()
    pub xll:        c_double,
    pub omgadf:     c_double,
    pub xnode:      c_double,
    pub em:         c_double,
    pub xinc:       c_double,
    pub xn:         c_double,
    pub t:          c_double,

    // Used by thetg and Deep()
    pub ds50:       c_double,
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Default, Debug, Clone)]
/// static data for SGP4 and SDP4
pub struct sgpsdp_static_t {
    pub aodp:       c_double,
    pub aycof:      c_double,
    pub c1:         c_double,
    pub c4:         c_double,
    pub c5:         c_double,
    pub cosio:      c_double,
    pub d2:         c_double,
    pub d3:         c_double,
    pub d4:         c_double,
    pub delmo:      c_double,
    pub omgcof:     c_double,

    pub eta:        c_double,
    pub omgdot:     c_double,
    pub sinio:      c_double,
    pub xnodp:      c_double,
    pub sinmo:      c_double,
    pub t2cof:      c_double,
    pub t3cof:      c_double,
    pub t4cof:      c_double,
    pub t5cof:      c_double,

    pub x1mth2:     c_double,
    pub x3thm1:     c_double,
    pub x7thm1:     c_double,
    pub xmcof:      c_double,
    pub xmdot:      c_double,
    pub xnodcf:     c_double,
    pub xnodot:     c_double,
    pub xlcof:      c_double,
}

#[repr(C)]
#[allow(dead_code)]
#[derive(Default, Debug, Clone)]
/// static data for DEEP
pub struct deep_static_t {
    pub thgr:       c_double,
    pub xnq:        c_double,
    pub xqncl:      c_double,
    pub omegaq:     c_double,
    pub zmol:       c_double,
    pub zmos:       c_double,
    pub savtsn:     c_double,
    pub ee2:        c_double,
    pub e3:         c_double,
    pub xi2:        c_double,

    pub xl2:        c_double,
    pub xl3:        c_double,
    pub xl4:        c_double,
    pub xgh2:       c_double,
    pub xgh3:       c_double,
    pub xgh4:       c_double,
    pub xh2:        c_double,
    pub xh3:        c_double,
    pub sse:        c_double,
    pub ssi:        c_double,
    pub ssg:        c_double,
    pub xi3:        c_double,

    pub se2:        c_double,
    pub si2:        c_double,
    pub sl2:        c_double,
    pub sgh2:       c_double,
    pub sh2:        c_double,
    pub se3:        c_double,
    pub si3:        c_double,
    pub sl3:        c_double,
    pub sgh3:       c_double,
    pub sh3:        c_double,
    pub sl4:        c_double,
    pub sgh4:       c_double,

    pub ssl:        c_double,
    pub ssh:        c_double,
    pub d3210:      c_double,
    pub d3222:      c_double,
    pub d4410:      c_double,
    pub d4422:      c_double,
    pub d5220:      c_double,
    pub d5232:      c_double,
    pub d5421:      c_double,

    pub d5433:      c_double,
    pub del1:       c_double,
    pub del2:       c_double,
    pub del3:       c_double,
    pub fasx2:      c_double,
    pub fasx4:      c_double,
    pub fasx6:      c_double,
    pub xlamo:      c_double,
    pub xfact:      c_double,

    pub xni:        c_double,
    pub atime:      c_double,
    pub stepp:      c_double,
    pub stepn:      c_double,
    pub step2:      c_double,
    pub preep:      c_double,
    pub pl:         c_double,
    pub sghs:       c_double,
    pub xli:        c_double,

    pub d2201:      c_double,
    pub d2211:      c_double,
    pub sghl:       c_double,
    pub sh1:        c_double,
    pub pinc:       c_double,
    pub pe:         c_double,
    pub shs:        c_double,
    pub zsingl:     c_double,
    pub zcosgl:     c_double,

    pub zsinhl:     c_double,
    pub zcoshl:     c_double,
    pub zsinil:     c_double,
    pub zcosil:     c_double,

}

#[repr(C)]
#[allow(raw_pointer_derive)]
#[derive(Debug, Clone)]
pub struct sat_t {
    pub name:       *const c_char,
    pub nickname:   *const c_char,
    pub website:    *const c_char,
    pub tle:        tle_t,          // Keplerian elements
    pub flags:      c_int,          // Flags for algo ctrl
    pub sgps:       sgpsdp_static_t,
    pub dps:        deep_static_t,
    pub deep_arg:   deep_arg_t,
    pub pos:        vector_t,       // Raw position and range
    pub vel:        vector_t,       // Raw velocity

    pub jul_epoch:  c_double,
    pub jul_utc:    c_double,
    pub tsince:     c_double,
    pub aos:        c_double,       // Next AOS
    pub los:        c_double,       // Next LO

    pub az:         c_double,       // Azimuth [deg]
    pub el:         c_double,       // Elevation [deg]
    pub range:      c_double,       // Range [km]
    pub range_rate: c_double,       // Range Rate [km/sec]
    pub ra:         c_double,       // Right Ascension [deg]
    pub dec:        c_double,       // Declination [deg]
    pub ssplat:     c_double,       // SSP latitude [deg]
    pub ssplon:     c_double,       // SSP longitude [deg]
    pub alt:        c_double,       // altitude [km]
    pub velo:       c_double,       // velocity [km/s]
    pub ma:         c_double,       // mean anomaly
    pub footprint:  c_double,       // footprint
    pub phase:      c_double,       // orbit phase
    pub meanmo:     c_double,       // mean motion kept in rev/day
    pub orbit:      c_ulong,        // orbit number
    pub otype:      orbit_type_t    // orbit type
}

#[link(name = "gpredict")]
extern {
    pub fn get_current_daynum() -> c_double;
    pub fn predict_calc(sat: *mut sat_t, qth: *mut qth_t, t: c_double) -> c_void;
    pub fn find_aos(sat: *mut sat_t, qth: *mut qth_t, start: c_double, maxdt: c_double) -> c_double;
    pub fn find_los(sat: *mut sat_t, qth: *mut qth_t, start: c_double, maxdt: c_double) -> c_double;

    pub fn Get_Next_Tle_Set(line: *const c_char, tle: *mut tle_t) -> c_int;
    pub fn select_ephemeris(sat: *mut sat_t) -> c_void;
    pub fn gtk_sat_data_init_sat(sat: *mut sat_t, sat: *mut qth_t) -> c_void;
}
<|endoftext|>


<commit_before><commit_msg>removed cruft<commit_after><|endoftext|>


<commit_before>use image_convert::image_to_surface;
use scene::{SceneName, SceneChangeEvent, BoxedScene, Scene};
use cgmath::Point2;
use ggez::Context;
use ggez::graphics::{self, Canvas, Text, DrawParam, Image, Color};
use ggez::event::{KeyCode, KeyMods, MouseButton};
use ggez::conf::{NumSamples};
use std::io::Result;
use uorustlibs::hues::{HueReader, HueGroup, Hue};
use uorustlibs::color::Color as ColorTrait;
use std::fs::File;
use std::io::Error;
use std::path::Path;

static HEIGHT:f32 = 8.0;

pub struct HuesScene {
    reader: Result<HueReader<File>>,
    index: u32,
    texture: Option<Canvas>,
    exiting: bool,
}

impl<'a> HuesScene {
    pub fn new(ctx: &mut Context) -> BoxedScene<'a, SceneName, ()> {
        let mut scene = Box::new(HuesScene {
            reader: HueReader::new(&Path::new("./assets/hues.mul")),
            texture: None,
            index: 0,
            exiting: false,
        });
        scene.load_group(ctx);
        scene
    }

    fn load_group(&mut self, ctx: &mut Context) {
        let mut dest = Canvas::with_window_size(ctx).unwrap();
        let maybe_group = match self.reader {
            Ok(ref mut hue_reader) => {
                hue_reader.read_hue_group(self.index)
            },
            Err(ref x) => Err(Error::new(x.kind(), "Whoops"))
        };
        match maybe_group {
            Ok(group) => {
                let drawn_group = self.draw_hue_group(ctx, self.index, &group);
                graphics::set_canvas(ctx, Some(&dest));
                graphics::clear(ctx, graphics::BLACK);
                graphics::draw(ctx, &drawn_group, DrawParam::default()).expect("Failed to blit texture");
                graphics::set_canvas(ctx, None);
            },
            Err(_) => {
                graphics::set_canvas(ctx, Some(&dest));
                graphics::clear(ctx, graphics::BLACK);
                graphics::set_canvas(ctx, None);
            }
        };
        self.texture = Some(dest);
    }

    fn draw_hue_group(&self, ctx: &mut Context, group_idx: u32, group: &HueGroup) -> Image {
        let mut dest = Canvas::new(ctx, 256, HEIGHT as u16 * 9, NumSamples::One).unwrap();
        graphics::set_canvas(ctx, Some(&dest));
        graphics::clear(ctx, graphics::BLACK);
        for (idx, hue) in group.entries.iter().enumerate() {
            let drawn_hue = self.draw_hue(ctx, &hue);
            graphics::draw(ctx, &drawn_hue, DrawParam::default().dest(Point2::new(0.0, (idx * drawn_hue.height() as usize) as f32))).unwrap();
        }
        let label = Text::new(format!("Group {} - {}", group_idx, group.header));
        graphics::draw(ctx, &label, (Point2::new(0.0, HEIGHT * 8.0 + 4.0), graphics::WHITE));
        graphics::set_canvas(ctx, None);
        dest.into_inner()
    }

    fn draw_hue(&self, ctx: &mut Context, hue: &Hue) -> Image {
        let mut dest = Canvas::new(ctx, 256, HEIGHT as u16, NumSamples::One).unwrap();
        graphics::set_canvas(ctx, Some(&dest));
        graphics::clear(ctx, graphics::WHITE);
        /*for (col_idx, &color) in hue.color_table.iter().enumerate() {
            let (r, g, b, _) = color.to_rgba();
            let rect = graphics::Rect::new(col_idx as f32 * 16.0, 0.0, 16.0, HEIGHT);
            let r1 = graphics::Mesh::new_rectangle(ctx, graphics::DrawMode::fill(), rect, Color::from_rgba(r, g, b, 255)).unwrap();
            graphics::draw(ctx, &r1, DrawParam::default()).unwrap();
        };*/
        let label_text = format!("{}: {} - {}", if hue.name.trim().len() > 0 { &hue.name } else { "NONE" }, hue.table_start, hue.table_end);
        let label = Text::new(format!("{}", label_text));
        graphics::draw(ctx, &label, (Point2::new(0.0, 48.0), graphics::WHITE));
        graphics::set_canvas(ctx, None);
        dest.into_inner()
    }
}

impl Scene<SceneName, ()> for HuesScene {
    fn draw(&mut self, ctx: &mut Context, engine_data: &mut ()) {
        match self.texture {
            Some(ref texture) => {
                graphics::draw(ctx, texture, DrawParam::default()).unwrap();
            },
            None => ()
        };
    }

    fn update(&mut self, ctx: &mut Context, engine_data: &mut ()) -> Option<SceneChangeEvent<SceneName>> {
        if self.exiting {
            Some(SceneChangeEvent::PopScene)
        } else {
            None
        }
    }

    fn key_down_event(
        &mut self,
        ctx: &mut Context,
        keycode: KeyCode,
        keymods: KeyMods,
        repeat: bool,
        engine_data: &mut ()
    ) {
        match keycode {
            KeyCode::Escape => {
                self.exiting = true
            },
            KeyCode::Left => {
                if self.index > 0 {
                    self.index -= 1;
                    self.load_group(ctx);
                }
            },
            KeyCode::Right => {
                self.index += 1;
                self.load_group(ctx);
            },
            _ => ()
        }
    }
}
<commit_msg>Simplify and correct hue scene<commit_after>use image_convert::image_to_surface;
use scene::{SceneName, SceneChangeEvent, BoxedScene, Scene};
use cgmath::Point2;
use ggez::Context;
use ggez::graphics::{self, Canvas, Text, DrawParam, Image, Color};
use ggez::event::{KeyCode, KeyMods, MouseButton};
use ggez::conf::{NumSamples};
use std::io::Result;
use uorustlibs::hues::{HueReader, HueGroup, Hue};
use uorustlibs::color::Color as ColorTrait;
use std::fs::File;
use std::io::Error;
use std::path::Path;

static HEIGHT:f32 = 16.0;

pub struct HuesScene {
    reader: Result<HueReader<File>>,
    index: u32,
    texture: Option<Canvas>,
    exiting: bool,
}

impl<'a> HuesScene {
    pub fn new(ctx: &mut Context) -> BoxedScene<'a, SceneName, ()> {
        let mut scene = Box::new(HuesScene {
            reader: HueReader::new(&Path::new("./assets/hues.mul")),
            texture: None,
            index: 0,
            exiting: false,
        });
        scene.load_group(ctx);
        scene
    }

    fn load_group(&mut self, ctx: &mut Context) {
        let mut dest = Canvas::with_window_size(ctx).unwrap();
        let maybe_group = match self.reader {
            Ok(ref mut hue_reader) => {
                hue_reader.read_hue_group(self.index)
            },
            Err(ref x) => Err(Error::new(x.kind(), "Whoops"))
        };
        match maybe_group {
            Ok(group) => {
                graphics::set_canvas(ctx, Some(&dest));
                graphics::clear(ctx, graphics::BLACK);
                let drawn_group = self.draw_hue_group(ctx, self.index, &group);
                graphics::set_canvas(ctx, None);
            },
            Err(_) => {
                graphics::set_canvas(ctx, Some(&dest));
                graphics::clear(ctx, graphics::BLACK);
                graphics::set_canvas(ctx, None);
            }
        };
        self.texture = Some(dest);
    }

    fn draw_hue_group(&self, ctx: &mut Context, group_idx: u32, group: &HueGroup) {
        for (idx, hue) in group.entries.iter().enumerate() {
            let drawn_hue = self.draw_hue(ctx, &hue, idx as u32);
        }
        let label = Text::new(format!("Group {} - {}", group_idx, group.header));
        graphics::draw(ctx, &label, (Point2::new(0.0, HEIGHT * 8.0 + 4.0), graphics::WHITE));
    }

    fn draw_hue(&self, ctx: &mut Context, hue: &Hue, hue_idx: u32) {
        for (col_idx, &color) in hue.color_table.iter().enumerate() {
            let (r, g, b, _) = color.to_rgba();
            let rect = graphics::Rect::new(col_idx as f32 * 16.0, hue_idx as f32 * HEIGHT, 16.0, HEIGHT);
            let r1 = graphics::Mesh::new_rectangle(ctx, graphics::DrawMode::fill(), rect, Color::from_rgba(r, g, b, 255)).unwrap();
            graphics::draw(ctx, &r1, DrawParam::default()).unwrap();
        };
        let label_text = format!("{}: {} - {}", if hue.name.trim().len() > 0 { &hue.name } else { "NONE" }, hue.table_start, hue.table_end);
        let label = Text::new(format!("{}", label_text));
        graphics::draw(ctx, &label, (Point2::new(hue.color_table.len() as f32 * 16.0, hue_idx as f32 * HEIGHT), graphics::WHITE));
    }
}

impl Scene<SceneName, ()> for HuesScene {
    fn draw(&mut self, ctx: &mut Context, engine_data: &mut ()) {
        match self.texture {
            Some(ref texture) => {
                graphics::draw(ctx, texture, DrawParam::default()).unwrap();
            },
            None => ()
        };
    }

    fn update(&mut self, ctx: &mut Context, engine_data: &mut ()) -> Option<SceneChangeEvent<SceneName>> {
        if self.exiting {
            Some(SceneChangeEvent::PopScene)
        } else {
            None
        }
    }

    fn key_down_event(
        &mut self,
        ctx: &mut Context,
        keycode: KeyCode,
        keymods: KeyMods,
        repeat: bool,
        engine_data: &mut ()
    ) {
        match keycode {
            KeyCode::Escape => {
                self.exiting = true
            },
            KeyCode::Left => {
                if self.index > 0 {
                    self.index -= 1;
                    self.load_group(ctx);
                }
            },
            KeyCode::Right => {
                self.index += 1;
                self.load_group(ctx);
            },
            _ => ()
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014-2016 bluss and ndarray developers.
//
// 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.

use imp_prelude::*;
use dimension::{self, stride_offset};
use error::ShapeError;

use StrideShape;

/// # Methods for Array Views
///
/// Methods for read-only array views `ArrayView<'a, A, D>`
///
/// Note that array views implement traits like [`From`][f] and `IntoIterator` too.
/// [f]: #method.from
impl<'a, A, D> ArrayBase<ViewRepr<&'a A>, D>
    where D: Dimension,
{
    /// Create a read-only array view borrowing its data from a slice.
    ///
    /// Checks whether `shape` are compatible with the slice's
    /// length, returning an `Err` if not compatible.
    ///
    /// ```
    /// use ndarray::ArrayView;
    /// use ndarray::arr3;
    /// use ndarray::ShapeBuilder;
    ///
    /// let s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
    /// let a = ArrayView::from_shape((2, 3, 2).strides((1, 4, 2)),
    ///                               &s).unwrap();
    ///
    /// assert!(
    ///     a == arr3(&[[[0, 2],
    ///                  [4, 6],
    ///                  [8, 10]],
    ///                 [[1, 3],
    ///                  [5, 7],
    ///                  [9, 11]]])
    /// );
    /// assert!(a.strides() == &[1, 4, 2]);
    /// ```
    pub fn from_shape<Sh>(shape: Sh, xs: &'a [A])
        -> Result<Self, ShapeError>
        where Sh: Into<StrideShape<D>>,
    {
        let shape = shape.into();
        let dim = shape.dim;
        let strides = shape.strides;
        dimension::can_index_slice(xs, &dim, &strides).map(|_| {
            unsafe {
                Self::new_(xs.as_ptr(), dim, strides)
            }
        })
    }

    /// Create an `ArrayView<A, D>` from shape information and a
    /// raw pointer to the elements.
    ///
    /// Unsafe because caller is responsible for ensuring that the pointer is
    /// valid, not mutable aliased and coherent with the dim and stride information.
    pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *const A) -> Self
        where Sh: Into<StrideShape<D>>
    {
        let shape = shape.into();
        let dim = shape.dim;
        let strides = shape.strides;
        ArrayView::new_(ptr, dim, strides)
    }

    /// Split the array along `axis` and return one view strictly before the
    /// split and one view after the split.
    ///
    /// **Panics** if `axis` or `index` is out of bounds.
    ///
    /// Below, an illustration of `.split_at(Axis(2), 2)` on
    /// an array with shape 3 × 5 × 5.
    ///
    ///
    pub fn split_at(self, axis: Axis, index: Ix)
        -> (Self, Self)
    {
        // NOTE: Keep this in sync with the ArrayViewMut version
        assert!(index <= self.shape().axis(axis));
        let left_ptr = self.ptr;
        let right_ptr = if index == self.shape().axis(axis) {
            self.ptr
        } else {
            let offset = stride_offset(index, self.strides.axis(axis));
            unsafe {
                self.ptr.offset(offset)
            }
        };

        let mut dim_left = self.dim.clone();
        dim_left.set_axis(axis, index);
        let left = unsafe {
            Self::new_(left_ptr, dim_left, self.strides.clone())
        };

        let mut dim_right = self.dim;
        let right_len  = dim_right.axis(axis) - index;
        dim_right.set_axis(axis, right_len);
        let right = unsafe {
            Self::new_(right_ptr, dim_right, self.strides)
        };

        (left, right)
    }

}

/// Methods for read-write array views `ArrayViewMut<'a, A, D>`
///
/// Note that array views implement traits like [`From`][f] and `IntoIterator` too.
///
/// [f]: #method.from
impl<'a, A, D> ArrayBase<ViewRepr<&'a mut A>, D>
    where D: Dimension,
{
    /// Create a read-write array view borrowing its data from a slice.
    ///
    /// Checks whether `dim` and `strides` are compatible with the slice's
    /// length, returning an `Err` if not compatible.
    ///
    /// ```
    /// use ndarray::ArrayViewMut;
    /// use ndarray::arr3;
    /// use ndarray::ShapeBuilder;
    ///
    /// let mut s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
    /// let mut a = ArrayViewMut::from_shape((2, 3, 2).strides((1, 4, 2)),
    ///                                      &mut s).unwrap();
    ///
    /// a[[0, 0, 0]] = 1;
    /// assert!(
    ///     a == arr3(&[[[1, 2],
    ///                  [4, 6],
    ///                  [8, 10]],
    ///                 [[1, 3],
    ///                  [5, 7],
    ///                  [9, 11]]])
    /// );
    /// assert!(a.strides() == &[1, 4, 2]);
    /// ```
    pub fn from_shape<Sh>(shape: Sh, xs: &'a mut [A])
        -> Result<Self, ShapeError>
        where Sh: Into<StrideShape<D>>,
    {
        let shape = shape.into();
        let dim = shape.dim;
        let strides = shape.strides;
        dimension::can_index_slice(xs, &dim, &strides).map(|_| {
            unsafe {
                Self::new_(xs.as_mut_ptr(), dim, strides)
            }
        })
    }

    /// Create an `ArrayViewMut<A, D>` from shape information and a
    /// raw pointer to the elements.
    ///
    /// Unsafe because caller is responsible for ensuring that the pointer is
    /// valid, not aliased and coherent with the dim and stride information.
    pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *mut A) -> Self
        where Sh: Into<StrideShape<D>>
    {
        let shape = shape.into();
        let dim = shape.dim;
        let strides = shape.strides;
        ArrayViewMut::new_(ptr, dim, strides)
    }

    /// Split the array along `axis` and return one mutable view strictly
    /// before the split and one mutable view after the split.
    ///
    /// **Panics** if `axis` or `index` is out of bounds.
    pub fn split_at(self, axis: Axis, index: Ix)
        -> (Self, Self)
    {
        // NOTE: Keep this in sync with the ArrayView version
        assert!(index <= self.shape().axis(axis));
        let left_ptr = self.ptr;
        let right_ptr = if index == self.shape().axis(axis) {
            self.ptr
        } else {
            let offset = stride_offset(index, self.strides.axis(axis));
            unsafe {
                self.ptr.offset(offset)
            }
        };

        let mut dim_left = self.dim.clone();
        dim_left.set_axis(axis, index);
        let left = unsafe {
            Self::new_(left_ptr, dim_left, self.strides.clone())
        };

        let mut dim_right = self.dim;
        let right_len  = dim_right.axis(axis) - index;
        dim_right.set_axis(axis, right_len);
        let right = unsafe {
            Self::new_(right_ptr, dim_right, self.strides)
        };

        (left, right)
    }

}

<commit_msg>doc: language care<commit_after>// Copyright 2014-2016 bluss and ndarray developers.
//
// 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.

use imp_prelude::*;
use dimension::{self, stride_offset};
use error::ShapeError;

use StrideShape;

/// # Methods for Array Views
///
/// Methods for read-only array views `ArrayView<'a, A, D>`
///
/// Note that array views implement traits like [`From`][f] and `IntoIterator` too.
/// [f]: #method.from
impl<'a, A, D> ArrayBase<ViewRepr<&'a A>, D>
    where D: Dimension,
{
    /// Create a read-only array view borrowing its data from a slice.
    ///
    /// Checks whether `shape` are compatible with the slice's
    /// length, returning an `Err` if not compatible.
    ///
    /// ```
    /// use ndarray::ArrayView;
    /// use ndarray::arr3;
    /// use ndarray::ShapeBuilder;
    ///
    /// let s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
    /// let a = ArrayView::from_shape((2, 3, 2).strides((1, 4, 2)),
    ///                               &s).unwrap();
    ///
    /// assert!(
    ///     a == arr3(&[[[0, 2],
    ///                  [4, 6],
    ///                  [8, 10]],
    ///                 [[1, 3],
    ///                  [5, 7],
    ///                  [9, 11]]])
    /// );
    /// assert!(a.strides() == &[1, 4, 2]);
    /// ```
    pub fn from_shape<Sh>(shape: Sh, xs: &'a [A])
        -> Result<Self, ShapeError>
        where Sh: Into<StrideShape<D>>,
    {
        let shape = shape.into();
        let dim = shape.dim;
        let strides = shape.strides;
        dimension::can_index_slice(xs, &dim, &strides).map(|_| {
            unsafe {
                Self::new_(xs.as_ptr(), dim, strides)
            }
        })
    }

    /// Create an `ArrayView<A, D>` from shape information and a
    /// raw pointer to the elements.
    ///
    /// Unsafe because caller is responsible for ensuring that the pointer is
    /// valid, not mutably aliased and coherent with the dimension and stride information.
    pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *const A) -> Self
        where Sh: Into<StrideShape<D>>
    {
        let shape = shape.into();
        let dim = shape.dim;
        let strides = shape.strides;
        ArrayView::new_(ptr, dim, strides)
    }

    /// Split the array along `axis` and return one view strictly before the
    /// split and one view after the split.
    ///
    /// **Panics** if `axis` or `index` is out of bounds.
    ///
    /// Below, an illustration of `.split_at(Axis(2), 2)` on
    /// an array with shape 3 × 5 × 5.
    ///
    ///
    pub fn split_at(self, axis: Axis, index: Ix)
        -> (Self, Self)
    {
        // NOTE: Keep this in sync with the ArrayViewMut version
        assert!(index <= self.shape().axis(axis));
        let left_ptr = self.ptr;
        let right_ptr = if index == self.shape().axis(axis) {
            self.ptr
        } else {
            let offset = stride_offset(index, self.strides.axis(axis));
            unsafe {
                self.ptr.offset(offset)
            }
        };

        let mut dim_left = self.dim.clone();
        dim_left.set_axis(axis, index);
        let left = unsafe {
            Self::new_(left_ptr, dim_left, self.strides.clone())
        };

        let mut dim_right = self.dim;
        let right_len  = dim_right.axis(axis) - index;
        dim_right.set_axis(axis, right_len);
        let right = unsafe {
            Self::new_(right_ptr, dim_right, self.strides)
        };

        (left, right)
    }

}

/// Methods for read-write array views `ArrayViewMut<'a, A, D>`
///
/// Note that array views implement traits like [`From`][f] and `IntoIterator` too.
///
/// [f]: #method.from
impl<'a, A, D> ArrayBase<ViewRepr<&'a mut A>, D>
    where D: Dimension,
{
    /// Create a read-write array view borrowing its data from a slice.
    ///
    /// Checks whether `dim` and `strides` are compatible with the slice's
    /// length, returning an `Err` if not compatible.
    ///
    /// ```
    /// use ndarray::ArrayViewMut;
    /// use ndarray::arr3;
    /// use ndarray::ShapeBuilder;
    ///
    /// let mut s = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
    /// let mut a = ArrayViewMut::from_shape((2, 3, 2).strides((1, 4, 2)),
    ///                                      &mut s).unwrap();
    ///
    /// a[[0, 0, 0]] = 1;
    /// assert!(
    ///     a == arr3(&[[[1, 2],
    ///                  [4, 6],
    ///                  [8, 10]],
    ///                 [[1, 3],
    ///                  [5, 7],
    ///                  [9, 11]]])
    /// );
    /// assert!(a.strides() == &[1, 4, 2]);
    /// ```
    pub fn from_shape<Sh>(shape: Sh, xs: &'a mut [A])
        -> Result<Self, ShapeError>
        where Sh: Into<StrideShape<D>>,
    {
        let shape = shape.into();
        let dim = shape.dim;
        let strides = shape.strides;
        dimension::can_index_slice(xs, &dim, &strides).map(|_| {
            unsafe {
                Self::new_(xs.as_mut_ptr(), dim, strides)
            }
        })
    }

    /// Create an `ArrayViewMut<A, D>` from shape information and a
    /// raw pointer to the elements.
    ///
    /// Unsafe because caller is responsible for ensuring that the pointer is
    /// valid, not aliased and coherent with the dimension and stride information.
    pub unsafe fn from_shape_ptr<Sh>(shape: Sh, ptr: *mut A) -> Self
        where Sh: Into<StrideShape<D>>
    {
        let shape = shape.into();
        let dim = shape.dim;
        let strides = shape.strides;
        ArrayViewMut::new_(ptr, dim, strides)
    }

    /// Split the array along `axis` and return one mutable view strictly
    /// before the split and one mutable view after the split.
    ///
    /// **Panics** if `axis` or `index` is out of bounds.
    pub fn split_at(self, axis: Axis, index: Ix)
        -> (Self, Self)
    {
        // NOTE: Keep this in sync with the ArrayView version
        assert!(index <= self.shape().axis(axis));
        let left_ptr = self.ptr;
        let right_ptr = if index == self.shape().axis(axis) {
            self.ptr
        } else {
            let offset = stride_offset(index, self.strides.axis(axis));
            unsafe {
                self.ptr.offset(offset)
            }
        };

        let mut dim_left = self.dim.clone();
        dim_left.set_axis(axis, index);
        let left = unsafe {
            Self::new_(left_ptr, dim_left, self.strides.clone())
        };

        let mut dim_right = self.dim;
        let right_len  = dim_right.axis(axis) - index;
        dim_right.set_axis(axis, right_len);
        let right = unsafe {
            Self::new_(right_ptr, dim_right, self.strides)
        };

        (left, right)
    }

}

<|endoftext|>


<commit_before>//! Iterates over lines of a given reader by keeping an internal
//! buffer which client code is handed a reference to for consumption
//! of the line.
//!
//! Since this module implements internal buffering, there is no need
//! for clients to supply a buffering reader implementation.

use std::io::{Read, Result};
use bytes;

/// Wraps a `Read` and provides a way to iterate over lines split on a
/// newline character.
///
/// Unlike `BufReaderExt::lines` a line provided by
/// `LineReader::read_line` is represented as a slice into an internal
/// buffer which gets overwritten upon the next invocation of this
/// method.  This allows clients to read through lines without
/// enforcing memory allocation on every line.  On the other hand,
/// clients must copy the provided data if a line is to be kept for
/// later reference.
///
/// # Examples
///
/// Iterating over all the lines of a given `Read` can be implemented
/// as follows:
///
/// ```text
/// let r: Read = ...;
/// let mut lr = LineReader::new(r);
/// loop {
///   match lr.read_line() {
///      Ok(b) if b.is_empty() => { /* end of file */ }
///      Ok(line) => { /* process line bytes */ }
///      Err(e) => { /* i/o error occured */ }
///   }
/// }
/// ```
///
/// For convenience, you'd usually use the `read_lines` macro provided
/// by this module.  The macro will loop over the lines and take care
/// of aborting the loop when encountering end-of-file.
///
/// ```text
/// let r: Read = ...;
/// let mut reader = LineReader::new(r);
/// read_lines(line in reader, {
///   match line {
///     Ok(line) => { /* process line bytes; line is never empty */ }
///     Err(e)   => { /* i/o error occured */ }
///   }
/// });
/// ```
pub struct LineReader<R> {
    block: Vec<u8>,

    inner: R,
    buf: Vec<u8>,
    pos: usize,
    cap: usize,
}

static DEFAULT_BUF_SIZE: usize = 64 * 1024;

impl<R: Read> LineReader<R> {

    /// Constructs a new `LineReader` with an internal buffering of
    /// the specified capacity.
    pub fn with_capacity(cap: usize, inner: R) -> LineReader<R> {
        let mut buf = Vec::with_capacity(cap);
        unsafe { buf.set_len(cap); }
        LineReader {
            block: Vec::new(),

            inner: inner,
            buf: buf,
            pos: 0,
            cap: 0,
        }
    }

    /// Constructs a new `LineReader` with an internal buffering of
    /// the default capacity.
    pub fn new(inner: R) -> LineReader<R> {
        LineReader::with_capacity(DEFAULT_BUF_SIZE, inner)
    }

    // private
    fn fill_buf<'a>(&'a mut self) -> Result<usize> {
        if self.pos == self.cap {
            self.cap = try!(self.inner.read(&mut self.buf[..]));
            self.pos = 0;
        }
        Ok(self.cap-self.pos)
    }

    fn read_until<'a>(&'a mut self, byte: u8) -> Result<&'a [u8]> {
        // ~ clear our previously delivered block - if any
        unsafe { self.block.set_len(0); }

        loop {
            // ensure we have data to process
            match self.fill_buf() {
                Ok(0) => {
                    return Ok(&self.block[..]);
                },
                Ok(_) => {},
                Err(e) => return Err(e),
            };

            // note: we're dealing here with buf, pos, cap directly
            // to avoid the mutability checker from getting in our way
            let b = &self.buf[self.pos .. self.cap];
            match bytes::index(b, byte) {
                Some(mut i) => {
                    i += 1;
                    let b = if self.block.is_empty() {
                        &self.buf[self.pos .. self.pos+i]
                    } else {
                        let b: &[u8] = &b[..i];
                        self.block.extend(b.iter().cloned());
                        &self.block[..]
                    };
                    self.pos += i;
                    return Ok(b);
                }
                None => {
                    self.block.extend(b.iter().cloned());
                    self.pos += b.len();
                    // continue looping
                }
            }
        }
    }

    /// Reads the next line. Returns the empty slice if EOF is
    /// reached.  The newline character - if any - is not stripped by
    /// this method.
    #[inline]
    pub fn read_line(&mut self) -> Result<&[u8]> {
        self.read_until(b'\n')
    }
}

/// Provides a convenient way to iterate over all lines through a
/// `LineReader`.  For an example, refer to the documentation of
/// `LineReader`.  The identifier representing the read line will be
/// of type `Result<&[u8]>`.
#[macro_export]
macro_rules! read_lines {
    ($inp:ident in $expr:expr, $b:block) => {
        { let ref mut r = &mut $expr;
          loop {
              let $inp = r.read_line();
              match $inp {
                  Ok(b) if b.is_empty() => {
                      break
                  }
                  _ => { $b }
              };
          };
        }
    }
}

/// Provides a convenient way to iterate over all lines through a
/// `LineReader` wrapping a `try!` on the invocation to
/// `LineReader::read_line`.  Hence, the identifer representing the
/// read line will be directly of type `&[u8]`.
#[macro_export]
macro_rules! try_read_lines {
    ($inp:ident in $expr:expr, $b:block) => {
        { let ref mut r = &mut $expr;
          loop {
              let $inp = try!(r.read_line());
              if $inp.is_empty() { break; }
              else { $b };
          };
        }
    }
}

/// Counts the lines read through the given `LineReader`.
pub fn count_lines<R: Read> (mut r: LineReader<R>)
    -> Result<usize>
{
    let mut lines = 0usize;
    try_read_lines!(line in r, {
        lines += 1;
    });
    Ok(lines)
}
<commit_msg>Wording in documentation<commit_after>//! Iterates over lines of a given reader by keeping an internal
//! buffer which client code is handed a reference to for consumption
//! of the line.
//!
//! Since this module implements internal buffering, there is no need
//! for clients to supply a buffering reader implementation.

use std::io::{Read, Result};
use bytes;

/// Wraps a `Read` and provides a way to iterate over lines split on a
/// newline character.
///
/// Unlike `BufReaderExt::lines` a line provided by
/// `LineReader::read_line` is represented as a slice into an internal
/// buffer which gets overwritten upon the next invocation of this
/// method.  This allows clients to read through lines without
/// enforcing memory allocation on every line.  On the other hand,
/// clients must copy the provided data if a line is to be kept for
/// later reference.
///
/// # Examples
///
/// Iterating over all the lines of a given `Read` can be implemented
/// as follows:
///
/// ```text
/// extern crate lines;
///
/// let r: Read = ...;
/// let mut lr = LineReader::new(r);
/// loop {
///   match lr.read_line() {
///      Ok(b) if b.is_empty() => { /* end of file */ }
///      Ok(line) => { /* process line bytes */ }
///      Err(e) => { /* i/o error occured */ }
///   }
/// }
/// ```
///
/// For convenience, you'd usually use the `read_lines` macro provided
/// by this module.  The macro will loop over the lines and take care
/// of aborting the loop when encountering end-of-file.
///
/// ```text
/// #[macro_use(read_lines)]
/// extern crate lines;
///
/// let r: Read = ...;
/// let mut reader = LineReader::new(r);
/// read_lines(line in reader, {
///   match line {
///     Ok(line) => { /* process line bytes; line is never empty */ }
///     Err(e)   => { /* i/o error occured */ }
///   }
/// });
/// ```
pub struct LineReader<R> {
    block: Vec<u8>,

    inner: R,
    buf: Vec<u8>,
    pos: usize,
    cap: usize,
}

static DEFAULT_BUF_SIZE: usize = 64 * 1024;

impl<R: Read> LineReader<R> {

    /// Constructs a new `LineReader` with an internal buffering of
    /// the specified capacity.
    pub fn with_capacity(cap: usize, inner: R) -> LineReader<R> {
        let mut buf = Vec::with_capacity(cap);
        unsafe { buf.set_len(cap); }
        LineReader {
            block: Vec::new(),

            inner: inner,
            buf: buf,
            pos: 0,
            cap: 0,
        }
    }

    /// Constructs a new `LineReader` with an internal buffering of
    /// the default capacity.
    pub fn new(inner: R) -> LineReader<R> {
        LineReader::with_capacity(DEFAULT_BUF_SIZE, inner)
    }

    // private
    fn fill_buf<'a>(&'a mut self) -> Result<usize> {
        if self.pos == self.cap {
            self.cap = try!(self.inner.read(&mut self.buf[..]));
            self.pos = 0;
        }
        Ok(self.cap-self.pos)
    }

    fn read_until<'a>(&'a mut self, byte: u8) -> Result<&'a [u8]> {
        // ~ clear our previously delivered block - if any
        unsafe { self.block.set_len(0); }

        loop {
            // ensure we have data to process
            match self.fill_buf() {
                Ok(0) => {
                    return Ok(&self.block[..]);
                },
                Ok(_) => {},
                Err(e) => return Err(e),
            };

            // note: we're dealing here with buf, pos, cap directly
            // to avoid the mutability checker from getting in our way
            let b = &self.buf[self.pos .. self.cap];
            match bytes::index(b, byte) {
                Some(mut i) => {
                    i += 1;
                    let b = if self.block.is_empty() {
                        &self.buf[self.pos .. self.pos+i]
                    } else {
                        let b: &[u8] = &b[..i];
                        self.block.extend(b.iter().cloned());
                        &self.block[..]
                    };
                    self.pos += i;
                    return Ok(b);
                }
                None => {
                    self.block.extend(b.iter().cloned());
                    self.pos += b.len();
                    // continue looping
                }
            }
        }
    }

    /// Reads the next line. Returns the empty slice if EOF is
    /// reached.  The newline character - if any - is not stripped by
    /// this method.
    #[inline]
    pub fn read_line(&mut self) -> Result<&[u8]> {
        self.read_until(b'\n')
    }
}

/// Provides a convenient way to iterate over all lines through a
/// `LineReader`.  For an example, refer to the documentation of
/// `LineReader`.  The identifier representing the read line will be
/// of type `Result<&[u8]>`.
#[macro_export]
macro_rules! read_lines {
    ($inp:ident in $expr:expr, $b:block) => {
        { let ref mut r = &mut $expr;
          loop {
              let $inp = r.read_line();
              match $inp {
                  Ok(b) if b.is_empty() => {
                      break
                  }
                  _ => { $b }
              };
          };
        }
    }
}

/// Provides a convenient way to iterate over all lines through a
/// `LineReader` wrapping the invocation to `LineReader::read_line`
/// with a `try!`. Hence, the identifer representing the read line
/// will be directly of type `&[u8]`.
#[macro_export]
macro_rules! try_read_lines {
    ($inp:ident in $expr:expr, $b:block) => {
        { let ref mut r = &mut $expr;
          loop {
              let $inp = try!(r.read_line());
              if $inp.is_empty() { break; }
              else { $b };
          };
        }
    }
}

/// Counts the lines read through the given `LineReader`.
pub fn count_lines<R: Read> (mut r: LineReader<R>)
    -> Result<usize>
{
    let mut lines = 0usize;
    try_read_lines!(line in r, {
        lines += 1;
    });
    Ok(lines)
}
<|endoftext|>