<commit_before>#![cfg(not(windows))]

use super::Key;
use super::Key::*;
use std::io::{Read, Write};
use std::fs::{File, OpenOptions};
use std::os::unix::io::*;
use std::path::*;
use std::process::Command;
use std::process::Stdio;
use std::str;
use std::iter::repeat;
use std::cmp::min;
use crate::ansi;
use crate::NEWLINE;

use std::mem;
use std::thread;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;
use std::sync::{mpsc, Arc, Mutex};

use ::libc::{dup, SIGINT, SIGWINCH, c_int, c_ushort, c_ulong};
use crate::screen::Screen;

pub struct UnixScreen {
    tty: Terminal,
    start_line: u16,
    desired_rows: u16,
}

impl Screen for UnixScreen {
    fn visible_choices(&self) -> u16 {
        let (_, rows) = self.tty.winsize().unwrap();
        min(self.desired_rows, rows - 1)
    }

    fn width(&self) -> u16 {
        let (cols, _) = self.tty.winsize().unwrap();
        cols
    }

    fn move_cursor_to_prompt_line(&mut self, col: u16) {
        self.reset_cursor();
        self.tty.write(&ansi::cursor_right(col));
    }

    fn blank_screen(&mut self) {
        self.reset_cursor();
        let blank_line = repeat(' ').take(self.width() as usize).collect::<String>();
        for _ in 0..self.visible_choices() + 1 {
            self.tty.write(blank_line.as_bytes());
        }
        self.reset_cursor();
    }

    fn show_cursor(&mut self) {
        self.tty.write(&ansi::show_cursor());
        self.tty.flush();
    }

    fn hide_cursor(&mut self) {
        self.tty.write(&ansi::hide_cursor());
    }

    fn write(&mut self, s: &str) {
        self.tty.write(s.as_bytes());
    }

    fn write_red_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    fn write_red(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    fn write_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    // Return all buffered keystrokes, or the next key if buffer is empty.
    fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(bytes) = self.tty.input.try_recv() {
            ret.extend(bytes);
        }
        while ret.is_empty() {
            let bytes = self.tty.input.recv().unwrap();
            if bytes == vec![SIGWINCH as u8] {
                self.blank_entire_screen();
                return vec![Nothing];
            } else if bytes == vec![SIGINT as u8] {
                return vec![Control('g')];
            } else {
                ret.extend(bytes);
            }
        }
        Terminal::translate_bytes(ret.clone())
    }
}

impl UnixScreen {
    pub fn is_cygwin() -> bool {
        false
    }

    pub fn open_screen(desired_rows: u16) -> UnixScreen {
        let mut tty = Terminal::open_terminal();
        let (_, rows) = tty.winsize().unwrap();
        let visible_choices = min(desired_rows, rows - 1);
        let start_line = rows - visible_choices - 1;
        for _ in 0..visible_choices {
            tty.write(NEWLINE.as_bytes());
        }
        tty.write(&ansi::save_cursor());

        UnixScreen {
            tty,
            start_line,
            desired_rows,
        }
    }

    fn restore_tty(&mut self) {
        self.tty.restore_tty();
    }

    fn reset_cursor(&mut self) {
        self.tty.write(&ansi::restore_cursor());

        // Writing this carriage return works around a rendering bug in
        // Neovim's terminal emulation. Without it, the cursor flies
        // around all over the place while typing, and the input prompt
        // is not rendered correctly. I have no idea why this workaround
        // is effective, or why others are not, or what the root cause
        // of the issue is (likely something involving save/restore
        // support).
        self.tty.write(b"\r");

        let num_lines = self.visible_choices();
        self.tty.write(&ansi::cursor_up(num_lines));
    }

    pub fn blank_entire_screen(&mut self){
        self.tty.write(&ansi::blank_screen());
    }

    fn more_bytes_needed(bytes: &[u8]) -> bool {
        if let Err(_) = str::from_utf8(bytes) { true } else { false }
    }
}

struct Terminal {
    input: Receiver<Vec<u8>>,
    input_fd: RawFd,
    output: File,
    output_buf: Vec<u8>,
    original_stty_state: Vec<u8>,
}

static mut GLOBAL_TX: *const Arc<Mutex<Sender<Vec<u8>>>> = 0 as *const Arc<Mutex<Sender<Vec<u8>>>>;

fn set_global_tx(tx: Sender<Vec<u8>>) {
    unsafe {
        let singleton = Arc::new(Mutex::new(tx));
        GLOBAL_TX = mem::transmute(Box::new(singleton));
    }
}

fn get_global_tx() -> Sender<Vec<u8>> {
    let singleton = unsafe { (*GLOBAL_TX).clone() };
    let tx = singleton.lock().unwrap();
    tx.clone()
}

fn start_sigwinch_handler() {
    let signals = signal_hook::iterator::Signals::new(&[SIGWINCH, SIGINT]).unwrap();
    thread::spawn(move || {
        for signal in signals.forever() {
            get_global_tx().send(vec![signal as u8]).unwrap();
        }
    });
}

impl Terminal {
    fn open_terminal() -> Terminal {
        let term_path = Path::new("/dev/tty");
        let mut input_file = File::open(&term_path).unwrap();
        let output_file = OpenOptions::new().write(true).open(&term_path).unwrap();
        let input_fd = input_file.as_raw_fd();
        let (tx, rx) = mpsc::channel();
        set_global_tx(tx);

        start_sigwinch_handler();

        let mut ret = Terminal {
            input: rx,
            input_fd,
            output: output_file,
            output_buf: Vec::new(),
            original_stty_state: Vec::new(),
        };
        let current_stty_state = ret.stty(&["-g"]);
        ret.original_stty_state = current_stty_state;
        ret.initialize();

        thread::spawn(move || {
            loop {
                let mut buf = [0; 255];
                let tx = get_global_tx();
                if let Ok(length) = input_file.read(&mut buf) {
                    tx.send(buf[0..length].to_vec()).unwrap();
                } else {
                    tx.send([0].to_vec()).unwrap();
                }
            }
        });
        ret
    }

    fn initialize(&mut self) {
        self.stty(&["raw", "-echo", "cbreak", "opost", "onlcr"]);
    }

    fn restore_tty(&mut self) {
        let state = String::from_utf8(self.original_stty_state.clone()).unwrap();
        self.stty(&[&state]);
    }

    fn stty(&mut self, args: &[&str]) -> Vec<u8> {
        let tty_input = unsafe { Stdio::from_raw_fd(dup(self.input_fd)) };
        let mut process = match Command::new("/bin/stty")
            .args(args)
            .stdin(tty_input)
            .stdout(Stdio::piped())
            .spawn()
        {
            Ok(p) => p,
            Err(e) => panic!("Spawn failed: {}", e),
        };

        let exit = process.wait();

        let mut buf = Vec::new();
        if exit.unwrap().success() {
            process.stdout.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            let mut str = String::from_utf8(buf).unwrap();

            // The output from `stty -g` may include a newline, which we have to strip off. Otherwise,
            // when we go to restore the tty, stty (on some platforms) will fail with an "invalid
            // argument" error.
            crate::trim(&mut str);

            str.into_bytes()
        } else {
            process.stderr.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            panic!("stty invocation failed: {}", String::from_utf8(buf).unwrap());
        }
    }

    fn translate_bytes(bytes: Vec<u8>) -> Vec<Key> {
        const BEGIN_PASTE: &'static [u8] = b"\x1B[200~";
        const END_PASTE: &'static [u8] = b"\x1B[201~";

        if bytes == b"\x1B[A" || bytes == b"\x1BOA" { return vec![Up] };
        if bytes == b"\x1B[B" || bytes == b"\x1BOB" { return vec![Down] };
        if bytes == b"\x1B[5~" { return vec![PgUp] }
        if bytes == b"\x1B[6~" { return vec![PgDown] }
        if bytes == b"\x1B[H" { return vec![Home] }
        if bytes == b"\x1B[F" { return vec![End] }
        if bytes == b"\x1B[Z" { return vec![ShiftTab] };

        let bs = if bytes.starts_with(BEGIN_PASTE) && bytes.ends_with(END_PASTE) {
            let start = BEGIN_PASTE.len();
            let end = bytes.len() - END_PASTE.len();
            bytes[start..end].to_vec()
        } else {
            bytes
        };

        String::from_utf8(bs)
            .unwrap()
            .chars()
            .map(Terminal::translate_char)
            .collect()
    }

    fn translate_char(c: char) -> Key {
        let numeric_char = c as u32;
        if c == '\r' {
            Enter
        } else if numeric_char == 9 {
            Tab
        } else if numeric_char == 127 {
            Backspace
        } else if numeric_char == 27 {
            Control('g')
        } else if numeric_char & 96 == 0 && numeric_char <= 128u32 {
            let c = c as u8;
            Control((c + 96u8) as char)
        } else {
            Char(c)
        }
    }

    fn write(&mut self, s: &[u8]) {
        self.output_buf.extend_from_slice(s);
    }

    fn writeln(&mut self, s: &str) {
        self.output_buf.extend_from_slice(s.as_bytes());
        self.output_buf.push(b'\n');
    }

    fn flush(&mut self) {
        self.output.write(&self.output_buf).unwrap();
        self.output_buf.clear();
    }

    fn winsize(&self) -> Option<(u16, u16)> {
        extern { fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; }
        #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
        const TIOCGWINSZ: c_ulong = 0x40087468;

        #[cfg(any(target_os = "linux", target_os = "android"))]
        const TIOCGWINSZ: c_ulong = 0x00005413;

        #[repr(C)]
        struct TermSize {
            rows: c_ushort,
            cols: c_ushort,
            x: c_ushort,
            y: c_ushort,
        }

        let size = TermSize { rows: 0, cols: 0, x: 0, y: 0 };
        if unsafe { ioctl(self.output.as_raw_fd(), TIOCGWINSZ, &size) } == 0 {
            Some((size.cols as u16, size.rows as u16))
        } else {
            None
        }
    }
}

impl Drop for Terminal {
    fn drop(&mut self) {
        self.flush();
        self.restore_tty();
    }
}

#[cfg(test)]
mod tests {
    use super::Terminal;

    #[test]
    fn winsize_test() {
        // Travis-CI builds run without a tty, making this test impossible.
        if option_env!("TRAVIS").is_some() {
            // TODO: It should be made obvious from the output that this test was skipped
            return;
        }
        let term = Terminal::open_terminal();
        let (cols, rows) = term.winsize().expect("Failed to get window size!");
        // We don't know the window size a priori, but we can at least
        // assert that it is within some kind of sensible range.
        assert!(cols > 40);
        assert!(rows > 40);
        assert!(cols < 1000);
        assert!(rows < 1000);
    }
}
<commit_msg>Distinguish signals from keystrokes<commit_after>#![cfg(not(windows))]

