<commit_before>extern crate libc;
extern crate ncurses;

mod util;

use std::io::{stdin, Read, BufRead, BufReader};
use std::error::Error;
use std::sync::{Arc, Mutex};
use std::thread;
use std::process::{Command, Stdio, exit};
use std::char;
use std::mem;
use std::sync::mpsc::{Sender, Receiver, channel};
use util::eventbox::EventBox;

use ncurses::*;

//==============================================================================

struct FZF {
    query: String,
}

//==============================================================================
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
enum Event{
    EV_READER_NEW,
    EV_READER_FIN,
    EV_MATCHER_NEW_ITEM,
    EV_MATCHER_RESET_QUERY,
    EV_MATCHER_UPDATE_PROCESS,
    EV_MATCHER_FINISHED,
    EV_QUERY_MOVE_CURSOR,
    EV_QUERY_CHANGE,
    EV_INPUT_TOGGLE,
    EV_INPUT_UP,
    EV_INPUT_DOWN,
    EV_INPUT_SELECT,
}

// matcher will receive two events:
// 1. EV_MATCHER_NEW_ITEM, to reset the input strings
// 2. EV_MATCHER_RESET_QUERY, to interrupt current processing.
//
// will send two events:
// 1. EV_MATCHER_UPDATE_PROCESS, to notify the matched/total items
// 2. EV_MATCHER_FINISHED.

struct Matcher {
    rx_source: Receiver<String>, // channel to retrieve strings from reader
    tx_output: Sender<String>,   // channel to send output to
    eb_req: Arc<EventBox<Event>>,       // event box that recieve requests
    eb_notify: Arc<EventBox<Event>>,    // event box that send out notification
    items: Vec<String>,
    item_pos: usize,
    query: String,
}

impl Matcher {
    pub fn new(rx_source: Receiver<String>, tx_output: Sender<String>,
               eb_req: Arc<EventBox<Event>>, eb_notify: Arc<EventBox<Event>>) -> Self {
        Matcher{
            rx_source: rx_source,
            tx_output: tx_output,
            eb_req: eb_req,
            eb_notify: eb_notify,
            items: Vec::new(),
            item_pos: 0,
            query: String::new(),
        }
    }

    pub fn process(&mut self) {
        for string in self.items[self.item_pos..].into_iter() {
            // process the matcher
            //self.tx_output.send(string.clone());
            (*self.eb_notify).set(Event::EV_MATCHER_UPDATE_PROCESS, Box::new(0));
            self.tx_output.send(string.clone());

            self.item_pos += 1;
            if (self.item_pos % 100) == 99 && !self.eb_req.is_empty() {
                break;
            }
        }
    }

    fn read_new_item(&mut self) {
        while let Ok(string) = self.rx_source.try_recv() {
            self.items.push(string);
        }
    }

    fn reset_query(&mut self, query: &str) {
        self.query.clear();
        self.query.push_str(query);
    }

    pub fn run(&mut self) {
        loop {
            for (e, val) in (*self.eb_req).wait() {
                match e {
                    Event::EV_MATCHER_NEW_ITEM => { self.read_new_item();}
                    Event::EV_MATCHER_RESET_QUERY => {
                        self.reset_query(&val.downcast::<String>().unwrap());
                    }
                    _ => {}
                }
            }

            self.process()
        }
    }
}

//==============================================================================
// Input: fetch the query string, handle key event

struct Input {
    query: Vec<char>,
    index: usize, // index in chars
    pos: usize, // position in bytes
    eb: Arc<EventBox<Event>>,
}

impl Input {
    pub fn new(eb: Arc<EventBox<Event>>) -> Self {
        Input {
            query: Vec::new(),
            index: 0,
            pos: 0,
            eb: eb,
        }
    }

    fn get_query(&self) -> String {
        self.query.iter().cloned().collect::<String>()
    }

    fn add_char (&mut self, ch: char) {
        self.query.insert(self.index, ch);
        self.index += 1;
        self.pos += if ch.len_utf8() > 1 {2} else {1};
    }

    fn delete_char(&mut self) {
        if self.index == 0 {
            return;
        }

        let ch = self.query.remove(self.index-1);
        self.index -= 1;
        self.pos -= if ch.len_utf8() > 1 {2} else {1};
    }

    pub fn run(&mut self) {
        loop {
            self.handle_char();
        }
    }

    // fetch input from curses and turn it into query.
    fn handle_char(&mut self) {
        let ch = wget_wch(stdscr);

        let orig_query = self.query.clone();

        match ch {
            Some(WchResult::KeyCode(_)) => {
                // will later handle readline-like shortcuts
            }

            Some(WchResult::Char(c)) => {
                /* Enable attributes and output message. */
                let ch = char::from_u32(c as u32).expect("Invalid char");
                match ch {
                    '\x7F' => { // backspace
                        self.delete_char();
                        self.eb.set(Event::EV_QUERY_CHANGE, Box::new((self.get_query(), self.pos)));
                    }
                    ch => { // other characters
                        self.add_char(ch);
                        self.eb.set(Event::EV_QUERY_CHANGE, Box::new((self.get_query(), self.pos)));
                    }
                }
            }

            None => { }
        }
    }
}

//==============================================================================
// Reader: fetch a list of lines from stdin or command output

const READER_LINES_CACHED: usize = 100;

struct Reader {
    cmd: Option<&'static str>, // command to invoke
    eb: Arc<EventBox<Event>>,         // eventbox
    tx: Sender<String>,    // sender to send the string read from command output
}

impl Reader {

    pub fn new(cmd: Option<&'static str>, eb: Arc<EventBox<Event>>, tx: Sender<String>) -> Self {
        Reader{cmd: cmd, eb: eb, tx: tx}
    }

    // invoke find comand.
    fn get_command_output(&self) -> Result<Box<BufRead>, Box<Error>> {
        let command = try!(Command::new("sh")
                           .arg("-c")
                           .arg(self.cmd.unwrap_or("find ."))
                           .stdout(Stdio::piped())
                           .stderr(Stdio::null())
                           .spawn());
        let stdout = try!(command.stdout.ok_or("command output: unwrap failed".to_owned()));
        Ok(Box::new(BufReader::new(stdout)))
    }

    fn run(&mut self) {
        // check if the input is TTY
        let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;

        let mut read;
        if istty {
            read = self.get_command_output().expect("command not found");
        } else {
            read = Box::new(BufReader::new(stdin()))
        };

        loop {
            let mut input = String::new();
            match read.read_line(&mut input) {
                Ok(n) => {
                    if n <= 0 { break; }

                    if input.ends_with("\n") {
                        input.pop();
                        if input.ends_with("\r") {
                            input.pop();
                        }
                    }
                    self.tx.send(input);
                }
                Err(_err) => { break; }
            }
            self.eb.set(Event::EV_READER_NEW, Box::new(0));
        }
        self.eb.set(Event::EV_READER_FIN, Box::new(0));
    }
}

//==============================================================================
// Model: data structure for display the result
struct Model {
    query: String,
    query_cursor: i32,
    num_matched: u64,
    num_total: u64,
    matched_items: Vec<String>,
    item_start_pos: i64,
    line_cursor: i32,
    max_y: i32,
    max_x: i32,
}

impl Model {
    pub fn new() -> Self {
        let mut max_y = 0;
        let mut max_x = 0;
        getmaxyx(stdscr, &mut max_y, &mut max_x);

        Model {
            query: String::new(),
            query_cursor: 0,
            num_matched: 0,
            num_total: 0,
            matched_items: Vec::new(),
            item_start_pos: 0,
            line_cursor: 0,
            max_y: max_y,
            max_x: max_x,
        }
    }

    pub fn update_query(&mut self, query: String, cursor: i32) {
        self.query = query;
        self.query_cursor = cursor;
    }

    pub fn update_process_info(&mut self, matched: u64, total: u64) {
        self.num_matched = matched;
        self.num_total = total;
    }

    pub fn push_item(&mut self, item: String) {
        self.matched_items.push(item);
    }

    pub fn move_line_cursor(&mut self, diff: i32) {
        self.line_cursor += diff;
    }

    pub fn print_query(&self) {
        // > query
        mv(self.max_y-1, 0);
        clrtoeol();
        printw("> ");
        addstr(&self.query);
        mv(self.max_y-1, self.query_cursor+2);
    }

    pub fn print_info(&self) {
        mv(self.max_y-2, 0);
        clrtoeol();
        printw(format!("  {}/{}", self.num_matched, self.num_total).as_str());
    }

    pub fn print_items(&self) {
        let mut y = self.max_y - 2;
        for item in self.matched_items.iter() {
            mv(y, 2);

            let shown_str: String = item.chars().take((self.max_x-1) as usize).collect();
            addstr(&shown_str);

            y -= 1;
            if y <= 0 {
                break;
            }
        }
    }

    pub fn refresh(&self) {
        refresh();
    }

    pub fn display(&self) {
        self.print_items();
        self.print_info();
        self.print_query();
        self.refresh();
    }
}

//==============================================================================
// Display: for printing the result

//==============================================================================

fn main() {
    // initialize ncurses
    let local_conf = LcCategory::all;
    setlocale(local_conf, "en_US.UTF-8"); // for showing wide characters
    initscr();
    raw();
    keypad(stdscr, true);
    noecho();

    let mut model = Model::new();

    let eb = Arc::new(EventBox::new());
    let (tx_source, rx_source) = channel();
    let (tx_matched, rx_matched) = channel();

    let eb_clone_reader = eb.clone();
    let mut reader = Reader::new(Some(&"find ."), eb_clone_reader, tx_source);

    let eb_matcher = Arc::new(EventBox::new());
    let eb_matcher_clone = eb_matcher.clone();
    let eb_clone_matcher = eb.clone();
    let mut matcher = Matcher::new(rx_source, tx_matched, eb_matcher_clone, eb_clone_matcher);

    let eb_clone_input = eb.clone();
    let mut input = Input::new(eb_clone_input);

    // start running
    thread::spawn(move || {
        reader.run();
    });

    thread::spawn(move || {
        matcher.run();
    });

    thread::spawn(move || {
        input.run();
    });

    loop {
        for (e, val) in eb.wait() {
            match e {
                Event::EV_READER_NEW => {
                    //printw("READER_NEW!\n");
                    eb_matcher.set(Event::EV_MATCHER_NEW_ITEM, Box::new(true));
                }

                Event::EV_READER_FIN => {
                    //printw("READER_FIN\n");
                }

                Event::EV_MATCHER_UPDATE_PROCESS => {
                    while let Ok(string) = rx_matched.try_recv() {
                        model.push_item(string);
                    }
                }

                Event::EV_QUERY_CHANGE => {
                    let (query, pos) : (String, usize) = *val.downcast().unwrap();
                    let modified = query == model.query;
                    model.update_query(query.clone(), pos as i32);

                    if modified {
                        eb_matcher.set(Event::EV_MATCHER_RESET_QUERY, Box::new(model.query.clone()));
                    }
                }

                _ => {
                    printw(format!("{}\n", e as i32).as_str());
                }
            }
        }
        model.display();
        refresh();
    };
}
<commit_msg>basic structure for reader/matcher/input done.<commit_after>extern crate libc;
extern crate ncurses;