use super::Key;
use super::Key::*;
use std::io::{Read, Write};
use std::fs::{File, OpenOptions};
use std::os::unix::io::*;
use std::path::*;
use std::process::Command;
use std::process::Stdio;
use std::str;
use std::iter::repeat;
use std::cmp::min;
use crate::ansi;
use crate::NEWLINE;

use std::mem;
use std::thread;
use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;
use std::sync::{mpsc, Arc, Mutex};

use ::libc::{dup, SIGINT, SIGWINCH, c_int, c_ushort, c_ulong};
use crate::screen::Screen;

pub struct UnixScreen {
    tty: Terminal,
    start_line: u16,
    desired_rows: u16,
}

impl Screen for UnixScreen {
    fn visible_choices(&self) -> u16 {
        let (_, rows) = self.tty.winsize().unwrap();
        min(self.desired_rows, rows - 1)
    }

    fn width(&self) -> u16 {
        let (cols, _) = self.tty.winsize().unwrap();
        cols
    }

    fn move_cursor_to_prompt_line(&mut self, col: u16) {
        self.reset_cursor();
        self.tty.write(&ansi::cursor_right(col));
    }

    fn blank_screen(&mut self) {
        self.reset_cursor();
        let blank_line = repeat(' ').take(self.width() as usize).collect::<String>();
        for _ in 0..self.visible_choices() + 1 {
            self.tty.write(blank_line.as_bytes());
        }
        self.reset_cursor();
    }

    fn show_cursor(&mut self) {
        self.tty.write(&ansi::show_cursor());
        self.tty.flush();
    }

    fn hide_cursor(&mut self) {
        self.tty.write(&ansi::hide_cursor());
    }

    fn write(&mut self, s: &str) {
        self.tty.write(s.as_bytes());
    }

    fn write_red_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    fn write_red(&mut self, s: &str) {
        self.tty.write(&ansi::red());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    fn write_inverted(&mut self, s: &str) {
        self.tty.write(&ansi::inverse());
        self.tty.write(s.as_bytes());
        self.tty.write(&ansi::reset());
    }

    // Return all buffered keystrokes, or the next key if buffer is empty.
    fn get_buffered_keys(&mut self) -> Vec<Key> {
        let mut ret = Vec::new();
        while let Ok(bytes) = self.tty.input.try_recv() {
            ret.extend(bytes);
        }
        while ret.is_empty() {
            let bytes = self.tty.input.recv().unwrap();
            if bytes == vec![128 + SIGWINCH as u8] {
                self.blank_entire_screen();
                return vec![Nothing];
            } else if bytes == vec![128 + SIGINT as u8] {
                return vec![Control('g')];
            } else {
                ret.extend(bytes);
            }
        }
        Terminal::translate_bytes(ret.clone())
    }
}

impl UnixScreen {
    pub fn is_cygwin() -> bool {
        false
    }

    pub fn open_screen(desired_rows: u16) -> UnixScreen {
        let mut tty = Terminal::open_terminal();
        let (_, rows) = tty.winsize().unwrap();
        let visible_choices = min(desired_rows, rows - 1);
        let start_line = rows - visible_choices - 1;
        for _ in 0..visible_choices {
            tty.write(NEWLINE.as_bytes());
        }
        tty.write(&ansi::save_cursor());

        UnixScreen {
            tty,
            start_line,
            desired_rows,
        }
    }

    fn restore_tty(&mut self) {
        self.tty.restore_tty();
    }

    fn reset_cursor(&mut self) {
        self.tty.write(&ansi::restore_cursor());

        // Writing this carriage return works around a rendering bug in
        // Neovim's terminal emulation. Without it, the cursor flies
        // around all over the place while typing, and the input prompt
        // is not rendered correctly. I have no idea why this workaround
        // is effective, or why others are not, or what the root cause
        // of the issue is (likely something involving save/restore
        // support).
        self.tty.write(b"\r");

        let num_lines = self.visible_choices();
        self.tty.write(&ansi::cursor_up(num_lines));
    }

    pub fn blank_entire_screen(&mut self){
        self.tty.write(&ansi::blank_screen());
    }

    fn more_bytes_needed(bytes: &[u8]) -> bool {
        if let Err(_) = str::from_utf8(bytes) { true } else { false }
    }
}

struct Terminal {
    input: Receiver<Vec<u8>>,
    input_fd: RawFd,
    output: File,
    output_buf: Vec<u8>,
    original_stty_state: Vec<u8>,
}

static mut GLOBAL_TX: *const Arc<Mutex<Sender<Vec<u8>>>> = 0 as *const Arc<Mutex<Sender<Vec<u8>>>>;

fn set_global_tx(tx: Sender<Vec<u8>>) {
    unsafe {
        let singleton = Arc::new(Mutex::new(tx));
        GLOBAL_TX = mem::transmute(Box::new(singleton));
    }
}

fn get_global_tx() -> Sender<Vec<u8>> {
    let singleton = unsafe { (*GLOBAL_TX).clone() };
    let tx = singleton.lock().unwrap();
    tx.clone()
}

fn start_sigwinch_handler() {
    let signals = signal_hook::iterator::Signals::new(&[SIGWINCH, SIGINT]).unwrap();
    thread::spawn(move || {
        for signal in signals.forever() {
            get_global_tx().send(vec![128 + signal as u8]).unwrap();
        }
    });
}

impl Terminal {
    fn open_terminal() -> Terminal {
        let term_path = Path::new("/dev/tty");
        let mut input_file = File::open(&term_path).unwrap();
        let output_file = OpenOptions::new().write(true).open(&term_path).unwrap();
        let input_fd = input_file.as_raw_fd();
        let (tx, rx) = mpsc::channel();
        set_global_tx(tx);

        start_sigwinch_handler();

        let mut ret = Terminal {
            input: rx,
            input_fd,
            output: output_file,
            output_buf: Vec::new(),
            original_stty_state: Vec::new(),
        };
        let current_stty_state = ret.stty(&["-g"]);
        ret.original_stty_state = current_stty_state;
        ret.initialize();

        thread::spawn(move || {
            loop {
                let mut buf = [0; 255];
                let tx = get_global_tx();
                if let Ok(length) = input_file.read(&mut buf) {
                    tx.send(buf[0..length].to_vec()).unwrap();
                } else {
                    tx.send([0].to_vec()).unwrap();
                }
            }
        });
        ret
    }

    fn initialize(&mut self) {
        self.stty(&["raw", "-echo", "cbreak", "opost", "onlcr"]);
    }

    fn restore_tty(&mut self) {
        let state = String::from_utf8(self.original_stty_state.clone()).unwrap();
        self.stty(&[&state]);
    }

    fn stty(&mut self, args: &[&str]) -> Vec<u8> {
        let tty_input = unsafe { Stdio::from_raw_fd(dup(self.input_fd)) };
        let mut process = match Command::new("/bin/stty")
            .args(args)
            .stdin(tty_input)
            .stdout(Stdio::piped())
            .spawn()
        {
            Ok(p) => p,
            Err(e) => panic!("Spawn failed: {}", e),
        };

        let exit = process.wait();

        let mut buf = Vec::new();
        if exit.unwrap().success() {
            process.stdout.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            let mut str = String::from_utf8(buf).unwrap();

            // The output from `stty -g` may include a newline, which we have to strip off. Otherwise,
            // when we go to restore the tty, stty (on some platforms) will fail with an "invalid
            // argument" error.
            crate::trim(&mut str);

            str.into_bytes()
        } else {
            process.stderr.as_mut().unwrap().read_to_end(&mut buf).unwrap();
            panic!("stty invocation failed: {}", String::from_utf8(buf).unwrap());
        }
    }

    fn translate_bytes(bytes: Vec<u8>) -> Vec<Key> {
        const BEGIN_PASTE: &'static [u8] = b"\x1B[200~";
        const END_PASTE: &'static [u8] = b"\x1B[201~";

        if bytes == b"\x1B[A" || bytes == b"\x1BOA" { return vec![Up] };
        if bytes == b"\x1B[B" || bytes == b"\x1BOB" { return vec![Down] };
        if bytes == b"\x1B[5~" { return vec![PgUp] }
        if bytes == b"\x1B[6~" { return vec![PgDown] }
        if bytes == b"\x1B[H" { return vec![Home] }
        if bytes == b"\x1B[F" { return vec![End] }
        if bytes == b"\x1B[Z" { return vec![ShiftTab] };

        let bs = if bytes.starts_with(BEGIN_PASTE) && bytes.ends_with(END_PASTE) {
            let start = BEGIN_PASTE.len();
            let end = bytes.len() - END_PASTE.len();
            bytes[start..end].to_vec()
        } else {
            bytes
        };

        String::from_utf8(bs)
            .unwrap()
            .chars()
            .map(Terminal::translate_char)
            .collect()
    }

    fn translate_char(c: char) -> Key {
        let numeric_char = c as u32;
        if c == '\r' {
            Enter
        } else if numeric_char == 9 {
            Tab
        } else if numeric_char == 127 {
            Backspace
        } else if numeric_char == 27 {
            Control('g')
        } else if numeric_char & 96 == 0 && numeric_char <= 128u32 {
            let c = c as u8;
            Control((c + 96u8) as char)
        } else {
            Char(c)
        }
    }

    fn write(&mut self, s: &[u8]) {
        self.output_buf.extend_from_slice(s);
    }

    fn writeln(&mut self, s: &str) {
        self.output_buf.extend_from_slice(s.as_bytes());
        self.output_buf.push(b'\n');
    }

    fn flush(&mut self) {
        self.output.write(&self.output_buf).unwrap();
        self.output_buf.clear();
    }

    fn winsize(&self) -> Option<(u16, u16)> {
        extern { fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int; }
        #[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
        const TIOCGWINSZ: c_ulong = 0x40087468;

        #[cfg(any(target_os = "linux", target_os = "android"))]
        const TIOCGWINSZ: c_ulong = 0x00005413;

        #[repr(C)]
        struct TermSize {
            rows: c_ushort,
            cols: c_ushort,
            x: c_ushort,
            y: c_ushort,
        }

        let size = TermSize { rows: 0, cols: 0, x: 0, y: 0 };
        if unsafe { ioctl(self.output.as_raw_fd(), TIOCGWINSZ, &size) } == 0 {
            Some((size.cols as u16, size.rows as u16))
        } else {
            None
        }
    }
}

impl Drop for Terminal {
    fn drop(&mut self) {
        self.flush();
        self.restore_tty();
    }
}

#[cfg(test)]
mod tests {
    use super::Terminal;

    #[test]
    fn winsize_test() {
        // Travis-CI builds run without a tty, making this test impossible.
        if option_env!("TRAVIS").is_some() {
            // TODO: It should be made obvious from the output that this test was skipped
            return;
        }
        let term = Terminal::open_terminal();
        let (cols, rows) = term.winsize().expect("Failed to get window size!");
        // We don't know the window size a priori, but we can at least
        // assert that it is within some kind of sensible range.
        assert!(cols > 40);
        assert!(rows > 40);
        assert!(cols < 1000);
        assert!(rows < 1000);
    }
}
<|endoftext|>


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

use std::thread;
use std::sync::{Arc, mpsc};
use std::sync::mpsc::Sender;
use std::time::Duration;
use std::process;

use mio::EventLoop;
use rocksdb::DB;

use pd::{INVALID_ID, PdClient, Error as PdError};
use kvproto::raft_serverpb::StoreIdent;
use kvproto::metapb;
use protobuf::RepeatedField;
use util::transport::SendCh;
use raftstore::store::{self, Msg, SnapshotStatusMsg, StoreChannel, Store, Config as StoreConfig,
                       keys, Peekable, Transport, SnapManager};
use super::Result;
use super::config::Config;
use storage::{Storage, RaftKv};
use super::transport::RaftStoreRouter;

const MAX_CHECK_CLUSTER_BOOTSTRAPPED_RETRY_COUNT: u64 = 60;
const CHECK_CLUSTER_BOOTSTRAPPED_RETRY_SECONDS: u64 = 3;

pub fn create_raft_storage<S>(router: S, db: Arc<DB>, cfg: &Config) -> Result<Storage>
    where S: RaftStoreRouter + 'static
{
    let engine = box RaftKv::new(db, router);
    let store = try!(Storage::from_engine(engine, &cfg.storage));
    Ok(store)
}

// Node is a wrapper for raft store.
// TODO: we will rename another better name like RaftStore later.
pub struct Node<C: PdClient + 'static> {
    cluster_id: u64,
    store: metapb::Store,
    store_cfg: StoreConfig,
    store_handle: Option<thread::JoinHandle<()>>,
    ch: SendCh<Msg>,
    snapshot_status_sender: Option<Sender<SnapshotStatusMsg>>,

    pd_client: Arc<C>,
}

impl<C> Node<C>
    where C: PdClient
{
    pub fn new<T>(event_loop: &mut EventLoop<Store<T, C>>,
                  cfg: &Config,
                  pd_client: Arc<C>)
                  -> Node<C>
        where T: Transport + 'static
    {
        let mut store = metapb::Store::new();
        store.set_id(INVALID_ID);
        if cfg.advertise_addr.is_empty() {
            store.set_address(cfg.addr.clone());
        } else {
            store.set_address(cfg.advertise_addr.clone())
        }

        let mut labels = Vec::new();
        for (k, v) in &cfg.labels {
            let mut label = metapb::StoreLabel::new();
            label.set_key(k.to_owned());
            label.set_value(v.to_owned());
            labels.push(label);
        }
        store.set_labels(RepeatedField::from_vec(labels));

        let ch = SendCh::new(event_loop.channel(), "raftstore");
        Node {
            cluster_id: cfg.cluster_id,
            store: store,
            store_cfg: cfg.raft_store.clone(),
            store_handle: None,
            pd_client: pd_client,
            ch: ch,
            snapshot_status_sender: None,
        }
    }

    pub fn start<T>(&mut self,
                    event_loop: EventLoop<Store<T, C>>,
                    engine: Arc<DB>,
                    trans: T,
                    snap_mgr: SnapManager)
                    -> Result<()>
        where T: Transport + 'static
    {
        let bootstrapped = try!(self.check_cluster_bootstrapped());
        let mut store_id = try!(self.check_store(&engine));
        if store_id == INVALID_ID {
            store_id = try!(self.bootstrap_store(&engine));
        } else if !bootstrapped {
            // We have saved data before, and the cluster must be bootstrapped.
            return Err(box_err!("store {} is not empty, but cluster {} is not bootstrapped, \
                                 maybe you connected a wrong PD or need to remove the TiKV data \
                                 and start again",
                                store_id,
                                self.cluster_id));
        }

        self.store.set_id(store_id);

        if !bootstrapped {
            // cluster is not bootstrapped, and we choose first store to bootstrap
            // first region.
            let region = try!(self.bootstrap_first_region(&engine, store_id));
            try!(self.bootstrap_cluster(&engine, region));
        }

        // inform pd.
        try!(self.start_store(event_loop, store_id, engine, trans, snap_mgr));
        try!(self.pd_client
            .put_store(self.store.clone()));
        Ok(())
    }

    pub fn id(&self) -> u64 {
        self.store.get_id()
    }

    pub fn get_sendch(&self) -> SendCh<Msg> {
        self.ch.clone()
    }

    pub fn get_snapshot_status_sender(&self) -> Sender<SnapshotStatusMsg> {
        self.snapshot_status_sender.clone().unwrap()
    }

    // check store, return store id for the engine.
    // If the store is not bootstrapped, use INVALID_ID.
    fn check_store(&self, engine: &DB) -> Result<u64> {
        let res = try!(engine.get_msg::<StoreIdent>(&keys::store_ident_key()));
        if res.is_none() {
            return Ok(INVALID_ID);
        }

        let ident = res.unwrap();
        if ident.get_cluster_id() != self.cluster_id {
            error!("cluster id mismatch: local_id {} remote_id {}",
                   ident.get_cluster_id(),
                   self.cluster_id);
            process::exit(1);
        }

        let store_id = ident.get_store_id();
        if store_id == INVALID_ID {
            return Err(box_err!("invalid store ident {:?}", ident));
        }

        Ok(store_id)
    }

    fn alloc_id(&self) -> Result<u64> {
        let id = try!(self.pd_client.alloc_id());
        Ok(id)
    }

    fn bootstrap_store(&self, engine: &DB) -> Result<u64> {
        let store_id = try!(self.alloc_id());
        info!("alloc store id {} ", store_id);

        try!(store::bootstrap_store(engine, self.cluster_id, store_id));

        Ok(store_id)
    }

    fn bootstrap_first_region(&self, engine: &DB, store_id: u64) -> Result<metapb::Region> {
        let region_id = try!(self.alloc_id());
        info!("alloc first region id {} for cluster {}, store {}",
              region_id,
              self.cluster_id,
              store_id);
        let peer_id = try!(self.alloc_id());
        info!("alloc first peer id {} for first region {}",
              peer_id,
              region_id);

        let region = try!(store::bootstrap_region(engine, store_id, region_id, peer_id));
        Ok(region)
    }

    fn bootstrap_cluster(&mut self, engine: &DB, region: metapb::Region) -> Result<()> {
        let region_id = region.get_id();
        match self.pd_client.bootstrap_cluster(self.store.clone(), region) {
            Err(PdError::ClusterBootstrapped(_)) => {
                error!("cluster {} is already bootstrapped", self.cluster_id);
                try!(store::clear_region(engine, region_id));
                Ok(())
            }
            // TODO: should we clean region for other errors too?
            Err(e) => panic!("bootstrap cluster {} err: {:?}", self.cluster_id, e),
            Ok(_) => {
                info!("bootstrap cluster {} ok", self.cluster_id);
                Ok(())
            }
        }
    }

    fn check_cluster_bootstrapped(&self) -> Result<bool> {
        for _ in 0..MAX_CHECK_CLUSTER_BOOTSTRAPPED_RETRY_COUNT {
            match self.pd_client.is_cluster_bootstrapped() {
                Ok(b) => return Ok(b),
                Err(e) => {
                    warn!("check cluster bootstrapped failed: {:?}", e);
                }
            }
            thread::sleep(Duration::from_secs(CHECK_CLUSTER_BOOTSTRAPPED_RETRY_SECONDS));
        }
        Err(box_err!("check cluster bootstrapped failed"))
    }

    fn start_store<T>(&mut self,
                      mut event_loop: EventLoop<Store<T, C>>,
                      store_id: u64,
                      db: Arc<DB>,
                      trans: T,
                      snap_mgr: SnapManager)
                      -> Result<()>
        where T: Transport + 'static
    {
        info!("start raft store {} thread", store_id);

        if self.store_handle.is_some() {
            return Err(box_err!("{} is already started", store_id));
        }

        let cfg = self.store_cfg.clone();
        let pd_client = self.pd_client.clone();
        let store = self.store.clone();
        let sender = event_loop.channel();

        let (tx, rx) = mpsc::channel();
        let (snapshot_tx, snapshot_rx) = mpsc::channel();
        self.snapshot_status_sender = Some(snapshot_tx);
        let builder = thread::Builder::new().name(thd_name!(format!("raftstore-{}", store_id)));
        let h = try!(builder.spawn(move || {
            let ch = StoreChannel {
                sender: sender,
                snapshot_status_receiver: snapshot_rx,
            };
            let mut store = match Store::new(ch, store, cfg, db, trans, pd_client, snap_mgr) {
                Err(e) => panic!("construct store {} err {:?}", store_id, e),
                Ok(s) => s,
            };
            tx.send(0).unwrap();
            if let Err(e) = store.run(&mut event_loop) {
                error!("store {} run err {:?}", store_id, e);
            };
        }));
        // wait for store to be initialized
        rx.recv().unwrap();

        self.store_handle = Some(h);
        Ok(())
    }

    fn stop_store(&mut self, store_id: u64) -> Result<()> {
        info!("stop raft store {} thread", store_id);
        let h = match self.store_handle.take() {
            None => return Ok(()),
            Some(h) => h,
        };

        box_try!(self.ch.send(Msg::Quit));
        if let Err(e) = h.join() {
            return Err(box_err!("join store {} thread err {:?}", store_id, e));
        }

        Ok(())
    }

    pub fn stop(&mut self) -> Result<()> {
        let store_id = self.store.get_id();
        self.stop_store(store_id)
    }
}

impl<C> Drop for Node<C>
    where C: PdClient
{
    fn drop(&mut self) {
        self.stop().unwrap();
    }
}
<commit_msg>use uppercase ID<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::thread;
use std::sync::{Arc, mpsc};
use std::sync::mpsc::Sender;
use std::time::Duration;
use std::process;

use mio::EventLoop;
use rocksdb::DB;

use pd::{INVALID_ID, PdClient, Error as PdError};
use kvproto::raft_serverpb::StoreIdent;
use kvproto::metapb;
use protobuf::RepeatedField;
use util::transport::SendCh;
use raftstore::store::{self, Msg, SnapshotStatusMsg, StoreChannel, Store, Config as StoreConfig,
                       keys, Peekable, Transport, SnapManager};