mod util;

use std::io::{stdin, Read, BufRead, BufReader};
use std::error::Error;
use std::sync::{Arc, Mutex};
use std::thread;
use std::process::{Command, Stdio, exit};
use std::char;
use std::mem;
use std::sync::mpsc::{Sender, Receiver, channel};
use util::eventbox::EventBox;

use ncurses::*;

//==============================================================================

struct FZF {
    query: String,
}

//==============================================================================
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
enum Event{
    EvReaderNewItem,
    EvReaderFinished,
    EvMatcherNewItem,
    EvMatcherResetQuery,
    EvMatcherUpdateProcess,
    EvMatcherFinished,
    EvQueryChange,
    EvInputToggle,
    EvInputUp,
    EvInputDown,
    EvInputSelect,
}

// matcher will receive two events:
// 1. EvMatcherNewItem, to reset the input strings
// 2. EvMatcherResetQuery, to interrupt current processing.
//
// will send two events:
// 1. EvMatcherUpdateProcess, to notify the matched/total items
// 2. EvMatcherFinished.

struct Matcher {
    rx_source: Receiver<String>, // channel to retrieve strings from reader
    tx_output: Sender<String>,   // channel to send output to
    eb_req: Arc<EventBox<Event>>,       // event box that recieve requests
    eb_notify: Arc<EventBox<Event>>,    // event box that send out notification
    items: Vec<String>,
    item_pos: usize,
    num_matched: u64,
    query: String,
}

impl Matcher {
    pub fn new(rx_source: Receiver<String>, tx_output: Sender<String>,
               eb_req: Arc<EventBox<Event>>, eb_notify: Arc<EventBox<Event>>) -> Self {
        Matcher {
            rx_source: rx_source,
            tx_output: tx_output,
            eb_req: eb_req,
            eb_notify: eb_notify,
            items: Vec::new(),
            item_pos: 0,
            num_matched: 0,
            query: String::new(),
        }
    }

    fn match_str(&self, item: &str) -> bool {
        if self.query == "" {
            return true;
        }

        item.starts_with(&self.query)
    }

    pub fn process(&mut self) {
        for string in self.items[self.item_pos..].into_iter() {
            // process the matcher
            //self.tx_output.send(string.clone());
            if self.match_str(string) {
                self.num_matched += 1;
                self.tx_output.send(string.clone());
            }

            (*self.eb_notify).set(Event::EvMatcherUpdateProcess, Box::new((self.num_matched, self.items.len() as u64)));

            self.item_pos += 1;
            if (self.item_pos % 100) == 99 && !self.eb_req.is_empty() {
                break;
            }
        }
    }

    fn read_new_item(&mut self) {
        while let Ok(string) = self.rx_source.try_recv() {
            self.items.push(string);
        }
    }

    fn reset_query(&mut self, query: &str) {
        self.query.clear();
        self.query.push_str(query);
        self.num_matched = 0;
        self.item_pos = 0;
    }

    pub fn run(&mut self) {
        loop {
            for (e, val) in (*self.eb_req).wait() {
                match e {
                    Event::EvMatcherNewItem => { self.read_new_item();}
                    Event::EvMatcherResetQuery => {
                        self.reset_query(&val.downcast::<String>().unwrap());
                    }
                    _ => {}
                }
            }

            self.process()
        }
    }
}

//==============================================================================
// Input: fetch the query string, handle key event

struct Input {
    query: Vec<char>,
    index: usize, // index in chars
    pos: usize, // position in bytes
    eb: Arc<EventBox<Event>>,
}

impl Input {
    pub fn new(eb: Arc<EventBox<Event>>) -> Self {
        Input {
            query: Vec::new(),
            index: 0,
            pos: 0,
            eb: eb,
        }
    }

    fn get_query(&self) -> String {
        self.query.iter().cloned().collect::<String>()
    }

    fn add_char (&mut self, ch: char) {
        self.query.insert(self.index, ch);
        self.index += 1;
        self.pos += if ch.len_utf8() > 1 {2} else {1};
    }

    fn delete_char(&mut self) {
        if self.index == 0 {
            return;
        }

        let ch = self.query.remove(self.index-1);
        self.index -= 1;
        self.pos -= if ch.len_utf8() > 1 {2} else {1};
    }

    pub fn run(&mut self) {
        loop {
            self.handle_char();
        }
    }

    // fetch input from curses and turn it into query.
    fn handle_char(&mut self) {
        let ch = wget_wch(stdscr);

        let orig_query = self.query.clone();

        match ch {
            Some(WchResult::KeyCode(_)) => {
                // will later handle readline-like shortcuts
            }

            Some(WchResult::Char(c)) => {
                /* Enable attributes and output message. */
                let ch = char::from_u32(c as u32).expect("Invalid char");
                match ch {
                    '\x7F' => { // backspace
                        self.delete_char();
                        self.eb.set(Event::EvQueryChange, Box::new((self.get_query(), self.pos)));
                    }

                    '\x0A' => { // enter
                        self.eb.set(Event::EvInputSelect, Box::new(true));
                    }

                    ch => { // other characters
                        self.add_char(ch);
                        self.eb.set(Event::EvQueryChange, Box::new((self.get_query(), self.pos)));
                    }
                }
            }

            None => { }
        }
    }
}

//==============================================================================
// Reader: fetch a list of lines from stdin or command output

const READER_LINES_CACHED: usize = 100;

struct Reader {
    cmd: Option<&'static str>, // command to invoke
    eb: Arc<EventBox<Event>>,         // eventbox
    tx: Sender<String>,    // sender to send the string read from command output
}

impl Reader {

    pub fn new(cmd: Option<&'static str>, eb: Arc<EventBox<Event>>, tx: Sender<String>) -> Self {
        Reader{cmd: cmd, eb: eb, tx: tx}
    }

    // invoke find comand.
    fn get_command_output(&self) -> Result<Box<BufRead>, Box<Error>> {
        let command = try!(Command::new("sh")
                           .arg("-c")
                           .arg(self.cmd.unwrap_or("find ."))
                           .stdout(Stdio::piped())
                           .stderr(Stdio::null())
                           .spawn());
        let stdout = try!(command.stdout.ok_or("command output: unwrap failed".to_owned()));
        Ok(Box::new(BufReader::new(stdout)))
    }

    fn run(&mut self) {
        // check if the input is TTY
        let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0;

        let mut read;
        if istty {
            read = self.get_command_output().expect("command not found");
        } else {
            read = Box::new(BufReader::new(stdin()))
        };

        loop {
            let mut input = String::new();
            match read.read_line(&mut input) {
                Ok(n) => {
                    if n <= 0 { break; }

                    if input.ends_with("\n") {
                        input.pop();
                        if input.ends_with("\r") {
                            input.pop();
                        }
                    }
                    self.tx.send(input);
                }
                Err(_err) => { break; }
            }
            self.eb.set(Event::EvReaderNewItem, Box::new(0));
        }
        self.eb.set(Event::EvReaderFinished, Box::new(0));
    }
}

//==============================================================================
// Model: data structure for display the result
struct Model {
    query: String,
    query_cursor: i32,
    num_matched: u64,
    num_total: u64,
    matched_items: Vec<String>,
    item_start_pos: i64,
    line_cursor: i32,
    max_y: i32,
    max_x: i32,
}

impl Model {
    pub fn new() -> Self {
        let mut max_y = 0;
        let mut max_x = 0;
        getmaxyx(stdscr, &mut max_y, &mut max_x);

        Model {
            query: String::new(),
            query_cursor: 0,
            num_matched: 0,
            num_total: 0,
            matched_items: Vec::new(),
            item_start_pos: 0,
            line_cursor: 0,
            max_y: max_y,
            max_x: max_x,
        }
    }

    pub fn update_query(&mut self, query: String, cursor: i32) {
        self.query = query;
        self.query_cursor = cursor;
    }

    pub fn update_process_info(&mut self, matched: u64, total: u64) {
        self.num_matched = matched;
        self.num_total = total;
    }

    pub fn push_item(&mut self, item: String) {
        self.matched_items.push(item);
    }

    pub fn clear_items(&mut self) {
        self.matched_items.clear();
    }

    pub fn move_line_cursor(&mut self, diff: i32) {
        self.line_cursor += diff;
    }

    pub fn print_query(&self) {
        // > query
        mv(self.max_y-1, 0);
        addstr("> ");
        addstr(&self.query);
        mv(self.max_y-1, self.query_cursor+2);
    }

    pub fn print_info(&self) {
        mv(self.max_y-2, 0);
        addstr(format!("  {}/{}", self.num_matched, self.num_total).as_str());
    }

    pub fn print_items(&self) {
        let mut y = self.max_y - 2;
        for item in self.matched_items.iter() {
            mv(y, 2);

            let shown_str: String = item.chars().take((self.max_x-1) as usize).collect();
            addstr(&shown_str);

            y -= 1;
            if y <= 0 {
                break;
            }
        }
    }

    pub fn refresh(&self) {
        refresh();
    }

    pub fn display(&self) {
        erase();
        self.print_items();
        self.print_info();
        self.print_query();
        self.refresh();
    }
}

//==============================================================================
// Display: for printing the result

//==============================================================================

fn main() {
    // initialize ncurses
    let local_conf = LcCategory::all;
    setlocale(local_conf, "en_US.UTF-8"); // for showing wide characters
    initscr();
    raw();
    keypad(stdscr, true);
    noecho();

    let mut model = Model::new();

    let eb = Arc::new(EventBox::new());
    let (tx_source, rx_source) = channel();
    let (tx_matched, rx_matched) = channel();

    let eb_clone_reader = eb.clone();
    let mut reader = Reader::new(Some(&"find ."), eb_clone_reader, tx_source);

    let eb_matcher = Arc::new(EventBox::new());
    let eb_matcher_clone = eb_matcher.clone();
    let eb_clone_matcher = eb.clone();
    let mut matcher = Matcher::new(rx_source, tx_matched, eb_matcher_clone, eb_clone_matcher);

    let eb_clone_input = eb.clone();
    let mut input = Input::new(eb_clone_input);

    // start running
    thread::spawn(move || {
        reader.run();
    });

    thread::spawn(move || {
        matcher.run();
    });

    thread::spawn(move || {
        input.run();
    });

    'outer: loop {
        for (e, val) in eb.wait() {
            match e {
                Event::EvReaderNewItem | Event::EvReaderFinished => {
                    eb_matcher.set(Event::EvMatcherNewItem, Box::new(true));
                }

                Event::EvMatcherUpdateProcess => {
                    let (matched, total) : (u64, u64) = *val.downcast().unwrap();
                    model.update_process_info(matched, total);

                    while let Ok(string) = rx_matched.try_recv() {
                        model.push_item(string);
                    }
                }

                Event::EvQueryChange => {
                    let (query, pos) : (String, usize) = *val.downcast().unwrap();
                    let modified = query != model.query;
                    model.update_query(query.clone(), pos as i32);

                    if modified {
                        model.clear_items();
                        eb_matcher.set(Event::EvMatcherResetQuery, Box::new(model.query.clone()));
                    }
                }

                Event::EvInputSelect => {
                    // break out of the loop and output the selected item.
                    break 'outer;
                }

                _ => {
                    printw(format!("{}\n", e as i32).as_str());
                }
            }
        }
        model.display();
        refresh();
    };

    endwin();
}
<|endoftext|>


<commit_before>/*
** A simple program that allows basic arithmetic operations using roman numerals and conversions to decimal numbers.
*/

fn main() {

	let roman_number = "CLIII";
	let decimal_number = to_decimal(&roman_number);

	println!("The roman number {} is equal to {} in decimal numbers", roman_number, decimal_number);

	let roman_number = "XXXIV";
	let decimal_number = to_decimal(&roman_number);

	println!("The roman number {} is equal to {} in decimal numbers", roman_number, decimal_number);
}

fn to_decimal(roman_number: &str) -> i32 {

	let mut num = 0;

	for c in roman_number.chars() {
		num += roman_char_to_decimal(c);
	}

	num
}

fn roman_char_to_decimal(roman_char: char) -> i32 {

	match roman_char {
	    'I' => 1,
	    'V' => 5,
	    'X' => 10,
	    'L' => 50,
	    'C' => 100,
	    'D' => 500,
	    'M' => 1000,
	    _ => 0,
	}
}<commit_msg>Fix current implementation to allow subtractive notation.<commit_after>/*
** A simple program that allows basic arithmetic operations using roman numerals and conversions to decimal numbers.
*/

fn main() {

	let roman_number = "CLIII";
	let decimal_number = to_decimal(&roman_number);

	println!("The roman number {} is equal to {} in decimal numbers", roman_number, decimal_number);

	let roman_number = "XXXIV";
	let decimal_number = to_decimal(&roman_number);

	println!("The roman number {} is equal to {} in decimal numbers", roman_number, decimal_number);
}

fn to_decimal(roman_number: &str) -> i32 {

	let mut num = 0;
	let mut prev = 0;

	for c in roman_number.chars() {

		let digit = roman_char_to_decimal(c);

		num += digit;

		if prev != 0 && digit > prev {
			num -= 2 * prev;
		}

		prev = digit;
	}

	num
}

fn roman_char_to_decimal(roman_char: char) -> i32 {

	match roman_char {
	    'I' => 1,
	    'V' => 5,
	    'X' => 10,
	    'L' => 50,
	    'C' => 100,
	    'D' => 500,
	    'M' => 1000,
	    _ => 0,
	}
}<|endoftext|>


<commit_before>#![forbid(unsafe_code)]

pub mod api;
pub mod db;
pub mod indexer;
pub mod model;
pub mod opening;
pub mod util;

use std::{mem, net::SocketAddr, path::PathBuf, sync::Arc, time::Duration};

use axum::{
    extract::{Extension, Path, Query},
    handler::get,
    http::StatusCode,
    AddExtensionLayer, Router,
};
use clap::Clap;
use futures_util::stream::Stream;
use shakmaty::{fen::Fen, variant::VariantPosition, zobrist::Zobrist, CastlingMode};
use tokio::sync::watch;

use crate::{
    api::{
        Error, GameRow, GameRowWithUci, NdJson, PersonalMoveRow, PersonalQuery,
        PersonalQueryFilter, PersonalResponse,
    },
    db::Database,
    indexer::{IndexerOpt, IndexerStub},
    model::{PersonalKeyBuilder, PersonalKeyPrefix, UserId},
    opening::{Opening, Openings},
    util::DedupStreamExt as _,
};

#[derive(Clap)]
struct Opt {
    #[clap(long = "bind", default_value = "127.0.0.1:9000")]
    bind: SocketAddr,
    #[clap(long = "db", default_value = "_db")]
    db: PathBuf,
    #[clap(flatten)]
    indexer: IndexerOpt,
}

#[tokio::main]
async fn main() {
    env_logger::Builder::from_env(
        env_logger::Env::new()
            .filter("EXPLORER_LOG")
            .write_style("EXPLORER_LOG_STYLE"),
    )
    .format_timestamp(None)
    .format_module_path(false)
    .init();

    let opt = Opt::parse();

    let openings: &'static Openings = Box::leak(Box::new(Openings::build_table()));
    let db = Arc::new(Database::open(opt.db).expect("db"));
    let (indexer, join_handles) = IndexerStub::spawn(db.clone(), opt.indexer);

    let app = Router::new()
        .route("/admin/:prop", get(db_property))
        .route("/admin/game/:prop", get(game_property))
        .route("/admin/personal/:prop", get(personal_property))
        .route("/personal", get(personal))
        .layer(AddExtensionLayer::new(openings))
        .layer(AddExtensionLayer::new(db))
        .layer(AddExtensionLayer::new(indexer));

    axum::Server::bind(&opt.bind)
        .serve(app.into_make_service())
        .await
        .expect("bind");

    for join_handle in join_handles {
        join_handle.await.expect("indexer");
    }
}

async fn db_property(
    Extension(db): Extension<Arc<Database>>,
    Path(prop): Path<String>,
) -> Result<String, StatusCode> {
    db.queryable()
        .db_property(&prop)
        .expect("get property")
        .ok_or(StatusCode::NOT_FOUND)
}

async fn game_property(
    Extension(db): Extension<Arc<Database>>,
    Path(prop): Path<String>,
) -> Result<String, StatusCode> {
    db.queryable()
        .game_property(&prop)
        .expect("get property")
        .ok_or(StatusCode::NOT_FOUND)
}

async fn personal_property(
    Extension(db): Extension<Arc<Database>>,
    Path(prop): Path<String>,
) -> Result<String, StatusCode> {
    db.queryable()
        .personal_property(&prop)
        .expect("get property")
        .ok_or(StatusCode::NOT_FOUND)
}

struct PersonalStreamState {
    indexing: Option<watch::Receiver<()>>,
    key: PersonalKeyPrefix,
    db: Arc<Database>,
    filter: PersonalQueryFilter,
    pos: VariantPosition,
    opening: Option<&'static Opening>,
    first: bool,
    done: bool,
}

async fn personal(
    Extension(openings): Extension<&'static Openings>,
    Extension(db): Extension<Arc<Database>>,
    Extension(indexer): Extension<IndexerStub>,
    Query(query): Query<PersonalQuery>,
) -> Result<NdJson<impl Stream<Item = PersonalResponse>>, Error> {
    let player = UserId::from(query.player);
    let indexing = indexer.index_player(&player).await;

    let variant = query.variant.into();

    let mut pos = Zobrist::new(match query.fen {
        Some(fen) => VariantPosition::from_setup(variant, &Fen::from(fen), CastlingMode::Chess960)?,
        None => VariantPosition::new(variant),
    });

    let opening = openings.classify_and_play(&mut pos, query.play)?;

    let key = PersonalKeyBuilder::with_user_pov(&player, query.color)
        .with_zobrist(variant, pos.zobrist_hash());

    let state = PersonalStreamState {
        filter: query.filter,
        db,
        indexing,
        opening,
        key,
        pos: pos.into_inner(),
        first: true,
        done: false,
    };

    Ok(NdJson(futures_util::stream::unfold(
        state,
        |mut state| async move {
            if state.done {
                return None;
            }

            let first = mem::replace(&mut state.first, false);
            state.done = match state.indexing {
                Some(ref mut indexing) => {
                    tokio::select! {
                        _ = indexing.changed() => true,
                        _ = tokio::time::sleep(Duration::from_millis(if first { 0 } else { 1000 })) => false,
                    }
                }
                None => true,
            };

            let queryable = state.db.queryable();
            let filtered = queryable
                .get_personal(&state.key, state.filter.since, state.filter.until)
                .expect("get personal")
                .prepare(&state.pos, &state.filter);

            Some((
                PersonalResponse {
                    total: filtered.total,
                    moves: filtered
                        .moves
                        .into_iter()
                        .map(|row| PersonalMoveRow {
                            uci: row.uci,
                            san: row.san,
                            stats: row.stats,
                            game: row.game.and_then(|id| {
                                queryable
                                    .get_game_info(id)
                                    .expect("get game")
                                    .map(|info| GameRow { id, info })
                            }),
                        })
                        .collect(),
                    recent_games: filtered
                        .recent_games
                        .into_iter()
                        .flat_map(|(uci, id)| {
                            queryable.get_game_info(id).expect("get game").map(|info| {
                                GameRowWithUci {
                                    uci,
                                    row: GameRow { id, info },
                                }
                            })
                        })
                        .collect(),
                    opening: state.opening,
                },
                state,
            ))
        },
    ).dedup_by_key(|res| res.total.total())))
}
<commit_msg>also omit target from log<commit_after>#![forbid(unsafe_code)]