use super::Result;
use super::config::Config;
use storage::{Storage, RaftKv};
use super::transport::RaftStoreRouter;

const MAX_CHECK_CLUSTER_BOOTSTRAPPED_RETRY_COUNT: u64 = 60;
const CHECK_CLUSTER_BOOTSTRAPPED_RETRY_SECONDS: u64 = 3;

pub fn create_raft_storage<S>(router: S, db: Arc<DB>, cfg: &Config) -> Result<Storage>
    where S: RaftStoreRouter + 'static
{
    let engine = box RaftKv::new(db, router);
    let store = try!(Storage::from_engine(engine, &cfg.storage));
    Ok(store)
}

// Node is a wrapper for raft store.
// TODO: we will rename another better name like RaftStore later.
pub struct Node<C: PdClient + 'static> {
    cluster_id: u64,
    store: metapb::Store,
    store_cfg: StoreConfig,
    store_handle: Option<thread::JoinHandle<()>>,
    ch: SendCh<Msg>,
    snapshot_status_sender: Option<Sender<SnapshotStatusMsg>>,

    pd_client: Arc<C>,
}

impl<C> Node<C>
    where C: PdClient
{
    pub fn new<T>(event_loop: &mut EventLoop<Store<T, C>>,
                  cfg: &Config,
                  pd_client: Arc<C>)
                  -> Node<C>
        where T: Transport + 'static
    {
        let mut store = metapb::Store::new();
        store.set_id(INVALID_ID);
        if cfg.advertise_addr.is_empty() {
            store.set_address(cfg.addr.clone());
        } else {
            store.set_address(cfg.advertise_addr.clone())
        }

        let mut labels = Vec::new();
        for (k, v) in &cfg.labels {
            let mut label = metapb::StoreLabel::new();
            label.set_key(k.to_owned());
            label.set_value(v.to_owned());
            labels.push(label);
        }
        store.set_labels(RepeatedField::from_vec(labels));

        let ch = SendCh::new(event_loop.channel(), "raftstore");
        Node {
            cluster_id: cfg.cluster_id,
            store: store,
            store_cfg: cfg.raft_store.clone(),
            store_handle: None,
            pd_client: pd_client,
            ch: ch,
            snapshot_status_sender: None,
        }
    }

    pub fn start<T>(&mut self,
                    event_loop: EventLoop<Store<T, C>>,
                    engine: Arc<DB>,
                    trans: T,
                    snap_mgr: SnapManager)
                    -> Result<()>
        where T: Transport + 'static
    {
        let bootstrapped = try!(self.check_cluster_bootstrapped());
        let mut store_id = try!(self.check_store(&engine));
        if store_id == INVALID_ID {
            store_id = try!(self.bootstrap_store(&engine));
        } else if !bootstrapped {
            // We have saved data before, and the cluster must be bootstrapped.
            return Err(box_err!("store {} is not empty, but cluster {} is not bootstrapped, \
                                 maybe you connected a wrong PD or need to remove the TiKV data \
                                 and start again",
                                store_id,
                                self.cluster_id));
        }

        self.store.set_id(store_id);

        if !bootstrapped {
            // cluster is not bootstrapped, and we choose first store to bootstrap
            // first region.
            let region = try!(self.bootstrap_first_region(&engine, store_id));
            try!(self.bootstrap_cluster(&engine, region));
        }

        // inform pd.
        try!(self.start_store(event_loop, store_id, engine, trans, snap_mgr));
        try!(self.pd_client
            .put_store(self.store.clone()));
        Ok(())
    }

    pub fn id(&self) -> u64 {
        self.store.get_id()
    }

    pub fn get_sendch(&self) -> SendCh<Msg> {
        self.ch.clone()
    }

    pub fn get_snapshot_status_sender(&self) -> Sender<SnapshotStatusMsg> {
        self.snapshot_status_sender.clone().unwrap()
    }

    // check store, return store id for the engine.
    // If the store is not bootstrapped, use INVALID_ID.
    fn check_store(&self, engine: &DB) -> Result<u64> {
        let res = try!(engine.get_msg::<StoreIdent>(&keys::store_ident_key()));
        if res.is_none() {
            return Ok(INVALID_ID);
        }

        let ident = res.unwrap();
        if ident.get_cluster_id() != self.cluster_id {
            error!("cluster ID mismatch: local_id {} remote_id {}",
                   ident.get_cluster_id(),
                   self.cluster_id);
            process::exit(1);
        }

        let store_id = ident.get_store_id();
        if store_id == INVALID_ID {
            return Err(box_err!("invalid store ident {:?}", ident));
        }

        Ok(store_id)
    }

    fn alloc_id(&self) -> Result<u64> {
        let id = try!(self.pd_client.alloc_id());
        Ok(id)
    }

    fn bootstrap_store(&self, engine: &DB) -> Result<u64> {
        let store_id = try!(self.alloc_id());
        info!("alloc store id {} ", store_id);

        try!(store::bootstrap_store(engine, self.cluster_id, store_id));

        Ok(store_id)
    }

    fn bootstrap_first_region(&self, engine: &DB, store_id: u64) -> Result<metapb::Region> {
        let region_id = try!(self.alloc_id());
        info!("alloc first region id {} for cluster {}, store {}",
              region_id,
              self.cluster_id,
              store_id);
        let peer_id = try!(self.alloc_id());
        info!("alloc first peer id {} for first region {}",
              peer_id,
              region_id);

        let region = try!(store::bootstrap_region(engine, store_id, region_id, peer_id));
        Ok(region)
    }

    fn bootstrap_cluster(&mut self, engine: &DB, region: metapb::Region) -> Result<()> {
        let region_id = region.get_id();
        match self.pd_client.bootstrap_cluster(self.store.clone(), region) {
            Err(PdError::ClusterBootstrapped(_)) => {
                error!("cluster {} is already bootstrapped", self.cluster_id);
                try!(store::clear_region(engine, region_id));
                Ok(())
            }
            // TODO: should we clean region for other errors too?
            Err(e) => panic!("bootstrap cluster {} err: {:?}", self.cluster_id, e),
            Ok(_) => {
                info!("bootstrap cluster {} ok", self.cluster_id);
                Ok(())
            }
        }
    }

    fn check_cluster_bootstrapped(&self) -> Result<bool> {
        for _ in 0..MAX_CHECK_CLUSTER_BOOTSTRAPPED_RETRY_COUNT {
            match self.pd_client.is_cluster_bootstrapped() {
                Ok(b) => return Ok(b),
                Err(e) => {
                    warn!("check cluster bootstrapped failed: {:?}", e);
                }
            }
            thread::sleep(Duration::from_secs(CHECK_CLUSTER_BOOTSTRAPPED_RETRY_SECONDS));
        }
        Err(box_err!("check cluster bootstrapped failed"))
    }

    fn start_store<T>(&mut self,
                      mut event_loop: EventLoop<Store<T, C>>,
                      store_id: u64,
                      db: Arc<DB>,
                      trans: T,
                      snap_mgr: SnapManager)
                      -> Result<()>
        where T: Transport + 'static
    {
        info!("start raft store {} thread", store_id);

        if self.store_handle.is_some() {
            return Err(box_err!("{} is already started", store_id));
        }

        let cfg = self.store_cfg.clone();
        let pd_client = self.pd_client.clone();
        let store = self.store.clone();
        let sender = event_loop.channel();

        let (tx, rx) = mpsc::channel();
        let (snapshot_tx, snapshot_rx) = mpsc::channel();
        self.snapshot_status_sender = Some(snapshot_tx);
        let builder = thread::Builder::new().name(thd_name!(format!("raftstore-{}", store_id)));
        let h = try!(builder.spawn(move || {
            let ch = StoreChannel {
                sender: sender,
                snapshot_status_receiver: snapshot_rx,
            };
            let mut store = match Store::new(ch, store, cfg, db, trans, pd_client, snap_mgr) {
                Err(e) => panic!("construct store {} err {:?}", store_id, e),
                Ok(s) => s,
            };
            tx.send(0).unwrap();
            if let Err(e) = store.run(&mut event_loop) {
                error!("store {} run err {:?}", store_id, e);
            };
        }));
        // wait for store to be initialized
        rx.recv().unwrap();

        self.store_handle = Some(h);
        Ok(())
    }

    fn stop_store(&mut self, store_id: u64) -> Result<()> {
        info!("stop raft store {} thread", store_id);
        let h = match self.store_handle.take() {
            None => return Ok(()),
            Some(h) => h,
        };

        box_try!(self.ch.send(Msg::Quit));
        if let Err(e) = h.join() {
            return Err(box_err!("join store {} thread err {:?}", store_id, e));
        }

        Ok(())
    }

    pub fn stop(&mut self) -> Result<()> {
        let store_id = self.store.get_id();
        self.stop_store(store_id)
    }
}

impl<C> Drop for Node<C>
    where C: PdClient
{
    fn drop(&mut self) {
        self.stop().unwrap();
    }
}
<|endoftext|>


<commit_before>// cargo bench

#![feature(test)]

extern crate test;

macro_rules! benches {
    ($($name:ident($value:expr),)*) => {
        mod bench_ryu {
            use test::{Bencher, black_box};
            $(
                #[bench]
                fn $name(b: &mut Bencher) {
                    let mut buf = ryu::Buffer::new();

                    b.iter(move || {
                        let value = black_box($value);
                        let formatted = buf.format_finite(value);
                        black_box(formatted);
                    });
                }
            )*
        }

        mod bench_std_fmt {
            use test::{Bencher, black_box};
            $(
                #[bench]
                fn $name(b: &mut Bencher) {
                    use std::io::Write;

                    let mut buf = Vec::with_capacity(20);

                    b.iter(|| {
                        buf.clear();
                        let value = black_box($value);
                        write!(&mut buf, "{}", value).unwrap();
                        black_box(buf.as_slice());
                    });
                }
            )*
        }
    }
}

benches!(
    bench_0_f64(0f64),
    bench_short_f64(0.1234f64),
    bench_e_f64(2.718281828459045f64),
    bench_max_f64(::std::f64::MAX),
    bench_0_f32(0f32),
    bench_short_f32(0.1234f32),
    bench_e_f32(2.718281828459045f32),
    bench_max_f32(::std::f32::MAX),
);
<commit_msg>Organize imports in benchmark<commit_after>// cargo bench

#![feature(test)]

extern crate test;

use std::io::Write;
use std::{f32, f64};
use test::{black_box, Bencher};