pub mod api;
pub mod db;
pub mod indexer;
pub mod model;
pub mod opening;
pub mod util;

use std::{mem, net::SocketAddr, path::PathBuf, sync::Arc, time::Duration};

use axum::{
    extract::{Extension, Path, Query},
    handler::get,
    http::StatusCode,
    AddExtensionLayer, Router,
};
use clap::Clap;
use futures_util::stream::Stream;
use shakmaty::{fen::Fen, variant::VariantPosition, zobrist::Zobrist, CastlingMode};
use tokio::sync::watch;

use crate::{
    api::{
        Error, GameRow, GameRowWithUci, NdJson, PersonalMoveRow, PersonalQuery,
        PersonalQueryFilter, PersonalResponse,
    },
    db::Database,
    indexer::{IndexerOpt, IndexerStub},
    model::{PersonalKeyBuilder, PersonalKeyPrefix, UserId},
    opening::{Opening, Openings},
    util::DedupStreamExt as _,
};

#[derive(Clap)]
struct Opt {
    #[clap(long = "bind", default_value = "127.0.0.1:9000")]
    bind: SocketAddr,
    #[clap(long = "db", default_value = "_db")]
    db: PathBuf,
    #[clap(flatten)]
    indexer: IndexerOpt,
}

#[tokio::main]
async fn main() {
    env_logger::Builder::from_env(
        env_logger::Env::new()
            .filter("EXPLORER_LOG")
            .write_style("EXPLORER_LOG_STYLE"),
    )
    .format_timestamp(None)
    .format_module_path(false)
    .format_target(false)
    .init();

    let opt = Opt::parse();

    let openings: &'static Openings = Box::leak(Box::new(Openings::build_table()));
    let db = Arc::new(Database::open(opt.db).expect("db"));
    let (indexer, join_handles) = IndexerStub::spawn(db.clone(), opt.indexer);

    let app = Router::new()
        .route("/admin/:prop", get(db_property))
        .route("/admin/game/:prop", get(game_property))
        .route("/admin/personal/:prop", get(personal_property))
        .route("/personal", get(personal))
        .layer(AddExtensionLayer::new(openings))
        .layer(AddExtensionLayer::new(db))
        .layer(AddExtensionLayer::new(indexer));

    axum::Server::bind(&opt.bind)
        .serve(app.into_make_service())
        .await
        .expect("bind");

    for join_handle in join_handles {
        join_handle.await.expect("indexer");
    }
}

async fn db_property(
    Extension(db): Extension<Arc<Database>>,
    Path(prop): Path<String>,
) -> Result<String, StatusCode> {
    db.queryable()
        .db_property(&prop)
        .expect("get property")
        .ok_or(StatusCode::NOT_FOUND)
}

async fn game_property(
    Extension(db): Extension<Arc<Database>>,
    Path(prop): Path<String>,
) -> Result<String, StatusCode> {
    db.queryable()
        .game_property(&prop)
        .expect("get property")
        .ok_or(StatusCode::NOT_FOUND)
}

async fn personal_property(
    Extension(db): Extension<Arc<Database>>,
    Path(prop): Path<String>,
) -> Result<String, StatusCode> {
    db.queryable()
        .personal_property(&prop)
        .expect("get property")
        .ok_or(StatusCode::NOT_FOUND)
}

struct PersonalStreamState {
    indexing: Option<watch::Receiver<()>>,
    key: PersonalKeyPrefix,
    db: Arc<Database>,
    filter: PersonalQueryFilter,
    pos: VariantPosition,
    opening: Option<&'static Opening>,
    first: bool,
    done: bool,
}

async fn personal(
    Extension(openings): Extension<&'static Openings>,
    Extension(db): Extension<Arc<Database>>,
    Extension(indexer): Extension<IndexerStub>,
    Query(query): Query<PersonalQuery>,
) -> Result<NdJson<impl Stream<Item = PersonalResponse>>, Error> {
    let player = UserId::from(query.player);
    let indexing = indexer.index_player(&player).await;

    let variant = query.variant.into();

    let mut pos = Zobrist::new(match query.fen {
        Some(fen) => VariantPosition::from_setup(variant, &Fen::from(fen), CastlingMode::Chess960)?,
        None => VariantPosition::new(variant),
    });

    let opening = openings.classify_and_play(&mut pos, query.play)?;

    let key = PersonalKeyBuilder::with_user_pov(&player, query.color)
        .with_zobrist(variant, pos.zobrist_hash());

    let state = PersonalStreamState {
        filter: query.filter,
        db,
        indexing,
        opening,
        key,
        pos: pos.into_inner(),
        first: true,
        done: false,
    };

    Ok(NdJson(futures_util::stream::unfold(
        state,
        |mut state| async move {
            if state.done {
                return None;
            }

            let first = mem::replace(&mut state.first, false);
            state.done = match state.indexing {
                Some(ref mut indexing) => {
                    tokio::select! {
                        _ = indexing.changed() => true,
                        _ = tokio::time::sleep(Duration::from_millis(if first { 0 } else { 1000 })) => false,
                    }
                }
                None => true,
            };

            let queryable = state.db.queryable();
            let filtered = queryable
                .get_personal(&state.key, state.filter.since, state.filter.until)
                .expect("get personal")
                .prepare(&state.pos, &state.filter);

            Some((
                PersonalResponse {
                    total: filtered.total,
                    moves: filtered
                        .moves
                        .into_iter()
                        .map(|row| PersonalMoveRow {
                            uci: row.uci,
                            san: row.san,
                            stats: row.stats,
                            game: row.game.and_then(|id| {
                                queryable
                                    .get_game_info(id)
                                    .expect("get game")
                                    .map(|info| GameRow { id, info })
                            }),
                        })
                        .collect(),
                    recent_games: filtered
                        .recent_games
                        .into_iter()
                        .flat_map(|(uci, id)| {
                            queryable.get_game_info(id).expect("get game").map(|info| {
                                GameRowWithUci {
                                    uci,
                                    row: GameRow { id, info },
                                }
                            })
                        })
                        .collect(),
                    opening: state.opening,
                },
                state,
            ))
        },
    ).dedup_by_key(|res| res.total.total())))
}
<|endoftext|>


<commit_before>use cgmath::*;
use shader::*;
use device::Device;
use rasterization::triangle;

#[derive(Copy,Clone)]
pub struct Vertex {
    pub position: Vector3<f32>,
    pub normal: Vector3<f32>,
}

impl Vertex {
    #[allow(dead_code)]
    pub fn new() -> Vertex {
        Vertex {
            position: Vector3::new(0.0_f32, 0.0_f32, 0.0_f32),
            normal: Vector3::new(0.0_f32, 0.0_f32, 0.0_f32),
        }
    }
}

pub struct Mesh {
    pub vertex_buffer: Vec<Vertex>,
    pub index_buffer: Vec<u32>,
}

pub struct Model {
    pub mesh_arr: Vec<Mesh>,
}

impl Mesh {
    pub fn new() -> Mesh {
        Mesh {
            vertex_buffer: Vec::<Vertex>::new(),
            index_buffer: Vec::<u32>::new(),
        }
    }

    pub fn vertex(&mut self, buffer: Vec<Vertex>) {
        self.vertex_buffer = buffer;
    }

    pub fn index(&mut self, buffer: Vec<u32>) -> Result<(), String> {
        if buffer.len() % 3 != 0 {
            return Err(format!("len of index buffer can be N*3, real len is {}", buffer.len()));
        }
        self.index_buffer = buffer;

        Ok(())
    }

    pub fn calc_normal(&mut self) -> Result<(), String> {
        if self.vertex_buffer.len() == 0 ||
            self.index_buffer.len() == 0 {
                return Err("fill vertex and index buffer before calc normals".to_string());
            }
        for vertex in &mut self.vertex_buffer {
            vertex.normal = Vector3::<f32>::new(0.0_f32, 0.0_f32, 0.0_f32);
        }
        let ib = &self.index_buffer;
        // let vb = &self.vertex_buffer;
        for i in 0..ib.len() / 3 {
            let ind = i * 3;
            let v0_ind = ib[ind + 0] as usize;
            let v1_ind = ib[ind + 1] as usize;
            let v2_ind = ib[ind + 2] as usize;
            let v0 = self.vertex_buffer[v0_ind].position;
            let v1 = self.vertex_buffer[v1_ind].position;
            let v2 = self.vertex_buffer[v2_ind].position;
            // let normal = v1.sub_v(&v0).cross(&(v2.sub_v(&v1)));
            let normal = v2.sub_v(&v1).cross(&(v1.sub_v(&v0)));
            self.vertex_buffer[v0_ind].normal.add_self_v(&normal);
            self.vertex_buffer[v1_ind].normal.add_self_v(&normal);
            self.vertex_buffer[v2_ind].normal.add_self_v(&normal);
        }

        for vertex in &mut self.vertex_buffer {
            vertex.normal.normalize_self();
        }

        Ok(())
    }

    pub fn draw(&self, shader: &mut Shader, device: &mut Device) -> u32 {
        let vertex_func = shader.vertex_func;
        let cnt_triangle = self.index_buffer.len() / 3;
        for indexes in self.index_buffer.chunks(3) {
            let mut points: [Point3<f32>; 3] = [Point3::<f32>::new(0.0, 0.0, 0.0); 3];
            let mut vertex_out = [[0.0_f32;MAX_OUT_VALUES];3];
            let mut vertex_out_len = 0;
            for i in 0..3 {
                let v = self.vertex_buffer[indexes[i] as usize].position;
                let n = self.vertex_buffer[indexes[i] as usize].normal;

                shader.reset(Vector4::<f32>::new(v.x, v.y, v.z, 1.0_f32), Vector4::<f32>::new(n.x, n.y, n.z, 1.0_f32));
                let p_screen = vertex_func(shader);
                vertex_out_len = shader.vertex_out_len;
                let inverse_w = 1.0_f32 / p_screen.w;

                for ind in 0..vertex_out_len {
                    vertex_out[i][ind] = shader.out_vertex_data[ind] * inverse_w;
                }

                points[i] = Point3::new(
                    (p_screen.x * inverse_w + 1.0_f32) * device.x_size as f32 * 0.5_f32,
                    (p_screen.y * inverse_w + 1.0_f32) * device.y_size as f32 * 0.5_f32,
                    inverse_w);
            }

            let col0 = Vector3::new(points[0].x, points[1].x, points[2].x);
            let col1 = Vector3::new(points[0].y, points[1].y, points[2].y);
            let col2 = Vector3::new(1.0_f32,     1.0_f32,     1.0_f32    );
            let d = Matrix3::from_cols(col0, col1, col2).determinant();
            if d > 0.0_f32 {
                continue;
            }
            // if d < 0.0_f32 {
            //     continue;
            // }

            triangle(&mut device.cbuffer,
                     &mut device.zbuffer,
                     device.x_size,
                     device.y_size,
                     points, vertex_out, vertex_out_len, shader);
        }

        cnt_triangle as u32
    }
}