macro_rules! benches {
    ($($name:ident($value:expr),)*) => {
        mod bench_ryu {
            use super::*;
            $(
                #[bench]
                fn $name(b: &mut Bencher) {
                    let mut buf = ryu::Buffer::new();

                    b.iter(move || {
                        let value = black_box($value);
                        let formatted = buf.format_finite(value);
                        black_box(formatted);
                    });
                }
            )*
        }

        mod bench_std_fmt {
            use super::*;
            $(
                #[bench]
                fn $name(b: &mut Bencher) {
                    let mut buf = Vec::with_capacity(20);

                    b.iter(|| {
                        buf.clear();
                        let value = black_box($value);
                        write!(&mut buf, "{}", value).unwrap();
                        black_box(buf.as_slice());
                    });
                }
            )*
        }
    }
}

benches!(
    bench_0_f64(0f64),
    bench_short_f64(0.1234f64),
    bench_e_f64(2.718281828459045f64),
    bench_max_f64(f64::MAX),
    bench_0_f32(0f32),
    bench_short_f32(0.1234f32),
    bench_e_f32(2.718281828459045f32),
    bench_max_f32(f32::MAX),
);
<|endoftext|>


<commit_before>extern crate syscall;

use std::cell::Cell;
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::{env, mem, slice, thread};

use color::Color;
use event::{Event, EVENT_RESIZE};
use renderer::Renderer;
use Mode;
use WindowFlag;

pub fn get_display_size() -> Result<(u32, u32), String> {
    let display_path = try!(env::var("DISPLAY").or(Err("DISPLAY not set")));
    match File::open(&display_path) {
        Ok(display) => {
            let mut buf: [u8; 4096] = [0; 4096];
            let count = syscall::fpath(display.as_raw_fd() as usize, &mut buf)
                .map_err(|err| format!("{}", err))?;
            let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) };
            let res = path.split(":").nth(1).unwrap_or("");
            let width = res
                .split("/")
                .nth(1)
                .unwrap_or("")
                .parse::<u32>()
                .unwrap_or(0);
            let height = res
                .split("/")
                .nth(2)
                .unwrap_or("")
                .parse::<u32>()
                .unwrap_or(0);
            Ok((width, height))
        }
        Err(err) => Err(format!("{}", err)),
    }
}

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: i32,
    /// The y coordinate of the window
    y: i32,
    /// The width of the window
    w: u32,
    /// The height of the window
    h: u32,
    /// The title of the window
    t: String,
    /// True if the window should not wait for events
    window_async: bool,
    /// True if the window can be resized
    resizable: bool,
    /// Drawing mode
    mode: Cell<Mode>,
    /// The input scheme
    file: File,
    /// Window data
    data: &'static mut [Color],
}

impl Renderer for Window {
    /// Get width
    fn width(&self) -> u32 {
        self.w
    }

    /// Get height
    fn height(&self) -> u32 {
        self.h
    }

    /// Access pixel buffer
    fn data(&self) -> &[Color] {
        &self.data
    }

    /// Access pixel buffer mutably
    fn data_mut(&mut self) -> &mut [Color] {
        &mut self.data
    }

    /// Flip the buffer
    fn sync(&mut self) -> bool {
        self.file.sync_data().is_ok()
    }

    /// Set/get mode
    fn mode(&self) -> &Cell<Mode> {
        &self.mode
    }
}

impl Window {
    /// Create a new window
    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Self> {
        Window::new_flags(x, y, w, h, title, &[])
    }

    /// Create a new window with flags
    pub fn new_flags(
        x: i32,
        y: i32,
        w: u32,
        h: u32,
        title: &str,
        flags: &[WindowFlag],
    ) -> Option<Self> {
        let mut flag_str = String::new();

        let mut window_async = false;
        let mut resizable = false;
        for &flag in flags.iter() {
            match flag {
                WindowFlag::Async => {
                    window_async = true;
                    flag_str.push('a');
                }
                WindowFlag::Back => flag_str.push('b'),
                WindowFlag::Front => flag_str.push('f'),
                WindowFlag::Borderless => flag_str.push('l'),
                WindowFlag::Resizable => {
                    resizable = true;
                    flag_str.push('r');
                }
                WindowFlag::Transparent => flag_str.push('t'),
                WindowFlag::Unclosable => flag_str.push('u'),
            }
        }

        if let Ok(file) = File::open(&format!(
            "orbital:{}/{}/{}/{}/{}/{}",
            flag_str, x, y, w, h, title
        )) {
            if let Ok(address) = unsafe {
                syscall::fmap(
                    file.as_raw_fd() as usize,
                    &syscall::Map {
                        offset: 0,
                        size: (w * h * 4) as usize,
                        flags: syscall::PROT_READ | syscall::PROT_WRITE,
                    },
                )
            } {
                Some(Window {
                    x: x,
                    y: y,
                    w: w,
                    h: h,
                    t: title.to_string(),
                    window_async,
                    resizable: resizable,
                    mode: Cell::new(Mode::Blend),
                    file: file,
                    data: unsafe {
                        slice::from_raw_parts_mut(address as *mut Color, (w * h) as usize)
                    },
                })
            } else {
                None
            }
        } else {
            None
        }
    }

    pub fn clipboard(&self) -> String {
        let mut text = String::new();
        let window_fd = self.file.as_raw_fd();
        if let Ok(clipboard_fd) = syscall::dup(window_fd as usize, b"clipboard") {
            let mut clipboard_file = unsafe { File::from_raw_fd(clipboard_fd as RawFd) };
            let _ = clipboard_file.read_to_string(&mut text);
        }
        text
    }

    pub fn set_clipboard(&mut self, text: &str) {
        let window_fd = self.file.as_raw_fd();
        if let Ok(clipboard_fd) = syscall::dup(window_fd as usize, b"clipboard") {
            let mut clipboard_file = unsafe { File::from_raw_fd(clipboard_fd as RawFd) };
            let _ = clipboard_file.write(text.as_bytes());
        }
    }

    /// Not yet available on Redox OS.
    pub fn pop_drop_content(&self) -> Option<String> {
        None
    }

    // TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        let mut buf: [u8; 4096] = [0; 4096];
        if let Ok(count) = syscall::fpath(self.file.as_raw_fd() as usize, &mut buf) {
            let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) };
            // orbital:/x/y/w/h/t
            let mut parts = path.split('/').skip(1);
            if let Some(x) = parts.next() {
                self.x = x.parse::<i32>().unwrap_or(0);
            }
            if let Some(y) = parts.next() {
                self.y = y.parse::<i32>().unwrap_or(0);
            }
            if let Some(w) = parts.next() {
                self.w = w.parse::<u32>().unwrap_or(0);
            }
            if let Some(h) = parts.next() {
                self.h = h.parse::<u32>().unwrap_or(0);
            }
        }
    }

    /// Get x
    // TODO: Sync with window movements
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Get y
    // TODO: Sync with window movements
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set cursor visibility
    pub fn set_mouse_cursor(&mut self, visible: bool) {
        let _ = self.file.write(if visible { b"M,C,1" } else { b"M,C,0" });
    }

    /// Set mouse grabbing
    pub fn set_mouse_grab(&mut self, grab: bool) {
        let _ = self.file.write(if grab { b"M,G,1" } else { b"M,G,0" });
    }

    /// Set mouse relative mode
    pub fn set_mouse_relative(&mut self, relative: bool) {
        let _ = self.file.write(if relative { b"M,R,1" } else { b"M,R,0" });
    }

    /// Set position
    pub fn set_pos(&mut self, x: i32, y: i32) {
        let _ = self.file.write(&format!("P,{},{}", x, y).as_bytes());
        self.sync_path();
    }

    /// Set size
    pub fn set_size(&mut self, width: u32, height: u32) {
        //TODO: Improve safety and reliability
        unsafe {
            syscall::funmap(self.data.as_ptr() as usize)
                .expect("orbclient: failed to unmap memory in resize");
        }
        let _ = self
            .file
            .write(&format!("S,{},{}", width, height).as_bytes());
        self.sync_path();
        unsafe {
            let address = syscall::fmap(
                self.file.as_raw_fd() as usize,
                &syscall::Map {
                    offset: 0,
                    size: (self.w * self.h * 4) as usize,
                    flags: syscall::PROT_READ | syscall::PROT_WRITE,
                },
            )
            .expect("orbclient: failed to map memory in resize");
            self.data =
                slice::from_raw_parts_mut(address as *mut Color, (self.w * self.h) as usize);
        }
    }

    /// Set title
    pub fn set_title(&mut self, title: &str) {
        let _ = self.file.write(&format!("T,{}", title).as_bytes());
        self.sync_path();
    }

    /// Blocking iterator over events
    pub fn events(&mut self) -> EventIter {
        let mut iter = EventIter {
            extra: None,
            events: [Event::new(); 16],
            i: 0,
            count: 0,
        };

        'blocking: loop {
            if iter.count == iter.events.len() {
                if iter.extra.is_none() {
                    iter.extra = Some(Vec::with_capacity(32));
                }
                iter.extra.as_mut().unwrap().extend_from_slice(&iter.events);
                iter.count = 0;
            }
            let bytes = unsafe {
                slice::from_raw_parts_mut(
                    iter.events[iter.count..].as_mut_ptr() as *mut u8,
                    iter.events[iter.count..].len() * mem::size_of::<Event>(),
                )
            };
            match self.file.read(bytes) {
                Ok(0) => {
                    if !self.window_async && iter.extra.is_none() && iter.count == 0 {
                        thread::yield_now();
                    } else {
                        break 'blocking;
                    }
                }
                Ok(count) => {
                    let count = count / mem::size_of::<Event>();
                    let events = &iter.events[iter.count..][..count];
                    iter.count += count;

                    if self.resizable {
                        let mut resize = None;
                        for event in events {
                            let event = *event;
                            if event.code == EVENT_RESIZE {
                                resize = Some((event.a as u32, event.b as u32));
                            }
                        }
                        if let Some((w, h)) = resize {
                            self.set_size(w, h);
                        }
                    }
                    if !self.window_async {
                        // Synchronous windows are blocking, can't attempt another read
                        break 'blocking;
                    }
                }
                Err(_) => break 'blocking,
            }
        }

        iter
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        let _ = unsafe { syscall::funmap(self.data.as_ptr() as usize) };
    }
}

impl AsRawFd for Window {
    fn as_raw_fd(&self) -> RawFd {
        self.file.as_raw_fd()
    }
}

/// Event iterator
pub struct EventIter {
    extra: Option<Vec<Event>>,
    events: [Event; 16],
    i: usize,
    count: usize,
}

impl Iterator for EventIter {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        let mut i = self.i;
        if let Some(ref mut extra) = self.extra {
            if i < extra.len() {
                self.i += 1;
                return Some(extra[i]);
            }
            i -= extra.len();
        }
        if i < self.count {
            self.i += 1;
            return Some(self.events[i]);
        }
        None
    }
}
<commit_msg>fix warning<commit_after>extern crate syscall;

use std::cell::Cell;
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::{env, mem, slice, thread};

use color::Color;
use event::{Event, EVENT_RESIZE};
use renderer::Renderer;
use Mode;
use WindowFlag;

pub fn get_display_size() -> Result<(u32, u32), String> {
    let display_path = env::var("DISPLAY").or(Err("DISPLAY not set"))?;
    match File::open(&display_path) {
        Ok(display) => {
            let mut buf: [u8; 4096] = [0; 4096];
            let count = syscall::fpath(display.as_raw_fd() as usize, &mut buf)
                .map_err(|err| format!("{}", err))?;
            let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) };
            let res = path.split(":").nth(1).unwrap_or("");
            let width = res
                .split("/")
                .nth(1)
                .unwrap_or("")
                .parse::<u32>()
                .unwrap_or(0);
            let height = res
                .split("/")
                .nth(2)
                .unwrap_or("")
                .parse::<u32>()
                .unwrap_or(0);
            Ok((width, height))
        }
        Err(err) => Err(format!("{}", err)),
    }
}

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: i32,
    /// The y coordinate of the window
    y: i32,
    /// The width of the window
    w: u32,
    /// The height of the window
    h: u32,
    /// The title of the window
    t: String,
    /// True if the window should not wait for events
    window_async: bool,
    /// True if the window can be resized
    resizable: bool,
    /// Drawing mode
    mode: Cell<Mode>,
    /// The input scheme
    file: File,
    /// Window data
    data: &'static mut [Color],
}

impl Renderer for Window {
    /// Get width
    fn width(&self) -> u32 {
        self.w
    }

    /// Get height
    fn height(&self) -> u32 {
        self.h
    }

    /// Access pixel buffer
    fn data(&self) -> &[Color] {
        &self.data
    }

    /// Access pixel buffer mutably
    fn data_mut(&mut self) -> &mut [Color] {
        &mut self.data
    }

    /// Flip the buffer
    fn sync(&mut self) -> bool {
        self.file.sync_data().is_ok()
    }

    /// Set/get mode
    fn mode(&self) -> &Cell<Mode> {
        &self.mode
    }
}

impl Window {
    /// Create a new window
    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Self> {
        Window::new_flags(x, y, w, h, title, &[])
    }

    /// Create a new window with flags
    pub fn new_flags(
        x: i32,
        y: i32,
        w: u32,
        h: u32,
        title: &str,
        flags: &[WindowFlag],
    ) -> Option<Self> {
        let mut flag_str = String::new();

        let mut window_async = false;
        let mut resizable = false;
        for &flag in flags.iter() {
            match flag {
                WindowFlag::Async => {
                    window_async = true;
                    flag_str.push('a');
                }
                WindowFlag::Back => flag_str.push('b'),
                WindowFlag::Front => flag_str.push('f'),
                WindowFlag::Borderless => flag_str.push('l'),
                WindowFlag::Resizable => {
                    resizable = true;
                    flag_str.push('r');
                }
                WindowFlag::Transparent => flag_str.push('t'),
                WindowFlag::Unclosable => flag_str.push('u'),
            }
        }

        if let Ok(file) = File::open(&format!(
            "orbital:{}/{}/{}/{}/{}/{}",
            flag_str, x, y, w, h, title
        )) {
            if let Ok(address) = unsafe {
                syscall::fmap(
                    file.as_raw_fd() as usize,
                    &syscall::Map {
                        offset: 0,
                        size: (w * h * 4) as usize,
                        flags: syscall::PROT_READ | syscall::PROT_WRITE,
                    },
                )
            } {
                Some(Window {
                    x: x,
                    y: y,
                    w: w,
                    h: h,
                    t: title.to_string(),
                    window_async,
                    resizable: resizable,
                    mode: Cell::new(Mode::Blend),
                    file: file,
                    data: unsafe {
                        slice::from_raw_parts_mut(address as *mut Color, (w * h) as usize)
                    },
                })
            } else {
                None
            }
        } else {
            None
        }
    }

    pub fn clipboard(&self) -> String {
        let mut text = String::new();
        let window_fd = self.file.as_raw_fd();
        if let Ok(clipboard_fd) = syscall::dup(window_fd as usize, b"clipboard") {
            let mut clipboard_file = unsafe { File::from_raw_fd(clipboard_fd as RawFd) };
            let _ = clipboard_file.read_to_string(&mut text);
        }
        text
    }

    pub fn set_clipboard(&mut self, text: &str) {
        let window_fd = self.file.as_raw_fd();
        if let Ok(clipboard_fd) = syscall::dup(window_fd as usize, b"clipboard") {
            let mut clipboard_file = unsafe { File::from_raw_fd(clipboard_fd as RawFd) };
            let _ = clipboard_file.write(text.as_bytes());
        }
    }

    /// Not yet available on Redox OS.
    pub fn pop_drop_content(&self) -> Option<String> {
        None
    }

    // TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        let mut buf: [u8; 4096] = [0; 4096];
        if let Ok(count) = syscall::fpath(self.file.as_raw_fd() as usize, &mut buf) {
            let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) };
            // orbital:/x/y/w/h/t
            let mut parts = path.split('/').skip(1);
            if let Some(x) = parts.next() {
                self.x = x.parse::<i32>().unwrap_or(0);
            }
            if let Some(y) = parts.next() {
                self.y = y.parse::<i32>().unwrap_or(0);
            }
            if let Some(w) = parts.next() {
                self.w = w.parse::<u32>().unwrap_or(0);
            }
            if let Some(h) = parts.next() {
                self.h = h.parse::<u32>().unwrap_or(0);
            }
        }
    }

    /// Get x
    // TODO: Sync with window movements
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Get y
    // TODO: Sync with window movements
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set cursor visibility
    pub fn set_mouse_cursor(&mut self, visible: bool) {
        let _ = self.file.write(if visible { b"M,C,1" } else { b"M,C,0" });
    }

    /// Set mouse grabbing
    pub fn set_mouse_grab(&mut self, grab: bool) {
        let _ = self.file.write(if grab { b"M,G,1" } else { b"M,G,0" });
    }

    /// Set mouse relative mode
    pub fn set_mouse_relative(&mut self, relative: bool) {
        let _ = self.file.write(if relative { b"M,R,1" } else { b"M,R,0" });
    }

    /// Set position
    pub fn set_pos(&mut self, x: i32, y: i32) {
        let _ = self.file.write(&format!("P,{},{}", x, y).as_bytes());
        self.sync_path();
    }

    /// Set size
    pub fn set_size(&mut self, width: u32, height: u32) {
        //TODO: Improve safety and reliability
        unsafe {
            syscall::funmap(self.data.as_ptr() as usize)
                .expect("orbclient: failed to unmap memory in resize");
        }
        let _ = self
            .file
            .write(&format!("S,{},{}", width, height).as_bytes());
        self.sync_path();
        unsafe {
            let address = syscall::fmap(
                self.file.as_raw_fd() as usize,
                &syscall::Map {
                    offset: 0,
                    size: (self.w * self.h * 4) as usize,
                    flags: syscall::PROT_READ | syscall::PROT_WRITE,
                },
            )
            .expect("orbclient: failed to map memory in resize");
            self.data =
                slice::from_raw_parts_mut(address as *mut Color, (self.w * self.h) as usize);
        }
    }

    /// Set title
    pub fn set_title(&mut self, title: &str) {
        let _ = self.file.write(&format!("T,{}", title).as_bytes());
        self.sync_path();
    }

    /// Blocking iterator over events
    pub fn events(&mut self) -> EventIter {
        let mut iter = EventIter {
            extra: None,
            events: [Event::new(); 16],
            i: 0,
            count: 0,
        };

        'blocking: loop {
            if iter.count == iter.events.len() {
                if iter.extra.is_none() {
                    iter.extra = Some(Vec::with_capacity(32));
                }
                iter.extra.as_mut().unwrap().extend_from_slice(&iter.events);
                iter.count = 0;
            }
            let bytes = unsafe {
                slice::from_raw_parts_mut(
                    iter.events[iter.count..].as_mut_ptr() as *mut u8,
                    iter.events[iter.count..].len() * mem::size_of::<Event>(),
                )
            };
            match self.file.read(bytes) {
                Ok(0) => {
                    if !self.window_async && iter.extra.is_none() && iter.count == 0 {
                        thread::yield_now();
                    } else {
                        break 'blocking;
                    }
                }
                Ok(count) => {
                    let count = count / mem::size_of::<Event>();
                    let events = &iter.events[iter.count..][..count];
                    iter.count += count;

                    if self.resizable {
                        let mut resize = None;
                        for event in events {
                            let event = *event;
                            if event.code == EVENT_RESIZE {
                                resize = Some((event.a as u32, event.b as u32));
                            }
                        }
                        if let Some((w, h)) = resize {
                            self.set_size(w, h);
                        }
                    }
                    if !self.window_async {
                        // Synchronous windows are blocking, can't attempt another read
                        break 'blocking;
                    }
                }
                Err(_) => break 'blocking,
            }
        }

        iter
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        let _ = unsafe { syscall::funmap(self.data.as_ptr() as usize) };
    }
}

impl AsRawFd for Window {
    fn as_raw_fd(&self) -> RawFd {
        self.file.as_raw_fd()
    }
}

/// Event iterator
pub struct EventIter {
    extra: Option<Vec<Event>>,
    events: [Event; 16],
    i: usize,
    count: usize,
}

impl Iterator for EventIter {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        let mut i = self.i;
        if let Some(ref mut extra) = self.extra {
            if i < extra.len() {
                self.i += 1;
                return Some(extra[i]);
            }
            i -= extra.len();
        }
        if i < self.count {
            self.i += 1;
            return Some(self.events[i]);
        }
        None
    }
}
<|endoftext|>


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

use dom::bindings::codegen::WindowBinding;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::bindings::utils::{DOMString, null_str_as_empty, Traceable};
use dom::document::AbstractDocument;
use dom::eventtarget::{EventTarget, WindowTypeId};
use dom::node::{AbstractNode, ScriptView};
use dom::navigator::Navigator;

use layout_interface::ReflowForDisplay;
use script_task::{ExitWindowMsg, FireTimerMsg, Page, ScriptChan};
use servo_msg::compositor_msg::ScriptListener;
use servo_net::image_cache_task::ImageCacheTask;

use js::glue::*;
use js::jsapi::{JSObject, JSContext, JS_DefineProperty, JS_CallTracer};
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp, JSTracer, JSTRACE_OBJECT};
use js::{JSVAL_NULL, JSPROP_ENUMERATE};