impl Model {
    pub fn new() -> Model {
        Model {
            mesh_arr: Vec::<Mesh>::new(),
        }
    }

    pub fn add(&mut self, mesh: Mesh) {
        self.mesh_arr.push(mesh);
    }

    pub fn draw(&self, shader: &mut Shader, device: &mut Device) -> u32 {
        let mut triangle_cnt: u32 = 0;
        for mesh in &self.mesh_arr {
            triangle_cnt += mesh.draw(shader, device);
        }

        triangle_cnt
    }
}
<commit_msg>у нормали w должен быть = 0<commit_after>use cgmath::*;
use shader::*;
use device::Device;
use rasterization::triangle;

#[derive(Copy,Clone)]
pub struct Vertex {
    pub position: Vector3<f32>,
    pub normal: Vector3<f32>,
}

impl Vertex {
    #[allow(dead_code)]
    pub fn new() -> Vertex {
        Vertex {
            position: Vector3::new(0.0_f32, 0.0_f32, 0.0_f32),
            normal: Vector3::new(0.0_f32, 0.0_f32, 0.0_f32),
        }
    }
}

pub struct Mesh {
    pub vertex_buffer: Vec<Vertex>,
    pub index_buffer: Vec<u32>,
}

pub struct Model {
    pub mesh_arr: Vec<Mesh>,
}

impl Mesh {
    pub fn new() -> Mesh {
        Mesh {
            vertex_buffer: Vec::<Vertex>::new(),
            index_buffer: Vec::<u32>::new(),
        }
    }

    pub fn vertex(&mut self, buffer: Vec<Vertex>) {
        self.vertex_buffer = buffer;
    }

    pub fn index(&mut self, buffer: Vec<u32>) -> Result<(), String> {
        if buffer.len() % 3 != 0 {
            return Err(format!("len of index buffer can be N*3, real len is {}", buffer.len()));
        }
        self.index_buffer = buffer;

        Ok(())
    }

    pub fn calc_normal(&mut self) -> Result<(), String> {
        if self.vertex_buffer.len() == 0 ||
            self.index_buffer.len() == 0 {
                return Err("fill vertex and index buffer before calc normals".to_string());
            }
        for vertex in &mut self.vertex_buffer {
            vertex.normal = Vector3::<f32>::new(0.0_f32, 0.0_f32, 0.0_f32);
        }
        let ib = &self.index_buffer;
        // let vb = &self.vertex_buffer;
        for i in 0..ib.len() / 3 {
            let ind = i * 3;
            let v0_ind = ib[ind + 0] as usize;
            let v1_ind = ib[ind + 1] as usize;
            let v2_ind = ib[ind + 2] as usize;
            let v0 = self.vertex_buffer[v0_ind].position;
            let v1 = self.vertex_buffer[v1_ind].position;
            let v2 = self.vertex_buffer[v2_ind].position;
            // let normal = v1.sub_v(&v0).cross(&(v2.sub_v(&v1)));
            let normal = v2.sub_v(&v1).cross(&(v1.sub_v(&v0)));
            self.vertex_buffer[v0_ind].normal.add_self_v(&normal);
            self.vertex_buffer[v1_ind].normal.add_self_v(&normal);
            self.vertex_buffer[v2_ind].normal.add_self_v(&normal);
        }

        for vertex in &mut self.vertex_buffer {
            vertex.normal.normalize_self();
        }

        Ok(())
    }

    pub fn draw(&self, shader: &mut Shader, device: &mut Device) -> u32 {
        let vertex_func = shader.vertex_func;
        let cnt_triangle = self.index_buffer.len() / 3;
        for indexes in self.index_buffer.chunks(3) {
            let mut points: [Point3<f32>; 3] = [Point3::<f32>::new(0.0, 0.0, 0.0); 3];
            let mut vertex_out = [[0.0_f32;MAX_OUT_VALUES];3];
            let mut vertex_out_len = 0;
            for i in 0..3 {
                let v = self.vertex_buffer[indexes[i] as usize].position;
                let n = self.vertex_buffer[indexes[i] as usize].normal;

                shader.reset(Vector4::<f32>::new(v.x, v.y, v.z, 1.0_f32), Vector4::<f32>::new(n.x, n.y, n.z, 0.0_f32));
                let p_screen = vertex_func(shader);
                vertex_out_len = shader.vertex_out_len;
                let inverse_w = 1.0_f32 / p_screen.w;

                for ind in 0..vertex_out_len {
                    vertex_out[i][ind] = shader.out_vertex_data[ind] * inverse_w;
                }

                points[i] = Point3::new(
                    (p_screen.x * inverse_w + 1.0_f32) * device.x_size as f32 * 0.5_f32,
                    (p_screen.y * inverse_w + 1.0_f32) * device.y_size as f32 * 0.5_f32,
                    inverse_w);
            }

            let col0 = Vector3::new(points[0].x, points[1].x, points[2].x);
            let col1 = Vector3::new(points[0].y, points[1].y, points[2].y);
            let col2 = Vector3::new(1.0_f32,     1.0_f32,     1.0_f32    );
            let d = Matrix3::from_cols(col0, col1, col2).determinant();
            if d > 0.0_f32 {
                continue;
            }
            // if d < 0.0_f32 {
            //     continue;
            // }

            triangle(&mut device.cbuffer,
                     &mut device.zbuffer,
                     device.x_size,
                     device.y_size,
                     points, vertex_out, vertex_out_len, shader);
        }

        cnt_triangle as u32
    }
}

impl Model {
    pub fn new() -> Model {
        Model {
            mesh_arr: Vec::<Mesh>::new(),
        }
    }

    pub fn add(&mut self, mesh: Mesh) {
        self.mesh_arr.push(mesh);
    }

    pub fn draw(&self, shader: &mut Shader, device: &mut Device) -> u32 {
        let mut triangle_cnt: u32 = 0;
        for mesh in &self.mesh_arr {
            triangle_cnt += mesh.draw(shader, device);
        }

        triangle_cnt
    }
}
<|endoftext|>


<commit_before>use traitdefs::{Float, Point, Vector};
use std::convert::{AsRef, AsMut};
use std::cell::{Cell, RefCell};
use std::marker::PhantomData;

use super::traits::BezCurve;

#[derive(Copy, Clone)]
struct RangeSlice {
    start: usize,
    end: usize
}

impl RangeSlice {
    #[inline]
    fn new(start: usize, end: usize) -> RangeSlice {
        RangeSlice {
            start: start,
            end: end
        }
    }

    fn len(&self) -> usize {
        self.end - self.start
    }
}

fn combination(n: usize, k: usize) -> usize {
    factorial(n) / (factorial(k) * factorial(n - k))
}

fn factorial(n: usize) -> usize {
    match n {
        0 => 1,
        _ => n * factorial(n-1)
    }
}

fn order_index(order: usize) -> usize {
    (order*order+order)/2
}

thread_local!{
    static FACTORS: RefCell<(usize, Vec<usize>)> = RefCell::new((0, Vec::with_capacity(order_index(16+1))))
}

fn factors(order: usize) -> RangeSlice {
    FACTORS.with(|f| {
        let max_order = f.borrow().0;
        if order > max_order {
            let mut f = f.borrow_mut();
            f.0 = order;
            for n in max_order..order+1 {
                for k in 0..n+1 {
                    f.1.push(combination(n, k));
                }
            }
        }

        let order_index = order_index(order);
        RangeSlice::new(order_index, order_index+order+1)
    })
}

#[derive(Clone)]
pub struct NBezPoly<F, C = Vec<F>>
        where F: Float,
              C: AsRef<[F]> {
    points: C,
    factors: Cell<RangeSlice>,
    dfactors: Cell<RangeSlice>,
    phantom: PhantomData<F>
}

impl<F, C> NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    #[inline]
    fn new(points: C, factors: RangeSlice, dfactors: RangeSlice) -> NBezPoly<F, C> {
        NBezPoly {
            points: points,
            factors: Cell::new(factors),
            dfactors: Cell::new(dfactors),
            phantom: PhantomData
        }
    }

    #[inline]
    pub fn from_container(points: C) -> NBezPoly<F, C> {
        NBezPoly::new(points, RangeSlice::new(0, 0), RangeSlice::new(0, 0))
    }

    #[inline]
    pub fn unwrap(self) -> C {
        self.points
    }

    unsafe fn interp_unchecked<I: Iterator<Item=F>>(&self, t: F, order: usize, iter: I) -> F {
        let t1 = F::from_f32(1.0).unwrap() - t;
        let mut acc = F::from_f32(0.0).unwrap();
        let mut factor = 0;

        FACTORS.with(|fs| {
            let fs = fs.borrow();
            for point in iter {
                acc = acc + t.powi(factor as i32) *
                            t1.powi((order-factor) as i32) *
                            point *
                            F::from_usize(fs.1[self.factors.get().start + factor]).unwrap();
                factor += 1;
            }
        });
        acc
    }

    unsafe fn slope_unchecked<I: Iterator<Item=F>>(&self, t: F, order: usize, mut iter: I) -> F {
        let t1 = F::from_f32(1.0).unwrap() - t;
        let mut acc = F::from_f32(0.0).unwrap();
        let mut factor = 0;
        let mut point_next = iter.next().unwrap();

        FACTORS.with(|fs| {
            let fs = fs.borrow();
            for point in iter {
                acc = acc + t.powi(factor as i32) *
                            t1.powi((order-factor) as i32) *
                            (point_next - point) *
                            F::from_usize(fs.1[self.dfactors.get().start + factor] * (order + 1) as usize).unwrap();
                point_next = point;
                factor += 1;
            }
        });
        acc
    }
}

impl<F, C> BezCurve<F> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    type Point = F;
    type Vector = F;

    fn from_slice(_: &[F]) -> Option<NBezPoly<F, C>> {
        None
    }

    fn interp_unbounded(&self, t: F) -> F {
        let points = self.points.as_ref();
        if self.factors.get().len() != self.order() {
            self.factors.set(factors(self.order()))
        }

        unsafe{ self.interp_unchecked(t, self.order(), points.iter().map(|f| *f)) }
    }

    fn slope_unbounded(&self, t: F) -> F {
        let points = self.points.as_ref();
        let order = self.order() - 1;
        if self.dfactors.get().len() != order {
            self.dfactors.set(factors(order))
        }

        unsafe{ self.slope_unchecked(t, order, points.iter().map(|f| *f)) }
    }

    fn order(&self) -> usize {
        self.points.as_ref().len()-1
    }

    fn order_static() -> Option<usize> {
        None
    }
}

impl<F, C> AsRef<C> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<F, C> AsMut<C> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}

pub struct NBez<F, C, P, V>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    points: C,
    factors: Cell<RangeSlice>,
    dfactors: Cell<RangeSlice>,

    float_phantom: PhantomData<F>,
    point_phantom: PhantomData<P>,
    vector_phantom: PhantomData<V>
}

impl<F, C, P, V> NBez<F, C, P, V>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    pub fn from_container(container: C) -> NBez<F, C, P, V> {
        NBez {
            points: container,
            factors: Cell::new(RangeSlice::new(0, 0)),
            dfactors: Cell::new(RangeSlice::new(0, 0)),

            float_phantom: PhantomData,
            point_phantom: PhantomData,
            vector_phantom: PhantomData
        }
    }
}

impl<F, C, P, V> BezCurve<F> for NBez<F, C, P, V>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    type Point = P;
    type Vector = V;

    fn from_slice(_: &[P]) -> Option<NBez<F, C, P, V>> {
        None
    }

    fn interp_unbounded(&self, t: F) -> P {
        let points = self.points.as_ref();
        let mut point = points[0].clone();

        if self.factors.get().len() != self.order() {
            self.factors.set(factors(self.order()))
        }
        // Create an n-order bezier chain. Because we're passing the actual control points by an iterator
        // (defined in the for loop below), we give it a fake point slice.
        let chain = NBezPoly::new([], self.factors.get(), self.dfactors.get());

        for (i, f) in point.as_mut().iter_mut().enumerate() {
            let iter = points.iter().map(|p| p.as_ref()[i]);
            *f = unsafe{ chain.interp_unchecked(t, self.order(), iter) };
        }

        point
    }

    fn slope_unbounded(&self, t: F) -> V {
        let points = self.points.as_ref();
        let mut vector: V = points[0].clone().into();

        let order = self.order() - 1;
        if self.dfactors.get().len() != order {
            self.dfactors.set(factors(order))
        }
        // Ditto. See interp_unbounded.
        let chain = NBezPoly::new([], self.factors.get(), self.dfactors.get());

        for (i, f) in vector.as_mut().iter_mut().enumerate() {
            let iter = points.iter().map(|p| p.as_ref()[i]);
            *f = unsafe{ chain.slope_unchecked(t, order, iter) };
        }

        vector
    }

    fn order(&self) -> usize {
        self.points.as_ref().len() - 1
    }

    fn order_static() -> Option<usize> {
        None
    }
}

impl<F, C, P, V> AsRef<C> for NBez<F, C, P, V>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<F, C, P, V> AsMut<C> for NBez<F, C, P, V>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}<commit_msg>Modified `interp_unchecked` and `slope_unchecked` to be associated functions rather than methods<commit_after>use traitdefs::{Float, Point, Vector};
use std::convert::{AsRef, AsMut};
use std::cell::{Cell, RefCell};
use std::marker::PhantomData;

use super::traits::BezCurve;

#[derive(Copy, Clone)]
struct RangeSlice {
    start: usize,
    end: usize
}

impl RangeSlice {
    #[inline]
    fn new(start: usize, end: usize) -> RangeSlice {
        RangeSlice {
            start: start,
            end: end
        }
    }

    fn len(&self) -> usize {
        self.end - self.start
    }
}

fn combination(n: usize, k: usize) -> usize {
    factorial(n) / (factorial(k) * factorial(n - k))
}

fn factorial(n: usize) -> usize {
    match n {
        0 => 1,
        _ => n * factorial(n-1)
    }
}

fn order_index(order: usize) -> usize {
    (order*order+order)/2
}

thread_local!{
    static FACTORS: RefCell<(usize, Vec<usize>)> = RefCell::new((0, Vec::with_capacity(order_index(16+1))))
}

fn factors(order: usize) -> RangeSlice {
    FACTORS.with(|f| {
        let max_order = f.borrow().0;
        if order > max_order {
            let mut f = f.borrow_mut();
            f.0 = order;
            for n in max_order..order+1 {
                for k in 0..n+1 {
                    f.1.push(combination(n, k));
                }
            }
        }

        let order_index = order_index(order);
        RangeSlice::new(order_index, order_index+order+1)
    })
}

#[derive(Clone)]
pub struct NBezPoly<F, C = Vec<F>>
        where F: Float,
              C: AsRef<[F]> {
    points: C,
    factors: Cell<RangeSlice>,
    dfactors: Cell<RangeSlice>,
    phantom: PhantomData<F>
}

impl<F, C> NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    #[inline]
    fn new(points: C, factors: RangeSlice, dfactors: RangeSlice) -> NBezPoly<F, C> {
        NBezPoly {
            points: points,
            factors: Cell::new(factors),
            dfactors: Cell::new(dfactors),
            phantom: PhantomData
        }
    }

    #[inline]
    pub fn from_container(points: C) -> NBezPoly<F, C> {
        NBezPoly::new(points, RangeSlice::new(0, 0), RangeSlice::new(0, 0))
    }

    #[inline]
    pub fn unwrap(self) -> C {
        self.points
    }

    unsafe fn interp_unchecked<I: Iterator<Item=F>>(t: F, factors: RangeSlice, iter: I) -> F {
        let t1 = F::from_f32(1.0).unwrap() - t;
        let order = factors.len() - 1;
        let mut acc = F::from_f32(0.0).unwrap();
        let mut factor = 0;

        FACTORS.with(|fs| {
            let fs = fs.borrow();
            for point in iter {
                acc = acc + t.powi(factor as i32) *
                            t1.powi((order-factor) as i32) *
                            point *
                            F::from_usize(fs.1[factors.start + factor]).unwrap();
                factor += 1;
            }
        });
        acc
    }

    unsafe fn slope_unchecked<I: Iterator<Item=F>>(t: F, dfactors: RangeSlice, mut iter: I) -> F {
        let t1 = F::from_f32(1.0).unwrap() - t;
        let order = dfactors.len() - 1;
        let mut acc = F::from_f32(0.0).unwrap();
        let mut factor = 0;
        let mut point_next = iter.next().unwrap();

        FACTORS.with(|fs| {
            let fs = fs.borrow();
            for point in iter {
                acc = acc + t.powi(factor as i32) *
                            t1.powi((order-factor) as i32) *
                            (point_next - point) *
                            F::from_usize(fs.1[dfactors.start + factor] * (order + 1) as usize).unwrap();
                point_next = point;
                factor += 1;
            }
        });
        acc
    }
}

impl<F, C> BezCurve<F> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    type Point = F;
    type Vector = F;

    fn from_slice(_: &[F]) -> Option<NBezPoly<F, C>> {
        None
    }

    fn interp_unbounded(&self, t: F) -> F {
        let points = self.points.as_ref();
        if self.factors.get().len() != self.order() {
            self.factors.set(factors(self.order()))
        }

        unsafe{ NBezPoly::<_, &[_]>::interp_unchecked(t, self.factors.get(), points.iter().map(|f| *f)) }
    }

    fn slope_unbounded(&self, t: F) -> F {
        let points = self.points.as_ref();
        let order = self.order() - 1;
        if self.dfactors.get().len() != order {
            self.dfactors.set(factors(order))
        }

        unsafe{ NBezPoly::<_, &[_]>::slope_unchecked(t, self.dfactors.get(), points.iter().map(|f| *f)) }
    }

    fn order(&self) -> usize {
        self.points.as_ref().len()-1
    }

    fn order_static() -> Option<usize> {
        None
    }
}

impl<F, C> AsRef<C> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<F, C> AsMut<C> for NBezPoly<F, C>
        where F: Float,
              C: AsRef<[F]> {
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}

pub struct NBez<F, C, P, V>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    points: C,
    factors: Cell<RangeSlice>,
    dfactors: Cell<RangeSlice>,

    float_phantom: PhantomData<F>,
    point_phantom: PhantomData<P>,
    vector_phantom: PhantomData<V>
}

impl<F, C, P, V> NBez<F, C, P, V>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    pub fn from_container(container: C) -> NBez<F, C, P, V> {
        NBez {
            points: container,
            factors: Cell::new(RangeSlice::new(0, 0)),
            dfactors: Cell::new(RangeSlice::new(0, 0)),

            float_phantom: PhantomData,
            point_phantom: PhantomData,
            vector_phantom: PhantomData
        }
    }
}