use std::cell::Cell;
use std::comm;
use std::comm::SharedChan;
use std::hashmap::HashSet;
use std::ptr;
use std::int;
use std::libc;
use std::rt::io::timer::Timer;
use std::task::spawn_with;
use js::jsapi::JSVal;

pub enum TimerControlMsg {
    TimerMessage_Fire(~TimerData),
    TimerMessage_Close,
    TimerMessage_TriggerExit //XXXjdm this is just a quick hack to talk to the script task
}

pub struct Window {
    eventtarget: EventTarget,
    page: @mut Page,
    script_chan: ScriptChan,
    compositor: @ScriptListener,
    timer_chan: SharedChan<TimerControlMsg>,
    navigator: Option<@mut Navigator>,
    image_cache_task: ImageCacheTask,
    active_timers: ~HashSet<i32>,
    next_timer_handle: i32,
}

impl Window {
    pub fn get_cx(&self) -> *JSObject {
        self.page.js_info.get_ref().js_compartment.cx.ptr
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        self.timer_chan.send(TimerMessage_Close);
    }
}

// Holder for the various JS values associated with setTimeout
// (ie. function value to invoke and all arguments to pass
//      to the function when calling it)
pub struct TimerData {
    handle: i32,
    funval: JSVal,
    args: ~[JSVal],
}

impl Window {
    pub fn Alert(&self, s: &DOMString) {
        // Right now, just print to the console
        println(format!("ALERT: {:s}", null_str_as_empty(s)));
    }

    pub fn Close(&self) {
        self.timer_chan.send(TimerMessage_TriggerExit);
    }

    pub fn Document(&self) -> AbstractDocument {
        self.page.frame.unwrap().document
    }

    pub fn Name(&self) -> DOMString {
        None
    }

    pub fn SetName(&self, _name: &DOMString) {
    }

    pub fn Status(&self) -> DOMString {
        None
    }

    pub fn SetStatus(&self, _status: &DOMString) {
    }

    pub fn Closed(&self) -> bool {
        false
    }

    pub fn Stop(&self) {
    }

    pub fn Focus(&self) {
    }

    pub fn Blur(&self) {
    }

    pub fn GetFrameElement(&self) -> Option<AbstractNode<ScriptView>> {
        None
    }

    pub fn Navigator(&mut self) -> @mut Navigator {
        if self.navigator.is_none() {
            self.navigator = Some(Navigator::new(self));
        }
        self.navigator.unwrap()
    }

    pub fn Confirm(&self, _message: &DOMString) -> bool {
        false
    }

    pub fn Prompt(&self, _message: &DOMString, _default: &DOMString) -> DOMString {
        None
    }

    pub fn Print(&self) {
    }

    pub fn ShowModalDialog(&self, _cx: *JSContext, _url: &DOMString, _argument: JSVal) -> JSVal {
        JSVAL_NULL
    }
}

impl Reflectable for Window {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.eventtarget.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.eventtarget.mut_reflector()
    }
}

impl Window {
    pub fn SetTimeout(&mut self, _cx: *JSContext, callback: JSVal, timeout: i32) -> i32 {
        let timeout = int::max(0, timeout) as u64;
        let handle = self.next_timer_handle;
        self.next_timer_handle += 1;

        // Post a delayed message to the per-window timer task; it will dispatch it
        // to the relevant script handler that will deal with it.
        let tm = Cell::new(Timer::new().unwrap());
        let chan = self.timer_chan.clone();
        do spawn {
            let mut tm = tm.take();
            tm.sleep(timeout);
            chan.send(TimerMessage_Fire(~TimerData {
                handle: handle,
                funval: callback,
                args: ~[]
            }));
        }
        self.active_timers.insert(handle);
        handle
    }

    pub fn ClearTimeout(&mut self, handle: i32) {
        self.active_timers.remove(&handle);
    }

    pub fn content_changed(&self) {
        // FIXME This should probably be ReflowForQuery, not Display. All queries currently
        // currently rely on the display list, which means we can't destroy it by
        // doing a query reflow.
        self.page.reflow_all(ReflowForDisplay, self.script_chan.clone(), self.compositor);
    }

    pub fn wait_until_safe_to_modify_dom(&self) {
        // FIXME: This disables concurrent layout while we are modifying the DOM, since
        //        our current architecture is entirely unsafe in the presence of races.
        self.page.join_layout();
    }

    #[fixed_stack_segment]
    pub fn new(cx: *JSContext,
               page: @mut Page,
               script_chan: ScriptChan,
               compositor: @ScriptListener,
               image_cache_task: ImageCacheTask)
               -> @mut Window {
        let win = @mut Window {
            eventtarget: EventTarget::new_inherited(WindowTypeId),
            page: page,
            script_chan: script_chan.clone(),
            compositor: compositor,
            timer_chan: {
                let (timer_port, timer_chan) = comm::stream::<TimerControlMsg>();
                let id = page.id.clone();
                do spawn_with(script_chan) |script_chan| {
                    loop {
                        match timer_port.recv() {
                            TimerMessage_Close => break,
                            TimerMessage_Fire(td) => script_chan.send(FireTimerMsg(id, td)),
                            TimerMessage_TriggerExit => script_chan.send(ExitWindowMsg(id)),
                        }
                    }
                }
                SharedChan::new(timer_chan)
            },
            navigator: None,
            image_cache_task: image_cache_task,
            active_timers: ~HashSet::new(),
            next_timer_handle: 0
        };

        let global = WindowBinding::Wrap(cx, ptr::null(), win);
        unsafe {
            let fns = ["window","self"];
            for str in fns.iter() {
                do (*str).to_c_str().with_ref |name| {
                JS_DefineProperty(cx, global,  name,
                                  RUST_OBJECT_TO_JSVAL(global),
                                  Some(GetJSClassHookStubPointer(PROPERTY_STUB) as JSPropertyOp),
                                  Some(GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as JSStrictPropertyOp),
                                  JSPROP_ENUMERATE);
                }

            }

        }
        win
    }
}

impl Traceable for Window {
    #[fixed_stack_segment]
    fn trace(&self, tracer: *mut JSTracer) {
        debug!("tracing window");
        unsafe {
            match self.page.frame {
                Some(frame) => {
                    (*tracer).debugPrinter = ptr::null();
                    (*tracer).debugPrintIndex = -1;
                    do "document".to_c_str().with_ref |name| {
                        (*tracer).debugPrintArg = name as *libc::c_void;
                        debug!("tracing document");
                        JS_CallTracer(tracer as *JSTracer,
                                      frame.document.reflector().get_jsobject(),
                                      JSTRACE_OBJECT as u32);
                    }
                }
                None => ()
            }
        }
    }
}
<commit_msg>fix indent & name<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::WindowBinding;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::bindings::utils::{DOMString, null_str_as_empty, Traceable};
use dom::document::AbstractDocument;
use dom::eventtarget::{EventTarget, WindowTypeId};
use dom::node::{AbstractNode, ScriptView};
use dom::navigator::Navigator;

use layout_interface::ReflowForDisplay;
use script_task::{ExitWindowMsg, FireTimerMsg, Page, ScriptChan};
use servo_msg::compositor_msg::ScriptListener;
use servo_net::image_cache_task::ImageCacheTask;

use js::glue::*;
use js::jsapi::{JSObject, JSContext, JS_DefineProperty, JS_CallTracer};
use js::jsapi::{JSPropertyOp, JSStrictPropertyOp, JSTracer, JSTRACE_OBJECT};
use js::{JSVAL_NULL, JSPROP_ENUMERATE};

use std::cell::Cell;
use std::comm;
use std::comm::SharedChan;
use std::hashmap::HashSet;
use std::ptr;
use std::int;
use std::libc;
use std::rt::io::timer::Timer;
use std::task::spawn_with;
use js::jsapi::JSVal;

pub enum TimerControlMsg {
    TimerMessage_Fire(~TimerData),
    TimerMessage_Close,
    TimerMessage_TriggerExit //XXXjdm this is just a quick hack to talk to the script task
}

pub struct Window {
    eventtarget: EventTarget,
    page: @mut Page,
    script_chan: ScriptChan,
    compositor: @ScriptListener,
    timer_chan: SharedChan<TimerControlMsg>,
    navigator: Option<@mut Navigator>,
    image_cache_task: ImageCacheTask,
    active_timers: ~HashSet<i32>,
    next_timer_handle: i32,
}

impl Window {
    pub fn get_cx(&self) -> *JSObject {
        self.page.js_info.get_ref().js_compartment.cx.ptr
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        self.timer_chan.send(TimerMessage_Close);
    }
}

// Holder for the various JS values associated with setTimeout
// (ie. function value to invoke and all arguments to pass
//      to the function when calling it)
pub struct TimerData {
    handle: i32,
    funval: JSVal,
    args: ~[JSVal],
}

impl Window {
    pub fn Alert(&self, s: &DOMString) {
        // Right now, just print to the console
        println(format!("ALERT: {:s}", null_str_as_empty(s)));
    }

    pub fn Close(&self) {
        self.timer_chan.send(TimerMessage_TriggerExit);
    }

    pub fn Document(&self) -> AbstractDocument {
        self.page.frame.unwrap().document
    }

    pub fn Name(&self) -> DOMString {
        None
    }

    pub fn SetName(&self, _name: &DOMString) {
    }

    pub fn Status(&self) -> DOMString {
        None
    }

    pub fn SetStatus(&self, _status: &DOMString) {
    }

    pub fn Closed(&self) -> bool {
        false
    }

    pub fn Stop(&self) {
    }

    pub fn Focus(&self) {
    }

    pub fn Blur(&self) {
    }

    pub fn GetFrameElement(&self) -> Option<AbstractNode<ScriptView>> {
        None
    }

    pub fn Navigator(&mut self) -> @mut Navigator {
        if self.navigator.is_none() {
            self.navigator = Some(Navigator::new(self));
        }
        self.navigator.unwrap()
    }

    pub fn Confirm(&self, _message: &DOMString) -> bool {
        false
    }

    pub fn Prompt(&self, _message: &DOMString, _default: &DOMString) -> DOMString {
        None
    }

    pub fn Print(&self) {
    }

    pub fn ShowModalDialog(&self, _cx: *JSContext, _url: &DOMString, _argument: JSVal) -> JSVal {
        JSVAL_NULL
    }
}

impl Reflectable for Window {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.eventtarget.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.eventtarget.mut_reflector()
    }
}