impl<F, C, P, V> BezCurve<F> for NBez<F, C, P, V>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    type Point = P;
    type Vector = V;

    fn from_slice(_: &[P]) -> Option<NBez<F, C, P, V>> {
        None
    }

    fn interp_unbounded(&self, t: F) -> P {
        let points = self.points.as_ref();
        let mut point = points[0].clone();

        if self.factors.get().len() != self.order() {
            self.factors.set(factors(self.order()))
        }

        for (i, f) in point.as_mut().iter_mut().enumerate() {
            let iter = points.iter().map(|p| p.as_ref()[i]);
            *f = unsafe{ NBezPoly::<_, &[_]>::interp_unchecked(t, self.factors.get(), iter) };
        }

        point
    }

    fn slope_unbounded(&self, t: F) -> V {
        let points = self.points.as_ref();
        let mut vector: V = points[0].clone().into();

        let order = self.order() - 1;
        if self.dfactors.get().len() != order {
            self.dfactors.set(factors(order))
        }

        for (i, f) in vector.as_mut().iter_mut().enumerate() {
            let iter = points.iter().map(|p| p.as_ref()[i]);
            *f = unsafe{ NBezPoly::<_, &[_]>::slope_unchecked(t, self.dfactors.get(), iter) };
        }

        vector
    }

    fn order(&self) -> usize {
        self.points.as_ref().len() - 1
    }

    fn order_static() -> Option<usize> {
        None
    }
}

impl<F, C, P, V> AsRef<C> for NBez<F, C, P, V>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<F, C, P, V> AsMut<C> for NBez<F, C, P, V>
        where F: Float,
              C: AsRef<[P]>,
              P: Point<F>,
              V: Vector<F, P> {
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}<|endoftext|>


<commit_before>//! Module with the self-pipe pattern.
//!
//! One of the common patterns around signals is to have a pipe with both ends in the same program.
//! Whenever there's a signal, the signal handler writes one byte of garbage data to the write end,
//! unless the pipe's already full. The application then can handle the read end.
//!
//! This has two advantages. First, the real signal action moves outside of the signal handler
//! where there are a lot less restrictions. Second, it fits nicely in all kinds of asynchronous
//! loops and has less chance of race conditions.
//!
//! This module offers premade functions for the write end (and doesn't insist that it must be a
//! pipe ‒ anything that can be written to is fine ‒ sockets too, therefore `UnixStream::pair` is a
//! good candidate).
//!
//! If you want to integrate with some asynchronous library, plugging streams from `mio-uds` or
//! `tokio-uds` libraries should work.
//!
//! If it looks too low-level for your needs, the [`iterator`](../iterator/) module contains some
//! higher-lever interface that also uses a self-pipe pattern under the hood.
//!
//! # Correct order of handling
//!
//! A care needs to be taken to avoid race conditions, especially when handling the same signal in
//! a loop. Specifically, another signal might come when the action for the previous signal is
//! being taken. The correct order is first to clear the content of the pipe (read some/all data
//! from it) and then take the action. This way a spurious wakeup can happen (the pipe could wake
//! up even when no signal came after the signal was taken, because ‒ it arrived between cleaning
//! the pipe and taking the action). Note that some OS primitives (eg. `select`) suffer from
//! spurious wakeups themselves (they can claim a FD is readable when it is not true) and blocking
//! `read` might return prematurely (with eg. `EINTR`).
//!
//! The reverse order of first taking the action and then clearing the pipe might lose signals,
//! which is usually worse.
//!
//! This is not a problem with blocking on reading from the pipe (because both the blocking and
//! cleaning is the same action), but in case of asynchronous handling it matters.
//!
//! If you want to combine setting some flags with a self-pipe pattern, the flag needs to be set
//! first, then the pipe written. On the read end, first the pipe needs to be cleaned, then the
//! flag and then the action taken. This is what the [`Signals`](../iterator/struct.Signals.html)
//! structure does internally.
//!
//! # Write collating
//!
//! While unlikely if handled correctly, it is possible the write end is full when a signal comes.
//! In such case the signal handler simply does nothing. If the write end is full, the read end is
//! readable and therefore will wake up. On the other hand, blocking in the signal handler would
//! definitely be a bad idea.
//!
//! However, this also means the number of bytes read from the end might be lower than the number
//! of signals that arrived. This should not generally be a problem, since the OS already collates
//! signals of the same kind together.
//!
//! # Examples
//!
//! This example waits for at last one `SIGUSR1` signal to come before continuing (and
//! terminating). It sends the signal to itself, so it correctly terminates.
//!
//! ```rust
//! extern crate libc;
//! extern crate signal_hook;
//!
//! use std::io::{Error, Read};
//! use std::os::unix::net::UnixStream;
//!
//! fn main() -> Result<(), Error> {
//!     let (mut read, write) = UnixStream::pair()?;
//!     signal_hook::pipe::register(signal_hook::SIGUSR1, write)?;
//!     // This will write into the pipe write end through the signal handler
//!     unsafe { libc::raise(signal_hook::SIGUSR1) };
//!     let mut buff = [0];
//!     read.read_exact(&mut buff)?;
//!     println!("Happily terminating");
//!     Ok(())
//! }

use std::io::{Error, ErrorKind};
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};

use libc::{self, c_int};

use crate::SigId;

#[derive(Copy, Clone)]
pub(crate) enum WakeMethod {
    Send,
    Write,
}

struct WakeFd {
    fd: RawFd,
    method: WakeMethod,
}

impl WakeFd {
    /// Sets close on exec and nonblock on the inner file descriptor.
    fn set_flags(&self) -> Result<(), Error> {
        unsafe {
            let flags = libc::fcntl(self.as_raw_fd(), libc::F_GETFL, 0);
            if flags == -1 {
                return Err(Error::last_os_error());
            }
            let flags = flags | libc::O_NONBLOCK | libc::O_CLOEXEC;
            if libc::fcntl(self.as_raw_fd(), libc::F_SETFL, flags) == -1 {
                return Err(Error::last_os_error());
            }
        }
        Ok(())
    }
    fn wake(&self) {
        wake(self.fd, self.method);
    }
}

impl AsRawFd for WakeFd {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl Drop for WakeFd {
    fn drop(&mut self) {
        unsafe {
            libc::close(self.fd);
        }
    }
}

pub(crate) fn wake(pipe: RawFd, method: WakeMethod) {
    unsafe {
        // This writes some data into the pipe.
        //
        // There are two tricks:
        // * First, the crazy cast. The first part turns reference into pointer. The second part
        //   turns pointer to u8 into a pointer to void, which is what write requires.
        // * Second, we ignore errors, on purpose. We don't have any means to handling them. The
        //   two conceivable errors are EBADFD, if someone passes a non-existent file descriptor or
        //   if it is closed. The second is EAGAIN, in which case the pipe is full ‒ there were
        //   many signals, but the reader didn't have time to read the data yet. It'll still get
        //   woken up, so not fitting another letter in it is fine.
        let data = b"X" as *const _ as *const _;
        match method {
            WakeMethod::Write => libc::write(pipe, data, 1),
            WakeMethod::Send => libc::send(pipe, data, 1, libc::MSG_DONTWAIT),
        };
    }
}

/// Registers a write to a self-pipe whenever there's the signal.
///
/// In this case, the pipe is taken as the `RawFd`. It'll be closed on deregistration. Effectively,
/// the function takes ownership of the file descriptor. This includes feeling free to set arbitrary
/// flags on it, including file status flags (that are shared across file descriptors created by
/// `dup`).
///
/// Note that passing the wrong file descriptor won't cause UB, but can still lead to severe bugs ‒
/// like data corruptions in files. Prefer using [`register`] if possible.
///
/// Also, it is perfectly legal for multiple writes to be collated together (if not consumed) and
/// to generate spurious wakeups (but will not generate spurious *bytes* in the pipe).
///
/// # Internal details
///
/// Internally, it *currently* does following. Note that this is *not* part of the stability
/// guarantees and may change if necessary.
///
/// * If the file descriptor can be used with [`send`][libc::send], it'll be used together with
///   [`MSG_DONTWAIT`][libc::MSG_DONTWAIT]. This is tested by sending `0` bytes of data (depending
///   on the socket type, this might wake the read end with an empty message).
/// * If it is not possible, the [`O_NONBLOCK`][libc::O_NONBLOCK] will be set on the file
///   descriptor and [`write`][libc::write] will be used instead.
pub fn register_raw(signal: c_int, pipe: RawFd) -> Result<SigId, Error> {
    let res = unsafe { libc::send(pipe, &[] as *const _, 0, libc::MSG_DONTWAIT) };
    let fd = match (res, Error::last_os_error().kind()) {
        (0, _) | (-1, ErrorKind::WouldBlock) => WakeFd {
            fd: pipe,
            method: WakeMethod::Send,
        },
        _ => {
            let fd = WakeFd {
                fd: pipe,
                method: WakeMethod::Write,
            };
            fd.set_flags()?;
            fd
        }
    };
    let action = move || fd.wake();
    unsafe { crate::register(signal, action) }
}

/// Registers a write to a self-pipe whenever there's the signal.
///
/// The ownership of pipe is taken and will be closed whenever the created action is unregistered.
///
/// Note that if you want to register the same pipe for multiple signals, there's `try_clone`
/// method on many unix socket primitives.
///
/// See [`register_raw`] for further details.
pub fn register<P>(signal: c_int, pipe: P) -> Result<SigId, Error>
where
    P: IntoRawFd + 'static,
{
    register_raw(signal, pipe.into_raw_fd())
}

#[cfg(test)]
mod tests {
    use std::io::Read;
    use std::os::unix::net::{UnixDatagram, UnixStream};

    use super::*;

    // Note: multiple tests share the SIGUSR1 signal. This is fine, we only need to know the signal
    // arrives. It's OK to arrive multiple times, from multiple tests.
    fn wakeup() {
        unsafe { assert_eq!(0, libc::raise(libc::SIGUSR1)) }
    }

    #[test]
    fn register_with_socket() -> Result<(), Error> {
        let (mut read, write) = UnixStream::pair()?;
        register(libc::SIGUSR1, write)?;
        read.set_nonblocking(true)?;
        wakeup();
        let mut buff = [0; 1];
        read.read_exact(&mut buff)?;
        assert_eq!(b"X", &buff);
        Ok(())
    }

    #[test]
    fn register_dgram_socket() -> Result<(), Error> {
        let (read, write) = UnixDatagram::pair()?;
        register(libc::SIGUSR1, write)?;
        read.set_nonblocking(true)?;
        wakeup();
        let mut buff = [0; 1];
        // The attempt to detect if it is socket can generate an empty message. Therefore, do a few
        // retries.
        for _ in 0..3 {
            let len = read.recv(&mut buff)?;
            if len == 1 && &buff == b"X" {
                return Ok(());
            }
        }
        panic!("Haven't received the right data");
    }