impl Window {
    pub fn SetTimeout(&mut self, _cx: *JSContext, callback: JSVal, timeout: i32) -> i32 {
        let timeout = int::max(0, timeout) as u64;
        let handle = self.next_timer_handle;
        self.next_timer_handle += 1;

        // Post a delayed message to the per-window timer task; it will dispatch it
        // to the relevant script handler that will deal with it.
        let tm = Cell::new(Timer::new().unwrap());
        let chan = self.timer_chan.clone();
        do spawn {
            let mut tm = tm.take();
            tm.sleep(timeout);
            chan.send(TimerMessage_Fire(~TimerData {
                handle: handle,
                funval: callback,
                args: ~[]
            }));
        }
        self.active_timers.insert(handle);
        handle
    }

    pub fn ClearTimeout(&mut self, handle: i32) {
        self.active_timers.remove(&handle);
    }

    pub fn content_changed(&self) {
        // FIXME This should probably be ReflowForQuery, not Display. All queries currently
        // currently rely on the display list, which means we can't destroy it by
        // doing a query reflow.
        self.page.reflow_all(ReflowForDisplay, self.script_chan.clone(), self.compositor);
    }

    pub fn wait_until_safe_to_modify_dom(&self) {
        // FIXME: This disables concurrent layout while we are modifying the DOM, since
        //        our current architecture is entirely unsafe in the presence of races.
        self.page.join_layout();
    }

    #[fixed_stack_segment]
    pub fn new(cx: *JSContext,
               page: @mut Page,
               script_chan: ScriptChan,
               compositor: @ScriptListener,
               image_cache_task: ImageCacheTask)
               -> @mut Window {
        let win = @mut Window {
            eventtarget: EventTarget::new_inherited(WindowTypeId),
            page: page,
            script_chan: script_chan.clone(),
            compositor: compositor,
            timer_chan: {
                let (timer_port, timer_chan) = comm::stream::<TimerControlMsg>();
                let id = page.id.clone();
                do spawn_with(script_chan) |script_chan| {
                    loop {
                        match timer_port.recv() {
                            TimerMessage_Close => break,
                            TimerMessage_Fire(td) => script_chan.send(FireTimerMsg(id, td)),
                            TimerMessage_TriggerExit => script_chan.send(ExitWindowMsg(id)),
                        }
                    }
                }
                SharedChan::new(timer_chan)
            },
            navigator: None,
            image_cache_task: image_cache_task,
            active_timers: ~HashSet::new(),
            next_timer_handle: 0
        };

        let global = WindowBinding::Wrap(cx, ptr::null(), win);
        unsafe {
            let fn_names = ["window","self"];
            for str in fn_names.iter() {
                do (*str).to_c_str().with_ref |name| {
                    JS_DefineProperty(cx, global,  name,
                                      RUST_OBJECT_TO_JSVAL(global),
                                      Some(GetJSClassHookStubPointer(PROPERTY_STUB) as JSPropertyOp),
                                      Some(GetJSClassHookStubPointer(STRICT_PROPERTY_STUB) as JSStrictPropertyOp),
                                      JSPROP_ENUMERATE);
                }

            }

        }
        win
    }
}

impl Traceable for Window {
    #[fixed_stack_segment]
    fn trace(&self, tracer: *mut JSTracer) {
        debug!("tracing window");
        unsafe {
            match self.page.frame {
                Some(frame) => {
                    (*tracer).debugPrinter = ptr::null();
                    (*tracer).debugPrintIndex = -1;
                    do "document".to_c_str().with_ref |name| {
                        (*tracer).debugPrintArg = name as *libc::c_void;
                        debug!("tracing document");
                        JS_CallTracer(tracer as *JSTracer,
                                      frame.document.reflector().get_jsobject(),
                                      JSTRACE_OBJECT as u32);
                    }
                }
                None => ()
            }
        }
    }
}
<|endoftext|>


<commit_before>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

use rand::distributions::{Sample, Range};
use rand::Rng;

use std::f64;
use std::mem;

use super::MCMove;

use types::{Matrix3, One};
use sys::{System, EnergyCache};

/// Monte-Carlo move that changes the size of the simulation cell
pub struct Resize {
    /// Delta for translation of the box length
    delta: f64,
    /// Sampling range for volume scaling
    range: Range<f64>,
    /// System before applying changes to the simulation box
    old_system: System,
    /// target pressure
    pressure: f64,
    /// largest cut off diameter of `PairPotentials`
    rc_max: f64,
}

impl Resize {
    /// Create a new `Resize` move, with target pressure `pressure` and maximum
    /// displacement of `delta`.
    pub fn new(pressure: f64, delta: f64) -> Resize {
        assert!(delta > 0.0, "delta must be positive in Resize move");
        // TODO: set rc_max from the largest cut off in PairPotentials.
        // For the time being, we set rc_max to zero.
        // That way, the simulation cell can get smaller than 2*rc_max
        // which can lead to wrong energies.
        Resize {
            delta: 0.,
            range: Range::new(-delta, delta),
            old_system: System::new(),
            pressure: pressure,
            rc_max: 0.0,
        }
    }
}

impl MCMove for Resize {
    fn describe(&self) -> &str {
        "resizing of the cell"
    }

    fn prepare(&mut self, system: &mut System, rng: &mut Box<Rng>) -> bool {
        self.delta = self.range.sample(rng);
        // clone the current (old) system
        self.old_system = system.clone();
        let volume = system.volume();
        let scaling_factor = f64::cbrt((volume + self.delta) / volume);
        // change the simulation cell
        system.cell_mut().scale_mut(Matrix3::one() * scaling_factor);
        let new_cell = system.cell().clone();
        // check the radius of the smallest inscribed sphere and compare to the
        // cut off distance.
        // abort simulation when box gets smaller than twice the cutoff radius
        if new_cell.lengths().iter().any(|&d| 0.5 * d <= self.rc_max) {
            fatal_error!(
                "Tried to decrease the cell size but \
                new size conflicts with the cut off radius. \
                You could try to increase the number of particles to get rid \
                of this problem."
            )
        }
        for particle in system.iter_mut() {
            // when changing the size (or shape) of the cell, fractional
            // coordinates do not change.
            // compute fractional coordinates using the old cell
            let fractional = self.old_system.cell().fractional(&particle.position);
            // compute coordinates after resizing the cell
            particle.position = new_cell.cartesian(&fractional);
        }
        true
    }

    fn cost(&self, system: &System, beta: f64, cache: &mut EnergyCache) -> f64 {
        cache.unused();
        // get system energy before change: this is stored in `self.old_system`
        let old_energy = self.old_system.potential_energy();
        // get system energy after preparation
        let new_energy = system.potential_energy();
        let delta_energy = new_energy - old_energy;

        let new_volume = system.volume();
        let old_volume = self.old_system.volume();
        let delta_volume = new_volume - old_volume;

        // return the cost function
        beta * (delta_energy + self.pressure * delta_volume)
            - (system.size() as f64) * f64::ln(new_volume / old_volume)
    }

    fn apply(&mut self, _: &mut System) {
        // Nothing to do
    }

    fn restore(&mut self, system: &mut System) {
        mem::swap(system, &mut self.old_system);
    }

    fn update_amplitude(&mut self, scaling_factor: Option<f64>) {
        if let Some(s) = scaling_factor {
            self.delta *= s;
            self.range = Range::new(-self.delta, self.delta);
        }
    }
}
<commit_msg>Fixed bug which let to wrong (and possibly negative) deltas.<commit_after>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

use rand::distributions::{Sample, Range};
use rand::Rng;

use std::f64;
use std::mem;

use super::MCMove;

use types::{Matrix3, One};
use sys::{System, EnergyCache};

/// Monte-Carlo move that changes the size of the simulation cell
pub struct Resize {
    /// Delta for translation of the box length
    delta: f64,
    /// Sampling range for volume scaling
    range: Range<f64>,
    /// System before applying changes to the simulation box
    old_system: System,
    /// target pressure
    pressure: f64,
    /// largest cut off diameter of `PairPotentials`
    rc_max: f64,
}

impl Resize {
    /// Create a new `Resize` move, with target pressure `pressure` and maximum
    /// displacement of `delta`.
    pub fn new(pressure: f64, delta: f64) -> Resize {
        assert!(delta > 0.0, "delta must be positive in Resize move");
        // TODO: set rc_max from the largest cut off in PairPotentials.
        // For the time being, we set rc_max to zero.
        // That way, the simulation cell can get smaller than 2*rc_max
        // which can lead to wrong energies.
        Resize {
            delta: delta,
            range: Range::new(-delta, delta),
            old_system: System::new(),
            pressure: pressure,
            rc_max: 0.0,
        }
    }
}

impl MCMove for Resize {
    fn describe(&self) -> &str {
        "resizing of the cell"
    }

    fn prepare(&mut self, system: &mut System, rng: &mut Box<Rng>) -> bool {
        let delta = self.range.sample(rng);
        // clone the current (old) system
        self.old_system = system.clone();
        let volume = system.volume();
        let scaling_factor = f64::cbrt((volume + delta) / volume);
        // change the simulation cell
        system.cell_mut().scale_mut(Matrix3::one() * scaling_factor);
        let new_cell = system.cell().clone();
        // check the radius of the smallest inscribed sphere and compare to the
        // cut off distance.
        // abort simulation when box gets smaller than twice the cutoff radius
        if new_cell.lengths().iter().any(|&d| 0.5 * d <= self.rc_max) {
            fatal_error!(
                "Tried to decrease the cell size but \
                new size conflicts with the cut off radius. \
                You could try to increase the number of particles to get rid \
                of this problem."
            )
        }
        for particle in system.iter_mut() {
            // when changing the size (or shape) of the cell, fractional
            // coordinates do not change.
            // compute fractional coordinates using the old cell
            let fractional = self.old_system.cell().fractional(&particle.position);
            // compute coordinates after resizing the cell
            particle.position = new_cell.cartesian(&fractional);
        }
        true
    }

    fn cost(&self, system: &System, beta: f64, cache: &mut EnergyCache) -> f64 {
        cache.unused();
        // get system energy before change: this is stored in `self.old_system`
        let old_energy = self.old_system.potential_energy();
        // get system energy after preparation
        let new_energy = system.potential_energy();
        let delta_energy = new_energy - old_energy;

        let new_volume = system.volume();
        let old_volume = self.old_system.volume();
        let delta_volume = new_volume - old_volume;

        // return the cost function
        beta * (delta_energy + self.pressure * delta_volume)
            - (system.size() as f64) * f64::ln(new_volume / old_volume)
    }

    fn apply(&mut self, _: &mut System) {
        // Nothing to do
    }

    fn restore(&mut self, system: &mut System) {
        mem::swap(system, &mut self.old_system);
    }

    fn update_amplitude(&mut self, scaling_factor: Option<f64>) {
        if let Some(s) = scaling_factor {
            self.delta *= s;
            self.range = Range::new(-self.delta, self.delta);
        }
    }
}
<|endoftext|>