    #[test]
    fn register_with_pipe() -> Result<(), Error> {
        let mut fds = [0; 2];
        unsafe { assert_eq!(0, libc::pipe(fds.as_mut_ptr())) };
        register_raw(libc::SIGUSR1, fds[1])?;
        wakeup();
        let mut buff = [0; 1];
        unsafe { assert_eq!(1, libc::read(fds[0], buff.as_mut_ptr() as *mut _, 1)) }
        assert_eq!(b"X", &buff);
        Ok(())
    }
}
<commit_msg>Don't use non-blocking in tests<commit_after>//! Module with the self-pipe pattern.
//!
//! One of the common patterns around signals is to have a pipe with both ends in the same program.
//! Whenever there's a signal, the signal handler writes one byte of garbage data to the write end,
//! unless the pipe's already full. The application then can handle the read end.
//!
//! This has two advantages. First, the real signal action moves outside of the signal handler
//! where there are a lot less restrictions. Second, it fits nicely in all kinds of asynchronous
//! loops and has less chance of race conditions.
//!
//! This module offers premade functions for the write end (and doesn't insist that it must be a
//! pipe ‒ anything that can be written to is fine ‒ sockets too, therefore `UnixStream::pair` is a
//! good candidate).
//!
//! If you want to integrate with some asynchronous library, plugging streams from `mio-uds` or
//! `tokio-uds` libraries should work.
//!
//! If it looks too low-level for your needs, the [`iterator`](../iterator/) module contains some
//! higher-lever interface that also uses a self-pipe pattern under the hood.
//!
//! # Correct order of handling
//!
//! A care needs to be taken to avoid race conditions, especially when handling the same signal in
//! a loop. Specifically, another signal might come when the action for the previous signal is
//! being taken. The correct order is first to clear the content of the pipe (read some/all data
//! from it) and then take the action. This way a spurious wakeup can happen (the pipe could wake
//! up even when no signal came after the signal was taken, because ‒ it arrived between cleaning
//! the pipe and taking the action). Note that some OS primitives (eg. `select`) suffer from
//! spurious wakeups themselves (they can claim a FD is readable when it is not true) and blocking
//! `read` might return prematurely (with eg. `EINTR`).
//!
//! The reverse order of first taking the action and then clearing the pipe might lose signals,
//! which is usually worse.
//!
//! This is not a problem with blocking on reading from the pipe (because both the blocking and
//! cleaning is the same action), but in case of asynchronous handling it matters.
//!
//! If you want to combine setting some flags with a self-pipe pattern, the flag needs to be set
//! first, then the pipe written. On the read end, first the pipe needs to be cleaned, then the
//! flag and then the action taken. This is what the [`Signals`](../iterator/struct.Signals.html)
//! structure does internally.
//!
//! # Write collating
//!
//! While unlikely if handled correctly, it is possible the write end is full when a signal comes.
//! In such case the signal handler simply does nothing. If the write end is full, the read end is
//! readable and therefore will wake up. On the other hand, blocking in the signal handler would
//! definitely be a bad idea.
//!
//! However, this also means the number of bytes read from the end might be lower than the number
//! of signals that arrived. This should not generally be a problem, since the OS already collates
//! signals of the same kind together.
//!
//! # Examples
//!
//! This example waits for at last one `SIGUSR1` signal to come before continuing (and
//! terminating). It sends the signal to itself, so it correctly terminates.
//!
//! ```rust
//! extern crate libc;
//! extern crate signal_hook;
//!
//! use std::io::{Error, Read};
//! use std::os::unix::net::UnixStream;
//!
//! fn main() -> Result<(), Error> {
//!     let (mut read, write) = UnixStream::pair()?;
//!     signal_hook::pipe::register(signal_hook::SIGUSR1, write)?;
//!     // This will write into the pipe write end through the signal handler
//!     unsafe { libc::raise(signal_hook::SIGUSR1) };
//!     let mut buff = [0];
//!     read.read_exact(&mut buff)?;
//!     println!("Happily terminating");
//!     Ok(())
//! }

use std::io::{Error, ErrorKind};
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};

use libc::{self, c_int};

use crate::SigId;

#[derive(Copy, Clone)]
pub(crate) enum WakeMethod {
    Send,
    Write,
}

struct WakeFd {
    fd: RawFd,
    method: WakeMethod,
}

impl WakeFd {
    /// Sets close on exec and nonblock on the inner file descriptor.
    fn set_flags(&self) -> Result<(), Error> {
        unsafe {
            let flags = libc::fcntl(self.as_raw_fd(), libc::F_GETFL, 0);
            if flags == -1 {
                return Err(Error::last_os_error());
            }
            let flags = flags | libc::O_NONBLOCK | libc::O_CLOEXEC;
            if libc::fcntl(self.as_raw_fd(), libc::F_SETFL, flags) == -1 {
                return Err(Error::last_os_error());
            }
        }
        Ok(())
    }
    fn wake(&self) {
        wake(self.fd, self.method);
    }
}

impl AsRawFd for WakeFd {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl Drop for WakeFd {
    fn drop(&mut self) {
        unsafe {
            libc::close(self.fd);
        }
    }
}

pub(crate) fn wake(pipe: RawFd, method: WakeMethod) {
    unsafe {
        // This writes some data into the pipe.
        //
        // There are two tricks:
        // * First, the crazy cast. The first part turns reference into pointer. The second part
        //   turns pointer to u8 into a pointer to void, which is what write requires.
        // * Second, we ignore errors, on purpose. We don't have any means to handling them. The
        //   two conceivable errors are EBADFD, if someone passes a non-existent file descriptor or
        //   if it is closed. The second is EAGAIN, in which case the pipe is full ‒ there were
        //   many signals, but the reader didn't have time to read the data yet. It'll still get
        //   woken up, so not fitting another letter in it is fine.
        let data = b"X" as *const _ as *const _;
        match method {
            WakeMethod::Write => libc::write(pipe, data, 1),
            WakeMethod::Send => libc::send(pipe, data, 1, libc::MSG_DONTWAIT),
        };
    }
}

/// Registers a write to a self-pipe whenever there's the signal.
///
/// In this case, the pipe is taken as the `RawFd`. It'll be closed on deregistration. Effectively,
/// the function takes ownership of the file descriptor. This includes feeling free to set arbitrary
/// flags on it, including file status flags (that are shared across file descriptors created by
/// `dup`).
///
/// Note that passing the wrong file descriptor won't cause UB, but can still lead to severe bugs ‒
/// like data corruptions in files. Prefer using [`register`] if possible.
///
/// Also, it is perfectly legal for multiple writes to be collated together (if not consumed) and
/// to generate spurious wakeups (but will not generate spurious *bytes* in the pipe).
///
/// # Internal details
///
/// Internally, it *currently* does following. Note that this is *not* part of the stability
/// guarantees and may change if necessary.
///
/// * If the file descriptor can be used with [`send`][libc::send], it'll be used together with
///   [`MSG_DONTWAIT`][libc::MSG_DONTWAIT]. This is tested by sending `0` bytes of data (depending
///   on the socket type, this might wake the read end with an empty message).
/// * If it is not possible, the [`O_NONBLOCK`][libc::O_NONBLOCK] will be set on the file
///   descriptor and [`write`][libc::write] will be used instead.
pub fn register_raw(signal: c_int, pipe: RawFd) -> Result<SigId, Error> {
    let res = unsafe { libc::send(pipe, &[] as *const _, 0, libc::MSG_DONTWAIT) };
    let fd = match (res, Error::last_os_error().kind()) {
        (0, _) | (-1, ErrorKind::WouldBlock) => WakeFd {
            fd: pipe,
            method: WakeMethod::Send,
        },
        _ => {
            let fd = WakeFd {
                fd: pipe,
                method: WakeMethod::Write,
            };
            fd.set_flags()?;
            fd
        }
    };
    let action = move || fd.wake();
    unsafe { crate::register(signal, action) }
}

/// Registers a write to a self-pipe whenever there's the signal.
///
/// The ownership of pipe is taken and will be closed whenever the created action is unregistered.
///
/// Note that if you want to register the same pipe for multiple signals, there's `try_clone`
/// method on many unix socket primitives.
///
/// See [`register_raw`] for further details.
pub fn register<P>(signal: c_int, pipe: P) -> Result<SigId, Error>
where
    P: IntoRawFd + 'static,
{
    register_raw(signal, pipe.into_raw_fd())
}

#[cfg(test)]
mod tests {
    use std::io::Read;
    use std::os::unix::net::{UnixDatagram, UnixStream};

    use super::*;

    // Note: multiple tests share the SIGUSR1 signal. This is fine, we only need to know the signal
    // arrives. It's OK to arrive multiple times, from multiple tests.
    fn wakeup() {
        unsafe { assert_eq!(0, libc::raise(libc::SIGUSR1)) }
    }

    #[test]
    fn register_with_socket() -> Result<(), Error> {
        let (mut read, write) = UnixStream::pair()?;
        register(libc::SIGUSR1, write)?;
        wakeup();
        let mut buff = [0; 1];
        read.read_exact(&mut buff)?;
        assert_eq!(b"X", &buff);
        Ok(())
    }

    #[test]
    fn register_dgram_socket() -> Result<(), Error> {
        let (read, write) = UnixDatagram::pair()?;
        register(libc::SIGUSR1, write)?;
        wakeup();
        let mut buff = [0; 1];
        // The attempt to detect if it is socket can generate an empty message. Therefore, do a few
        // retries.
        for _ in 0..3 {
            let len = read.recv(&mut buff)?;
            if len == 1 && &buff == b"X" {
                return Ok(());
            }
        }
        panic!("Haven't received the right data");
    }

    #[test]
    fn register_with_pipe() -> Result<(), Error> {
        let mut fds = [0; 2];
        unsafe { assert_eq!(0, libc::pipe(fds.as_mut_ptr())) };
        register_raw(libc::SIGUSR1, fds[1])?;
        wakeup();
        let mut buff = [0; 1];
        unsafe { assert_eq!(1, libc::read(fds[0], buff.as_mut_ptr() as *mut _, 1)) }
        assert_eq!(b"X", &buff);
        Ok(())
    }
}
<|endoftext|>