<commit_before>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

mod command;
mod cursor;
mod insert;
mod normal;

use rustty::{self, Event, Color};
use editor;

/// `Term` represents our client application. This allows
/// us to work with the filesystem and the UI.
pub struct Term<'a> {
    /// Represents the location of the cursor in our UI
    cursor: cursor::Cursor,
    /// Contains file information; allows us to work with
    /// the filesystem
    editor: &'a mut editor::Editor<'a>,
    /// This is the UI itself
    term: rustty::Terminal,
    /// Represents the running status
    quit: bool,
    /// Represents the topmost line of the file we are editing in our UI
    line: usize,
    /// Represents the total number of lines in the currently
    /// open file
    total_lines: usize,
    partial_lines: Vec<usize>,
}

impl<'a> Term<'a> {
    /// Creates a new `Term` using the given `editor`.
    pub fn new(editor: &'a mut editor::Editor<'a>) -> Term<'a> {
        Term {
            cursor: cursor::Cursor::new(Color::Red),
            editor: editor,
            term: rustty::Terminal::new().unwrap(),
            quit: false,
            line: 0,
            total_lines: 0,
            partial_lines: vec![],
        }
    }

    /// Launches the terminal.
    pub fn run(&mut self) {
        self.editor.read_file();
        let lines = self.editor.contents.len() as isize;
        self.set_total_lines(lines);

        self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
        let current_line = self.current_line();
        self.print_file(current_line);
        self.prompt();
        self.term.swap_buffers().unwrap();

        while !self.quit {
            let evt = self.term.get_event(100).unwrap();
            if let Some(Event::Key(ch)) = evt {
                if self.editor.normal_mode() {
                    normal::handle(self, ch);
                } else if self.editor.command_mode() {
                    command::handle(self, ch);
                } else {
                    insert::handle(self, ch);
                }

                if self.cursor.pos.x > self.term.cols() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y += 1;
                }
                if self.cursor.pos.y >= self.term.rows() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y = 0;
                }

                self.term[self.cursor.last_pos()].set_bg(Color::Default);
                self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
                self.term.swap_buffers().unwrap();
            }
        }
    }

    /// Prints our prompt to the UI.
    pub fn prompt(&mut self) {
        let w = self.term.cols();
        let h = self.term.rows();

        for i in 0..w {
            self.term[(i, h - 2)].set_bg(Color::Red);
        }

        for (i, c) in self.editor.filename().chars().enumerate() {
            self.term[(i, h - 2)].set_ch(c);
        }
    }

    /// Prints our editor's contents to the UI.
    fn print_file(&mut self, start: usize) {
        self.partial_lines = vec![];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;
        for line in &self.editor.contents {
            if i < start {
                i += 1;
                continue;
            }

            for &b in line {
                if b == b'\n' {
                    continue;
                } else if j == w {
                    i += 1;
                    j = 0;
                    self.partial_lines.push(i - start);
                }

                self.term[(j, i - start)].set_ch(b as char);
                j += 1;
            }
            while j < w {
                self.term[(j, i - start)].set_ch(' ');
                j += 1;
            }

            i += 1;
            j = 0;
            if i - start == self.term.rows() - 2 {
                break;
            }
        }
    }

    /// Handles moving the cursor
    pub fn move_cursor(&mut self, direction: cursor::Direction) {
        match direction {
            cursor::Direction::Up => {
                if self.cursor.pos.y > 0 {
                    self.cursor.save_pos();
                    let mut i = self.cursor.pos.y - 1;
                    while self.partial_lines.contains(&i) {
                        self.cursor.pos.y -= 1;
                        i -= 1;
                    }
                    self.cursor.pos.y -= 1;
                    let curr = self.current_line() - 1;
                    self.set_current_line(curr);

                    let len = self.editor.contents[curr].len() - 2;
                    if self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                    }
                }
            }
            cursor::Direction::Down => {
                if self.cursor.pos.y < self.term.rows() - 3 {
                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;

                    self.cursor.save_pos();
                    self.set_current_line(curr + 1);

                    if len > self.term.cols() {
                        let mut adv = len / self.term.cols();
                        if len % self.term.cols() > 0 {
                            adv += 1;
                        }
                        if self.partial_lines.contains(&self.cursor.pos.y) {
                            adv -= 1;
                        }
                        self.cursor.pos.y += adv;
                    } else {
                        self.cursor.pos.y += 1;
                    }

                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 2;
                    if self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                    }
                }
            }
            cursor::Direction::Left => {
                let y = self.cursor.pos.y;

                if self.cursor.pos.x != 0 {
                    self.cursor.save_pos();
                    self.cursor.pos.x -= 1;
                    self.cursor.in_line -= 1;
                } else if self.partial_lines.contains(&y) {
                    self.cursor.save_pos();
                    self.cursor.pos.y -= 1;
                    self.cursor.pos.x = self.term.cols() - 1;
                    self.cursor.in_line -= 1;
                }
            }
            cursor::Direction::Right => {
                let (x, y) = self.cursor.current_pos();
                let curr = self.current_line();
                let len = self.editor.contents[curr].len();

                if self.cursor.in_line < len - 2 {
                    if x < self.term.cols() - 1 {
                        self.cursor.save_pos();
                        self.cursor.pos.x += 1;
                        self.cursor.in_line += 1;
                    } else {
                        self.cursor.save_pos();
                        self.cursor.pos.x = 1;
                        self.cursor.pos.y += 1;
                        self.cursor.in_line += 1;
                    }
                }
            }
        }
    }

    /// Changes the value of the `quit` attribute to `true`.
    pub fn quit(&mut self) {
        self.quit = true;
    }

    /// Returns the total lines in our file
    pub fn total_lines(&self) -> usize {
        self.total_lines
    }

    /// Allows us to modify the total number of lines
    /// in our file, e.g. if a new line is added.
    pub fn set_total_lines(&mut self, change: isize) {
        let new = self.total_lines as isize + change;
        self.total_lines = new as usize;
    }

    /// Gives the current line at the top of our UI
    pub fn current_line(&self) -> usize {
        self.line
    }

    /// Allows us to change what the topmost line in the UI is
    pub fn set_current_line(&mut self, line: usize) {
        self.line = line;
    }

    /// This function redraws the portion of our UI displaying
    /// file contents. E.g. this is called when the current line
    /// changes.
    pub fn redraw_file(&mut self) {
        let current_line = self.current_line();
        self.print_file(current_line);
    }

    /// This function redraws the given line of the UI on the screen.
    pub fn redraw_line(&mut self, ui_line: usize) {
        let file_line = ui_line + self.current_line();
        self.print_line(ui_line, file_line);
    }

    pub fn print_line(&mut self, ui_line: usize, file_line: usize) {
        let contents = &self.editor.contents[file_line];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;

        for &b in contents {
            if b == b'\n' {
                continue;
            } else if i == w {
                i = 0;
                j += 1;
            }
            self.term[(i, ui_line + j)].set_ch(b as char);
            i += 1;
        }

        while i < self.term.cols() {
            self.term[(i, ui_line + j)].set_ch(' ');
            i += 1;
        }
    }
}
<commit_msg>Fixes several bugs for up, down, and right movement<commit_after>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

mod command;
mod cursor;
mod insert;
mod normal;

use rustty::{self, Event, Color};
use editor;

/// `Term` represents our client application. This allows
/// us to work with the filesystem and the UI.
pub struct Term<'a> {
    /// Represents the location of the cursor in our UI
    cursor: cursor::Cursor,
    /// Contains file information; allows us to work with
    /// the filesystem
    editor: &'a mut editor::Editor<'a>,
    /// This is the UI itself
    term: rustty::Terminal,
    /// Represents the running status
    quit: bool,
    /// Represents the topmost line of the file we are editing in our UI
    line: usize,
    /// Represents the total number of lines in the currently
    /// open file
    total_lines: usize,
    partial_lines: Vec<usize>,
}

impl<'a> Term<'a> {
    /// Creates a new `Term` using the given `editor`.
    pub fn new(editor: &'a mut editor::Editor<'a>) -> Term<'a> {
        Term {
            cursor: cursor::Cursor::new(Color::Red),
            editor: editor,
            term: rustty::Terminal::new().unwrap(),
            quit: false,
            line: 0,
            total_lines: 0,
            partial_lines: vec![],
        }
    }

    /// Launches the terminal.
    pub fn run(&mut self) {
        self.editor.read_file();
        let lines = self.editor.contents.len() as isize;
        self.set_total_lines(lines);

        self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
        let current_line = self.current_line();
        self.print_file(current_line);
        self.prompt();
        self.term.swap_buffers().unwrap();

        while !self.quit {
            let evt = self.term.get_event(100).unwrap();
            if let Some(Event::Key(ch)) = evt {
                if self.editor.normal_mode() {
                    normal::handle(self, ch);
                } else if self.editor.command_mode() {
                    command::handle(self, ch);
                } else {
                    insert::handle(self, ch);
                }

                if self.cursor.pos.x > self.term.cols() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y += 1;
                }
                if self.cursor.pos.y >= self.term.rows() - 1 {
                    self.term[self.cursor.last_pos()].set_bg(Color::Default);
                    self.cursor.save_pos();
                    self.cursor.pos.x = 0;
                    self.cursor.pos.y = 0;
                }

                self.term[self.cursor.last_pos()].set_bg(Color::Default);
                self.term[self.cursor.current_pos()].set_bg(self.cursor.color);
                self.term.swap_buffers().unwrap();
            }
        }
    }

    /// Prints our prompt to the UI.
    pub fn prompt(&mut self) {
        let w = self.term.cols();
        let h = self.term.rows();

        for i in 0..w {
            self.term[(i, h - 2)].set_bg(Color::Red);
        }

        for (i, c) in self.editor.filename().chars().enumerate() {
            self.term[(i, h - 2)].set_ch(c);
        }
    }

    /// Prints our editor's contents to the UI.
    fn print_file(&mut self, start: usize) {
        self.partial_lines = vec![];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;
        for line in &self.editor.contents {
            if i < start {
                i += 1;
                continue;
            }

            for &b in line {
                if b == b'\n' {
                    continue;
                } else if j == w {
                    i += 1;
                    j = 0;
                    self.partial_lines.push(i - start);
                }

                self.term[(j, i - start)].set_ch(b as char);
                j += 1;
            }
            while j < w {
                self.term[(j, i - start)].set_ch(' ');
                j += 1;
            }

            i += 1;
            j = 0;
            if i - start == self.term.rows() - 2 {
                break;
            }
        }
    }

    /// Handles moving the cursor
    pub fn move_cursor(&mut self, direction: cursor::Direction) {
        match direction {
            cursor::Direction::Up => {
                if self.cursor.pos.y > 0 {
                    self.cursor.save_pos();
                    let mut i = self.cursor.pos.y - 1;
                    while self.partial_lines.contains(&i) {
                        self.cursor.pos.y -= 1;
                        i -= 1;
                    }
                    self.cursor.pos.y -= 1;
                    let curr = self.current_line() - 1;
                    self.set_current_line(curr);

                    let len = self.editor.contents[curr].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                }
            }
            cursor::Direction::Down => {
                if self.cursor.pos.y < self.term.rows() - 3 {
                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;

                    self.cursor.save_pos();
                    self.set_current_line(curr + 1);

                    if len > self.term.cols() {
                        let mut adv = len / self.term.cols();
                        if len % self.term.cols() > 0 {
                            adv += 1;
                        }
                        if self.partial_lines.contains(&self.cursor.pos.y) {
                            adv -= 1;
                        }
                        self.cursor.pos.y += adv;
                    } else {
                        self.cursor.pos.y += 1;
                    }

                    let curr = self.current_line();
                    let len = self.editor.contents[curr].len() - 1;
                    if len == 0 && self.cursor.pos.x > len {
                        self.cursor.pos.x = len;
                        self.cursor.in_line = len;
                    } else if len > 0 && self.cursor.pos.x > len - 1 {
                        self.cursor.pos.x = len - 1;
                        self.cursor.in_line = len - 1;
                    }
                }
            }
            cursor::Direction::Left => {
                let y = self.cursor.pos.y;

                if self.cursor.pos.x != 0 {
                    self.cursor.save_pos();
                    self.cursor.pos.x -= 1;
                    self.cursor.in_line -= 1;
                } else if self.partial_lines.contains(&y) {
                    self.cursor.save_pos();
                    self.cursor.pos.y -= 1;
                    self.cursor.pos.x = self.term.cols() - 1;
                    self.cursor.in_line -= 1;
                }
            }
            cursor::Direction::Right => {
                let (x, y) = self.cursor.current_pos();
                let curr = self.current_line();
                let len = self.editor.contents[curr].len() - 1;

                if len > 0 && self.cursor.in_line < len - 1 {
                    if x < self.term.cols() - 1 {
                        self.cursor.save_pos();
                        self.cursor.pos.x += 1;
                        self.cursor.in_line += 1;
                    } else {
                        self.cursor.save_pos();
                        self.cursor.pos.x = 1;
                        self.cursor.pos.y += 1;
                        self.cursor.in_line += 1;
                    }
                }
            }
        }
    }

    /// Changes the value of the `quit` attribute to `true`.
    pub fn quit(&mut self) {
        self.quit = true;
    }

    /// Returns the total lines in our file
    pub fn total_lines(&self) -> usize {
        self.total_lines
    }

    /// Allows us to modify the total number of lines
    /// in our file, e.g. if a new line is added.
    pub fn set_total_lines(&mut self, change: isize) {
        let new = self.total_lines as isize + change;
        self.total_lines = new as usize;
    }

    /// Gives the current line at the top of our UI
    pub fn current_line(&self) -> usize {
        self.line
    }

    /// Allows us to change what the topmost line in the UI is
    pub fn set_current_line(&mut self, line: usize) {
        self.line = line;
    }

    /// This function redraws the portion of our UI displaying
    /// file contents. E.g. this is called when the current line
    /// changes.
    pub fn redraw_file(&mut self) {
        let current_line = self.current_line();
        self.print_file(current_line);
    }

    /// This function redraws the given line of the UI on the screen.
    pub fn redraw_line(&mut self, ui_line: usize) {
        let file_line = ui_line + self.current_line();
        self.print_line(ui_line, file_line);
    }

    pub fn print_line(&mut self, ui_line: usize, file_line: usize) {
        let contents = &self.editor.contents[file_line];
        let w = self.term.cols();
        let mut i = 0;
        let mut j = 0;

        for &b in contents {
            if b == b'\n' {
                continue;
            } else if i == w {
                i = 0;
                j += 1;
            }
            self.term[(i, ui_line + j)].set_ch(b as char);
            i += 1;
        }

        while i < self.term.cols() {
            self.term[(i, ui_line + j)].set_ch(' ');
            i += 1;
        }
    }
}
<|endoftext|>


<commit_before>use openvr_sys as sys;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TrackingUniverseOrigin {
    Seated = sys::ETrackingUniverseOrigin_ETrackingUniverseOrigin_TrackingUniverseSeated as isize,
    Standing = sys::ETrackingUniverseOrigin_ETrackingUniverseOrigin_TrackingUniverseStanding as isize,
    RawAndUncalibrated = sys::ETrackingUniverseOrigin_ETrackingUniverseOrigin_TrackingUniverseRawAndUncalibrated as isize,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct TrackedDevicePose(sys::TrackedDevicePose_t);

impl TrackedDevicePose {
    pub fn device_to_absolute_tracking(&self) -> &[[f32; 4]; 3] { &self.0.mDeviceToAbsoluteTracking.m }
    pub fn velocity(&self) -> &[f32; 3] { &self.0.vVelocity.v }
    pub fn angular_velocity(&self) -> &[f32; 3] { &self.0.vAngularVelocity.v }
    pub fn tracking_result(&self) -> TrackingResult {
        use self::TrackingResult::*;
        match self.0.eTrackingResult {
            sys::ETrackingResult_ETrackingResult_TrackingResult_Uninitialized => Uninitialized,
            sys::ETrackingResult_ETrackingResult_TrackingResult_Calibrating_InProgress => CalibratingInProgress,
            sys::ETrackingResult_ETrackingResult_TrackingResult_Calibrating_OutOfRange => CalibratingOutOfRange,
            sys::ETrackingResult_ETrackingResult_TrackingResult_Running_OK => OK,
            sys::ETrackingResult_ETrackingResult_TrackingResult_Running_OutOfRange => RunningOutOfRange,
            _ => panic!("unrecognized tracking result")
        }
    }
    pub fn pose_is_valid(&self) -> bool { self.0.bPoseIsValid }
    pub fn device_is_connected(&self) -> bool { self.0.bDeviceIsConnected }
}

pub enum TrackingResult {
    Uninitialized = sys::ETrackingResult_ETrackingResult_TrackingResult_Uninitialized as isize,
    CalibratingInProgress = sys::ETrackingResult_ETrackingResult_TrackingResult_Calibrating_InProgress as isize,
    CalibratingOutOfRange = sys::ETrackingResult_ETrackingResult_TrackingResult_Calibrating_OutOfRange as isize,
    OK = sys::ETrackingResult_ETrackingResult_TrackingResult_Running_OK as isize,
    RunningOutOfRange = sys::ETrackingResult_ETrackingResult_TrackingResult_Running_OutOfRange as isize,
}

pub enum TrackedDeviceClass {
    Invalid = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_Invalid as isize,
    HMD = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_HMD as isize,
    Controller = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_Controller as isize,
    GenericTracker = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_GenericTracker as isize,
    TrackingReference = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_TrackingReference as isize,
    DisplayRedirect = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_DisplayRedirect as isize,
}

pub type TrackedDeviceIndex = sys::TrackedDeviceIndex_t;

pub mod tracked_device_index {
    use super::*;
    pub const HMD: TrackedDeviceIndex = sys::k_unTrackedDeviceIndex_Hmd;
    pub const INVALID: TrackedDeviceIndex = sys::k_unTrackedDeviceIndexInvalid;
}

pub type TrackedDeviceProperty = sys::ETrackedDeviceProperty;
<commit_msg>Fix some missing derives<commit_after>use openvr_sys as sys;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TrackingUniverseOrigin {
    Seated = sys::ETrackingUniverseOrigin_ETrackingUniverseOrigin_TrackingUniverseSeated as isize,
    Standing = sys::ETrackingUniverseOrigin_ETrackingUniverseOrigin_TrackingUniverseStanding as isize,
    RawAndUncalibrated = sys::ETrackingUniverseOrigin_ETrackingUniverseOrigin_TrackingUniverseRawAndUncalibrated as isize,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct TrackedDevicePose(sys::TrackedDevicePose_t);

impl TrackedDevicePose {
    pub fn device_to_absolute_tracking(&self) -> &[[f32; 4]; 3] { &self.0.mDeviceToAbsoluteTracking.m }
    pub fn velocity(&self) -> &[f32; 3] { &self.0.vVelocity.v }
    pub fn angular_velocity(&self) -> &[f32; 3] { &self.0.vAngularVelocity.v }
    pub fn tracking_result(&self) -> TrackingResult {
        use self::TrackingResult::*;
        match self.0.eTrackingResult {
            sys::ETrackingResult_ETrackingResult_TrackingResult_Uninitialized => Uninitialized,
            sys::ETrackingResult_ETrackingResult_TrackingResult_Calibrating_InProgress => CalibratingInProgress,
            sys::ETrackingResult_ETrackingResult_TrackingResult_Calibrating_OutOfRange => CalibratingOutOfRange,
            sys::ETrackingResult_ETrackingResult_TrackingResult_Running_OK => OK,
            sys::ETrackingResult_ETrackingResult_TrackingResult_Running_OutOfRange => RunningOutOfRange,
            _ => panic!("unrecognized tracking result")
        }
    }
    pub fn pose_is_valid(&self) -> bool { self.0.bPoseIsValid }
    pub fn device_is_connected(&self) -> bool { self.0.bDeviceIsConnected }
}

#[derive(Debug, Copy, Clone)]
pub enum TrackingResult {
    Uninitialized = sys::ETrackingResult_ETrackingResult_TrackingResult_Uninitialized as isize,
    CalibratingInProgress = sys::ETrackingResult_ETrackingResult_TrackingResult_Calibrating_InProgress as isize,
    CalibratingOutOfRange = sys::ETrackingResult_ETrackingResult_TrackingResult_Calibrating_OutOfRange as isize,
    OK = sys::ETrackingResult_ETrackingResult_TrackingResult_Running_OK as isize,
    RunningOutOfRange = sys::ETrackingResult_ETrackingResult_TrackingResult_Running_OutOfRange as isize,
}

#[derive(Debug, Copy, Clone)]
pub enum TrackedDeviceClass {
    Invalid = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_Invalid as isize,
    HMD = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_HMD as isize,
    Controller = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_Controller as isize,
    GenericTracker = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_GenericTracker as isize,
    TrackingReference = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_TrackingReference as isize,
    DisplayRedirect = sys::ETrackedDeviceClass_ETrackedDeviceClass_TrackedDeviceClass_DisplayRedirect as isize,
}

pub type TrackedDeviceIndex = sys::TrackedDeviceIndex_t;

pub mod tracked_device_index {
    use super::*;
    pub const HMD: TrackedDeviceIndex = sys::k_unTrackedDeviceIndex_Hmd;
    pub const INVALID: TrackedDeviceIndex = sys::k_unTrackedDeviceIndexInvalid;
}

pub type TrackedDeviceProperty = sys::ETrackedDeviceProperty;
<|endoftext|>


<commit_before>extern crate libc;
use super::{Width, Height};
use std::os::raw::*;

#[derive(Debug)]
struct WinSize {
    ws_row: c_ushort,
    ws_col: c_ushort,
    ws_xpixel: c_ushort,
    ws_ypixel: c_ushort,
}

/// Returns the size of the terminal, if available.
///
/// If STDOUT is not a tty, returns `None`
pub fn terminal_size() -> Option<(Width, Height)> {
    use self::libc::{ioctl, isatty, STDOUT_FILENO, TIOCGWINSZ};
    let is_tty: bool = unsafe { isatty(STDOUT_FILENO) == 1 };

    if !is_tty {
        return None;
    }

    let (rows, cols) = unsafe {
        let mut winsize = WinSize {
            ws_row: 0,
            ws_col: 0,
            ws_xpixel: 0,
            ws_ypixel: 0,
        };
        ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut winsize);
        let rows = if winsize.ws_row > 0 {
            winsize.ws_row
        } else {
            0
        };
        let cols = if winsize.ws_col > 0 {
            winsize.ws_col
        } else {
            0
        };
        (rows as u16, cols as u16)
    };

    if rows > 0 && cols > 0 {
        Some((Width(cols), Height(rows)))
    } else {
        None
    }
}

#[test]
/// Compare with the output of `stty size`
fn compare_with_stty() {
    use std::process::Command;
    use std::process::Stdio;
    let mut args = vec!["-F", "/dev/stderr", "size"];
    if cfg!(target_os = "macos") {
        args[0] = "-f"
    }
    let output = Command::new("stty")
                     .args(&args)
                     .stderr(Stdio::inherit())
                     .output()
                     .unwrap();
    let stdout = String::from_utf8(output.stdout).unwrap();
    assert!(output.status.success());

    // stdout is "rows cols"
    let mut data = stdout.split_whitespace();
    let rows = u16::from_str_radix(data.next().unwrap(), 10).unwrap();
    let cols = u16::from_str_radix(data.next().unwrap(), 10).unwrap();
    println!("{}", stdout);
    println!("{} {}", rows, cols);

    if let Some((Width(w), Height(h))) = terminal_size() {
        assert_eq!(rows, h);
        assert_eq!(cols, w);
    }
}
<commit_msg>Use winsize from libc<commit_after>extern crate libc;
use super::{Width, Height};

/// Returns the size of the terminal, if available.
///
/// If STDOUT is not a tty, returns `None`
pub fn terminal_size() -> Option<(Width, Height)> {
    use self::libc::{ioctl, isatty, STDOUT_FILENO, TIOCGWINSZ, winsize};
    let is_tty: bool = unsafe { isatty(STDOUT_FILENO) == 1 };

    if !is_tty {
        return None;
    }

    let (rows, cols) = unsafe {
        let mut winsize = winsize {
            ws_row: 0,
            ws_col: 0,
            ws_xpixel: 0,
            ws_ypixel: 0,
        };
        ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut winsize);
        let rows = if winsize.ws_row > 0 {
            winsize.ws_row
        } else {
            0
        };
        let cols = if winsize.ws_col > 0 {
            winsize.ws_col
        } else {
            0
        };
        (rows as u16, cols as u16)
    };

    if rows > 0 && cols > 0 {
        Some((Width(cols), Height(rows)))
    } else {
        None
    }
}

#[test]
/// Compare with the output of `stty size`
fn compare_with_stty() {
    use std::process::Command;
    use std::process::Stdio;
    let mut args = vec!["-F", "/dev/stderr", "size"];
    if cfg!(target_os = "macos") {
        args[0] = "-f"
    }
    let output = Command::new("stty")
                     .args(&args)
                     .stderr(Stdio::inherit())
                     .output()
                     .unwrap();
    let stdout = String::from_utf8(output.stdout).unwrap();
    assert!(output.status.success());

    // stdout is "rows cols"
    let mut data = stdout.split_whitespace();
    let rows = u16::from_str_radix(data.next().unwrap(), 10).unwrap();
    let cols = u16::from_str_radix(data.next().unwrap(), 10).unwrap();
    println!("{}", stdout);
    println!("{} {}", rows, cols);

    if let Some((Width(w), Height(h))) = terminal_size() {
        assert_eq!(rows, h);
        assert_eq!(cols, w);
    }
}
<|endoftext|>


<commit_before>use crate::FileTime;
use libc::{time_t, timespec};
use std::fs;
use std::os::unix::prelude::*;

cfg_if::cfg_if! {
    if #[cfg(target_os = "linux")] {
        mod utimes;
        mod linux;
        pub use self::linux::*;
    } else if #[cfg(target_os = "android")] {
        mod android;
        pub use self::android::*;
    } else if #[cfg(target_os = "macos")] {
        mod utimes;
        mod macos;
        pub use self::macos::*;
    } else if #[cfg(any(target_os = "solaris",
                        target_os = "illumos",
                        target_os = "emscripten",
                        target_os = "freebsd",
                        target_os = "netbsd",
                        target_os = "openbsd",
                        target_os = "haiku"))] {
        mod utimensat;
        pub use self::utimensat::*;
    } else {
        mod utimes;
        pub use self::utimes::*;
    }
}

#[allow(dead_code)]
fn to_timespec(ft: &Option<FileTime>) -> timespec {
    cfg_if::cfg_if! {
        if #[cfg(any(target_os = "macos",
                     target_os = "illumos",
                     target_os = "freebsd"))] {
            // https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/sys/stat.h#L541
            // https://github.com/illumos/illumos-gate/blob/master/usr/src/boot/sys/sys/stat.h#L312
            // https://svnweb.freebsd.org/base/head/sys/sys/stat.h?view=markup#l359
            const UTIME_OMIT: i64 = -2;
        } else if #[cfg(target_os = "openbsd")] {
            // https://github.com/openbsd/src/blob/master/sys/sys/stat.h#L189
            const UTIME_OMIT: i64 = -1;
        } else if #[cfg(target_os = "haiku")] {
            // https://git.haiku-os.org/haiku/tree/headers/posix/sys/stat.h?#n106
            const UTIME_OMIT: i64 = 1000000001;
        } else {
            // http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/stat.h?annotate=1.68.30.1
            // https://github.com/emscripten-core/emscripten/blob/master/system/include/libc/sys/stat.h#L71
            const UTIME_OMIT: i64 = 1_073_741_822;
        }
    }

    if let &Some(ft) = ft {
        timespec {
            tv_sec: ft.seconds() as time_t,
            tv_nsec: ft.nanoseconds() as _,
        }
    } else {
        timespec {
            tv_sec: 0,
            tv_nsec: UTIME_OMIT as _,
        }
    }
}

pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.mtime(),
        nanos: meta.mtime_nsec() as u32,
    }
}

pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.atime(),
        nanos: meta.atime_nsec() as u32,
    }
}

pub fn from_creation_time(meta: &fs::Metadata) -> Option<FileTime> {
    macro_rules! birthtim {
        ($(($e:expr, $i:ident)),*) => {
            #[cfg(any($(target_os = $e),*))]
            fn imp(meta: &fs::Metadata) -> Option<FileTime> {
                $(
                    #[cfg(target_os = $e)]
                    use std::os::$i::fs::MetadataExt;
                )*
                Some(FileTime {
                    seconds: meta.st_birthtime(),
                    nanos: meta.st_birthtime_nsec() as u32,
                })
            }

            #[cfg(all($(not(target_os = $e)),*))]
            fn imp(_meta: &fs::Metadata) -> Option<FileTime> {
                None
            }
        }
    }

    birthtim! {
        ("bitrig", bitrig),
        ("freebsd", freebsd),
        ("ios", ios),
        ("macos", macos),
        ("openbsd", openbsd)
    }

    imp(meta)
}
<commit_msg>Add support for AIX (#85)<commit_after>use crate::FileTime;
use libc::{time_t, timespec};
use std::fs;
use std::os::unix::prelude::*;

cfg_if::cfg_if! {
    if #[cfg(target_os = "linux")] {
        mod utimes;
        mod linux;
        pub use self::linux::*;
    } else if #[cfg(target_os = "android")] {
        mod android;
        pub use self::android::*;
    } else if #[cfg(target_os = "macos")] {
        mod utimes;
        mod macos;
        pub use self::macos::*;
    } else if #[cfg(any(target_os = "aix",
                        target_os = "solaris",
                        target_os = "illumos",
                        target_os = "emscripten",
                        target_os = "freebsd",
                        target_os = "netbsd",
                        target_os = "openbsd",
                        target_os = "haiku"))] {
        mod utimensat;
        pub use self::utimensat::*;
    } else {
        mod utimes;
        pub use self::utimes::*;
    }
}

#[allow(dead_code)]
fn to_timespec(ft: &Option<FileTime>) -> timespec {
    cfg_if::cfg_if! {
        if #[cfg(any(target_os = "macos",
                     target_os = "illumos",
                     target_os = "freebsd"))] {
            // https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/bsd/sys/stat.h#L541
            // https://github.com/illumos/illumos-gate/blob/master/usr/src/boot/sys/sys/stat.h#L312
            // https://svnweb.freebsd.org/base/head/sys/sys/stat.h?view=markup#l359
            const UTIME_OMIT: i64 = -2;
        } else if #[cfg(target_os = "openbsd")] {
            // https://github.com/openbsd/src/blob/master/sys/sys/stat.h#L189
            const UTIME_OMIT: i64 = -1;
        } else if #[cfg(target_os = "haiku")] {
            // https://git.haiku-os.org/haiku/tree/headers/posix/sys/stat.h?#n106
            const UTIME_OMIT: i64 = 1000000001;
        } else if #[cfg(target_os = "aix")] {
            // AIX hasn't disclosed system header files yet.
            // https://github.com/golang/go/blob/master/src/cmd/vendor/golang.org/x/sys/unix/zerrors_aix_ppc64.go#L1007
            const UTIME_OMIT: i64 = -3;
        } else {
            // http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/stat.h?annotate=1.68.30.1
            // https://github.com/emscripten-core/emscripten/blob/master/system/include/libc/sys/stat.h#L71
            const UTIME_OMIT: i64 = 1_073_741_822;
        }
    }

    if let &Some(ft) = ft {
        timespec {
            tv_sec: ft.seconds() as time_t,
            tv_nsec: ft.nanoseconds() as _,
        }
    } else {
        timespec {
            tv_sec: 0,
            tv_nsec: UTIME_OMIT as _,
        }
    }
}

pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.mtime(),
        nanos: meta.mtime_nsec() as u32,
    }
}

pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.atime(),
        nanos: meta.atime_nsec() as u32,
    }
}

pub fn from_creation_time(meta: &fs::Metadata) -> Option<FileTime> {
    macro_rules! birthtim {
        ($(($e:expr, $i:ident)),*) => {
            #[cfg(any($(target_os = $e),*))]
            fn imp(meta: &fs::Metadata) -> Option<FileTime> {
                $(
                    #[cfg(target_os = $e)]
                    use std::os::$i::fs::MetadataExt;
                )*
                Some(FileTime {
                    seconds: meta.st_birthtime(),
                    nanos: meta.st_birthtime_nsec() as u32,
                })
            }

            #[cfg(all($(not(target_os = $e)),*))]
            fn imp(_meta: &fs::Metadata) -> Option<FileTime> {
                None
            }
        }
    }

    birthtim! {
        ("bitrig", bitrig),
        ("freebsd", freebsd),
        ("ios", ios),
        ("macos", macos),
        ("openbsd", openbsd)
    }

    imp(meta)
}
<|endoftext|>


<commit_before>use std;
use std::f32::consts::PI;

use arrayvec::ArrayVec;
use num::complex::Complex32;
use collect_slice::CollectSlice;

use consts::SAMPLES;
use descramble::VoiceDecisions;
use enhance::EnhancedSpectrals;
use noise::Noise;
use params::BaseParams;
use window;

// Result of equation 121
const SCALING_COEF: f32 = 146.6432708443356;

pub struct UnvoicedDFT {
    dfts: ArrayVec<[Complex32; 256]>,
    scale: f32,
}

impl UnvoicedDFT {
    pub fn new(lower: isize, upper: isize, noise: &Noise, window: &window::Window)
        -> UnvoicedDFT
    {
        let dfts = (lower..upper).map(|m| {
            let mut nclone = noise.clone();

            (-104..105).map(|n| {
                nclone.next() * window.get(n) *
                    Complex32::new(0.0, -2.0 / 256.0 * PI * m as f32 * n as f32).exp()
            }).fold(Complex32::new(0.0, 0.0), |s, x| s + x)
        }).collect::<ArrayVec<[Complex32; 256]>>();

        let sum = dfts.iter().map(|dft| dft.norm_sqr()).fold(0.0, |s, x| s + x);

        UnvoicedDFT {
            dfts: dfts,
            scale: SCALING_COEF / (sum / (upper - lower) as f32).sqrt(),
        }
    }

    pub fn scale(&self, spectral: f32) -> f32 { self.scale * spectral }
}

impl std::ops::Deref for UnvoicedDFT {
    type Target = ArrayVec<[Complex32; 256]>;
    fn deref(&self) -> &Self::Target { &self.dfts }
}

fn edges(l: usize, params: &BaseParams) -> (isize, isize) {
    let edge = |inner: f32| {
        256.0 / (2.0 * PI) * inner * params.fundamental
    };

    (
        edge(l as f32 - 0.5).ceil() as isize,
        edge(l as f32 + 0.5).ceil() as isize,
    )
}

pub struct UnvoicedParts([Complex32; 256]);

impl UnvoicedParts {
    pub fn new(params: &BaseParams, voice: &VoiceDecisions, enhanced: &EnhancedSpectrals)
        -> UnvoicedParts
    {
        let mut parts = [Complex32::new(0.0, 0.0); 256];

        let noise = Noise::new();
        let window = window::synthesis_trunc();

        for (l, &m) in enhanced.iter().enumerate() {
            let l = l + 1;

            if voice.is_voiced(l) {
                continue;
            }

            let (lower, upper) = edges(l, params);

            let pos = UnvoicedDFT::new(lower, upper, &noise, &window);
            let pscale = pos.scale(m);

            let neg = UnvoicedDFT::new(-upper+1, -lower+1, &noise, &window);
            let nscale = neg.scale(m);

            pos.iter().map(|&dft| {
                pscale * dft
            }).collect_slice_checked(&mut parts[128 + lower as usize..128 + upper as usize]);

            neg.iter().rev().map(|&dft| {
                nscale * dft
            }).collect_slice_checked(&mut parts[128 - upper as usize + 1..128 - lower as usize + 1]);
        }

        UnvoicedParts(parts)
    }

    // -128 <= m < 128
    fn get(&self, m: isize) -> Complex32 { self.0[(m + 128) as usize] }

    pub fn idft(&self, n: isize) -> f32 {
        if n < -128 || n > 127 {
            return 0.0;
        }

        (-128..128).map(|m| {
            self.get(m) *
                Complex32::new(0.0, 2.0 / 256.0 * PI * m as f32 * n as f32).exp()
        }).fold(Complex32::new(0.0, 0.0), |s, x| s + x).re / 256.0
    }
}

impl Default for UnvoicedParts {
    fn default() -> UnvoicedParts {
        UnvoicedParts([Complex32::new(0.0, 0.0); 256])
    }
}

pub struct Unvoiced<'a, 'b> {
    cur: &'a UnvoicedParts,
    prev: &'b UnvoicedParts,
    window: window::Window,
}

impl<'a, 'b> Unvoiced<'a, 'b> {
    pub fn new(cur: &'a UnvoicedParts, prev: &'b UnvoicedParts) -> Unvoiced<'a, 'b> {
        Unvoiced {
            cur: cur,
            prev: prev,
            window: window::synthesis_full(),
        }
    }

    pub fn get(&self, n: usize) -> f32 {
        let n = n as isize;

        let numer = self.window.get(n) * self.prev.idft(n) +
            self.window.get(n - SAMPLES as isize) * self.cur.idft(n - SAMPLES as isize);
        let denom = self.window.get(n).powi(2) +
            self.window.get(n - SAMPLES as isize).powi(2);

        numer / denom
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::edges;
    use descramble::Bootstrap;
    use params::BaseParams;

    #[test]
    fn test_edges() {
        let chunks = [
            0b001000010010,
            0b110011001100,
            0b111000111000,
            0b111111111111,
            0b10100110101,
            0b00101111010,
            0b01110111011,
            0b00001000,
        ];

        let b = Bootstrap::new(&chunks);
        let p = BaseParams::new(b.unwrap_period());

        assert!((p.fundamental - 0.17575344).abs() < 0.000001);

        let (lower, upper) = edges(1, &p);
        assert_eq!(lower, 4);
        assert_eq!(upper, 11);

        let (lower, upper) = edges(2, &p);
        assert_eq!(lower, 11);
        assert_eq!(upper, 18);

        let (lower, upper) = edges(5, &p);
        assert_eq!(lower, 33);
        assert_eq!(upper, 40);

        let (lower, upper) = edges(8, &p);
        assert_eq!(lower, 54);
        assert_eq!(upper, 61);

        let (lower, upper) = edges(16, &p);
        assert_eq!(lower, 111);
        assert_eq!(upper, 119);
    }
}
<commit_msg>Fix unvoiced dft generation<commit_after>use std;
use std::f32::consts::PI;

use arrayvec::ArrayVec;
use num::complex::Complex32;
use collect_slice::CollectSlice;

use consts::SAMPLES;
use descramble::VoiceDecisions;
use enhance::EnhancedSpectrals;
use noise::Noise;
use params::BaseParams;
use window;

// Result of equation 121
const SCALING_COEF: f32 = 146.6432708443356;

pub struct UnvoicedDFT {
    dfts: ArrayVec<[Complex32; 256]>,
    scale: f32,
}

impl UnvoicedDFT {
    pub fn new(lower: isize, upper: isize, noise: &Noise, window: &window::Window)
        -> UnvoicedDFT
    {
        let dfts = (lower..upper).map(|m| {
            let mut nclone = noise.clone();

            (-104..105).map(|n| {
                nclone.next() * window.get(n) *
                    Complex32::new(0.0, -2.0 / 256.0 * PI * m as f32 * n as f32).exp()
            }).fold(Complex32::new(0.0, 0.0), |s, x| s + x)
        }).collect::<ArrayVec<[Complex32; 256]>>();

        let sum = dfts.iter().map(|dft| dft.norm_sqr()).fold(0.0, |s, x| s + x);

        UnvoicedDFT {
            dfts: dfts,
            scale: SCALING_COEF / (sum / (upper - lower) as f32).sqrt(),
        }
    }

    pub fn scale(&self, spectral: f32) -> f32 { self.scale * spectral }
}

impl std::ops::Deref for UnvoicedDFT {
    type Target = ArrayVec<[Complex32; 256]>;
    fn deref(&self) -> &Self::Target { &self.dfts }
}

fn edges(l: usize, params: &BaseParams) -> (isize, isize) {
    let edge = |inner: f32| {
        256.0 / (2.0 * PI) * inner * params.fundamental
    };

    (
        edge(l as f32 - 0.5).ceil() as isize,
        edge(l as f32 + 0.5).ceil() as isize,
    )
}

pub struct UnvoicedParts([Complex32; 256]);

impl UnvoicedParts {
    pub fn new(params: &BaseParams, voice: &VoiceDecisions, enhanced: &EnhancedSpectrals)
        -> UnvoicedParts
    {
        let mut parts = [Complex32::new(0.0, 0.0); 256];

        let noise = Noise::new();
        let window = window::synthesis_trunc();

        for (l, &m) in enhanced.iter().enumerate() {
            let l = l + 1;

            if voice.is_voiced(l) {
                continue;
            }

            let (lower, upper) = edges(l, params);

            let pos = UnvoicedDFT::new(lower, upper, &noise, &window);
            let pscale = pos.scale(m);

            let neg = UnvoicedDFT::new(-upper+1, -lower+1, &noise, &window);
            let nscale = neg.scale(m);

            pos.iter().map(|&dft| {
                pscale * dft
            }).collect_slice_checked(&mut parts[128 + lower as usize..128 + upper as usize]);

            neg.iter().map(|&dft| {
                nscale * dft
            }).collect_slice_checked(&mut parts[128 - upper as usize + 1..128 - lower as usize + 1]);
        }

        UnvoicedParts(parts)
    }

    // -128 <= m < 128
    fn get(&self, m: isize) -> Complex32 { self.0[(m + 128) as usize] }

    pub fn idft(&self, n: isize) -> f32 {
        if n < -128 || n > 127 {
            return 0.0;
        }

        (-128..128).map(|m| {
            self.get(m) *
                Complex32::new(0.0, 2.0 / 256.0 * PI * m as f32 * n as f32).exp()
        }).fold(Complex32::new(0.0, 0.0), |s, x| s + x).re / 256.0
    }
}

impl Default for UnvoicedParts {
    fn default() -> UnvoicedParts {
        UnvoicedParts([Complex32::new(0.0, 0.0); 256])
    }
}

pub struct Unvoiced<'a, 'b> {
    cur: &'a UnvoicedParts,
    prev: &'b UnvoicedParts,
    window: window::Window,
}

impl<'a, 'b> Unvoiced<'a, 'b> {
    pub fn new(cur: &'a UnvoicedParts, prev: &'b UnvoicedParts) -> Unvoiced<'a, 'b> {
        Unvoiced {
            cur: cur,
            prev: prev,
            window: window::synthesis_full(),
        }
    }

    pub fn get(&self, n: usize) -> f32 {
        let n = n as isize;

        let numer = self.window.get(n) * self.prev.idft(n) +
            self.window.get(n - SAMPLES as isize) * self.cur.idft(n - SAMPLES as isize);
        let denom = self.window.get(n).powi(2) +
            self.window.get(n - SAMPLES as isize).powi(2);

        numer / denom
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::edges;
    use descramble::Bootstrap;
    use params::BaseParams;

    #[test]
    fn test_edges() {
        let chunks = [
            0b001000010010,
            0b110011001100,
            0b111000111000,
            0b111111111111,
            0b10100110101,
            0b00101111010,
            0b01110111011,
            0b00001000,
        ];

        let b = Bootstrap::new(&chunks);
        let p = BaseParams::new(b.unwrap_period());

        assert!((p.fundamental - 0.17575344).abs() < 0.000001);

        let (lower, upper) = edges(1, &p);
        assert_eq!(lower, 4);
        assert_eq!(upper, 11);

        let (lower, upper) = edges(2, &p);
        assert_eq!(lower, 11);
        assert_eq!(upper, 18);

        let (lower, upper) = edges(5, &p);
        assert_eq!(lower, 33);
        assert_eq!(upper, 40);

        let (lower, upper) = edges(8, &p);
        assert_eq!(lower, 54);
        assert_eq!(upper, 61);

        let (lower, upper) = edges(16, &p);
        assert_eq!(lower, 111);
        assert_eq!(upper, 119);
    }
}
<|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 properties::GeckoComputedValues;
use selectors::parser::{ParserContext, SelectorImpl};
use style;
use style::element_state::ElementState;
use style::selector_impl::SelectorImplExt;

pub type Stylist = style::selector_matching::Stylist<GeckoSelectorImpl>;
pub type Stylesheet = style::stylesheets::Stylesheet<GeckoSelectorImpl>;
pub type SharedStyleContext = style::context::SharedStyleContext<GeckoSelectorImpl>;
pub type PrivateStyleData = style::data::PrivateStyleData<GeckoSelectorImpl, GeckoComputedValues>;

pub struct GeckoSelectorImpl;

#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)]
pub enum PseudoElement {
    Before,
    After,
    FirstLine,
    // TODO: Probably a few more are missing here

    // https://mxr.mozilla.org/mozilla-central/source/layout/style/nsCSSAnonBoxList.h
    MozNonElement,
    MozAnonymousBlock,
    MozAnonymousPositionedBlock,
    MozMathMLAnonymousBlock,
    MozXULAnonymousBlock,

    MozHorizontalFramesetBorder,
    MozVerticalFramesetBorder,
    MozLineFrame,
    MozButtonContent,
    MozButtonLabel,
    MozCellContent,
    MozDropdownList,
    MozFieldsetContent,
    MozFramesetBlank,
    MozDisplayComboboxControlFrame,

    MozHTMLCanvasContent,
    MozInlineTable,
    MozTable,
    MozTableCell,
    MozTableColumnGroup,
    MozTableColumn,
    MozTableOuter,
    MozTableRowGroup,
    MozTableRow,

    MozCanvas,
    MozPageBreak,
    MozPage,
    MozPageContent,
    MozPageSequence,
    MozScrolledContent,
    MozScrolledCanvas,
    MozScrolledPageSequence,
    MozColumnContent,
    MozViewport,
    MozViewportScroll,
    MozAnonymousFlexItem,
    MozAnonymousGridItem,

    MozRuby,
    MozRubyBase,
    MozRubyBaseContainer,
    MozRubyText,
    MozRubyTextContainer,

    MozTreeColumn,
    MozTreeRow,
    MozTreeSeparator,
    MozTreeCell,
    MozTreeIndentation,
    MozTreeLine,
    MozTreeTwisty,
    MozTreeImage,
    MozTreeCellText,
    MozTreeCheckbox,
    MozTreeProgressMeter,
    MozTreeDropFeedback,

    MozSVGMarkerAnonChild,
    MozSVGOuterSVGAnonChild,
    MozSVGForeignContent,
    MozSVGText,
}

#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)]
pub enum NonTSPseudoClass {
    AnyLink,
    Link,
    Visited,
    Active,
    Focus,
    Hover,
    Enabled,
    Disabled,
    Checked,
    Indeterminate,
    ReadWrite,
    ReadOnly,
}

impl NonTSPseudoClass {
    pub fn state_flag(&self) -> ElementState {
        use self::NonTSPseudoClass::*;
        use style::element_state::*;
        match *self {
            Active => IN_ACTIVE_STATE,
            Focus => IN_FOCUS_STATE,
            Hover => IN_HOVER_STATE,
            Enabled => IN_ENABLED_STATE,
            Disabled => IN_DISABLED_STATE,
            Checked => IN_CHECKED_STATE,
            Indeterminate => IN_INDETERMINATE_STATE,
            ReadOnly | ReadWrite => IN_READ_WRITE_STATE,

            AnyLink |
            Link |
            Visited => ElementState::empty(),
        }
    }
}

impl SelectorImpl for GeckoSelectorImpl {
    type PseudoElement = PseudoElement;
    type NonTSPseudoClass = NonTSPseudoClass;
    fn parse_non_ts_pseudo_class(_context: &ParserContext,
                                 name: &str) -> Result<NonTSPseudoClass, ()> {
        use self::NonTSPseudoClass::*;
        let pseudo_class = match_ignore_ascii_case! { name,
            "any-link" => AnyLink,
            "link" => Link,
            "visited" => Visited,
            "active" => Active,
            "focus" => Focus,
            "hover" => Hover,
            "enabled" => Enabled,
            "disabled" => Disabled,
            "checked" => Checked,
            "indeterminate" => Indeterminate,
            "read-write" => ReadWrite,
            "read-only" => ReadOnly,
            _ => return Err(())
        };

        Ok(pseudo_class)
    }

    fn parse_pseudo_element(_context: &ParserContext,
                            name: &str) -> Result<PseudoElement, ()> {
        use self::PseudoElement::*;
        let pseudo_element = match_ignore_ascii_case! { name,
            "before" => Before,
            "after" => After,
            "first-line" => FirstLine,

            "-moz-non-element" => MozNonElement,

            "-moz-anonymous-block" => MozAnonymousBlock,
            "-moz-anonymous-positioned-block" => MozAnonymousPositionedBlock,
            "-moz-mathml-anonymous-block" => MozMathMLAnonymousBlock,
            "-moz-xul-anonymous-block" => MozXULAnonymousBlock,

            "-moz-hframeset-border" => MozHorizontalFramesetBorder,
            "-moz-vframeset-border" => MozVerticalFramesetBorder,

            "-moz-line-frame" => MozLineFrame,

            "-moz-button-content" => MozButtonContent,
            "-moz-buttonlabel" => MozButtonLabel,
            "-moz-cell-content" => MozCellContent,
            "-moz-dropdown-list" => MozDropdownList,
            "-moz-fieldset-content" => MozFieldsetContent,
            "-moz-frameset-blank" => MozFramesetBlank,
            "-moz-display-comboboxcontrol-frame" => MozDisplayComboboxControlFrame,
            "-moz-html-canvas-content" => MozHTMLCanvasContent,

            "-moz-inline-table" => MozInlineTable,
            "-moz-table" => MozTable,
            "-moz-table-cell" => MozTableCell,
            "-moz-table-column-group" => MozTableColumnGroup,
            "-moz-table-column" => MozTableColumn,
            "-moz-table-outer" => MozTableOuter,
            "-moz-table-row-group" => MozTableRowGroup,
            "-moz-table-row" => MozTableRow,

            "-moz-canvas" => MozCanvas,
            "-moz-pagebreak" => MozPageBreak,
            "-moz-page" => MozPage,
            "-moz-pagecontent" => MozPageContent,
            "-moz-page-sequence" => MozPageSequence,
            "-moz-scrolled-content" => MozScrolledContent,
            "-moz-scrolled-canvas" => MozScrolledCanvas,
            "-moz-scrolled-page-sequence" => MozScrolledPageSequence,
            "-moz-column-content" => MozColumnContent,
            "-moz-viewport" => MozViewport,
            "-moz-viewport-scroll" => MozViewportScroll,
            "-moz-anonymous-flex-item" => MozAnonymousFlexItem,
            "-moz-anonymous-grid-item" => MozAnonymousGridItem,
            "-moz-ruby" => MozRuby,
            "-moz-ruby-base" => MozRubyBase,
            "-moz-ruby-base-container" => MozRubyBaseContainer,
            "-moz-ruby-text" => MozRubyText,
            "-moz-ruby-text-container" => MozRubyTextContainer,
            "-moz-tree-column" => MozTreeColumn,
            "-moz-tree-row" => MozTreeRow,
            "-moz-tree-separator" => MozTreeSeparator,
            "-moz-tree-cell" => MozTreeCell,
            "-moz-tree-indentation" => MozTreeIndentation,
            "-moz-tree-line" => MozTreeLine,
            "-moz-tree-twisty" => MozTreeTwisty,
            "-moz-tree-image" => MozTreeImage,
            "-moz-tree-cell-text" => MozTreeCellText,
            "-moz-tree-checkbox" => MozTreeCheckbox,
            "-moz-tree-progressmeter" => MozTreeProgressMeter,
            "-moz-tree-drop-feedback" => MozTreeDropFeedback,
            "-moz-svg-marker-anon-child" => MozSVGMarkerAnonChild,
            "-moz-svg-outer-svg-anon-child" => MozSVGOuterSVGAnonChild,
            "-moz-svg-foreign-content" => MozSVGForeignContent,
            "-moz-svg-text" => MozSVGText,

            _ => return Err(())
        };

        Ok(pseudo_element)
    }
}

impl SelectorImplExt for GeckoSelectorImpl {
    type ComputedValues = GeckoComputedValues;

    #[inline]
    fn is_eagerly_cascaded_pseudo_element(pseudo: &PseudoElement) -> bool {
        match *pseudo {
            PseudoElement::Before |
            PseudoElement::After |
            PseudoElement::FirstLine => true,
            _ => false,
        }
    }

    #[inline]
    fn each_pseudo_element<F>(mut fun: F)
        where F: FnMut(PseudoElement) {
        fun(PseudoElement::Before);
        fun(PseudoElement::After);
        fun(PseudoElement::FirstLine);

        fun(PseudoElement::MozNonElement);
        fun(PseudoElement::MozAnonymousBlock);
        fun(PseudoElement::MozAnonymousPositionedBlock);
        fun(PseudoElement::MozMathMLAnonymousBlock);
        fun(PseudoElement::MozXULAnonymousBlock);

        fun(PseudoElement::MozHorizontalFramesetBorder);
        fun(PseudoElement::MozVerticalFramesetBorder);
        fun(PseudoElement::MozLineFrame);
        fun(PseudoElement::MozButtonContent);
        fun(PseudoElement::MozButtonLabel);
        fun(PseudoElement::MozCellContent);
        fun(PseudoElement::MozDropdownList);
        fun(PseudoElement::MozFieldsetContent);
        fun(PseudoElement::MozFramesetBlank);
        fun(PseudoElement::MozDisplayComboboxControlFrame);

        fun(PseudoElement::MozHTMLCanvasContent);
        fun(PseudoElement::MozInlineTable);
        fun(PseudoElement::MozTable);
        fun(PseudoElement::MozTableCell);
        fun(PseudoElement::MozTableColumnGroup);
        fun(PseudoElement::MozTableColumn);
        fun(PseudoElement::MozTableOuter);
        fun(PseudoElement::MozTableRowGroup);
        fun(PseudoElement::MozTableRow);

        fun(PseudoElement::MozCanvas);
        fun(PseudoElement::MozPageBreak);
        fun(PseudoElement::MozPage);
        fun(PseudoElement::MozPageContent);
        fun(PseudoElement::MozPageSequence);
        fun(PseudoElement::MozScrolledContent);
        fun(PseudoElement::MozScrolledCanvas);
        fun(PseudoElement::MozScrolledPageSequence);
        fun(PseudoElement::MozColumnContent);
        fun(PseudoElement::MozViewport);
        fun(PseudoElement::MozViewportScroll);
        fun(PseudoElement::MozAnonymousFlexItem);
        fun(PseudoElement::MozAnonymousGridItem);

        fun(PseudoElement::MozRuby);
        fun(PseudoElement::MozRubyBase);
        fun(PseudoElement::MozRubyBaseContainer);
        fun(PseudoElement::MozRubyText);
        fun(PseudoElement::MozRubyTextContainer);

        fun(PseudoElement::MozTreeColumn);
        fun(PseudoElement::MozTreeRow);
        fun(PseudoElement::MozTreeSeparator);
        fun(PseudoElement::MozTreeCell);
        fun(PseudoElement::MozTreeIndentation);
        fun(PseudoElement::MozTreeLine);
        fun(PseudoElement::MozTreeTwisty);
        fun(PseudoElement::MozTreeImage);
        fun(PseudoElement::MozTreeCellText);
        fun(PseudoElement::MozTreeCheckbox);
        fun(PseudoElement::MozTreeProgressMeter);
        fun(PseudoElement::MozTreeDropFeedback);

        fun(PseudoElement::MozSVGMarkerAnonChild);
        fun(PseudoElement::MozSVGOuterSVGAnonChild);
        fun(PseudoElement::MozSVGForeignContent);
        fun(PseudoElement::MozSVGText);
    }

    #[inline]
    fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
        pc.state_flag()
    }

    #[inline]
    fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet] {
        &[]
    }

    #[inline]
    fn get_quirks_mode_stylesheet() -> Option<&'static Stylesheet> {
        None
    }
}
<commit_msg>geckolib: Parse anon-box pseudo-elements just on UA stylesheets<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 properties::GeckoComputedValues;
use selectors::parser::{ParserContext, SelectorImpl};
use style;
use style::element_state::ElementState;
use style::selector_impl::SelectorImplExt;

pub type Stylist = style::selector_matching::Stylist<GeckoSelectorImpl>;
pub type Stylesheet = style::stylesheets::Stylesheet<GeckoSelectorImpl>;
pub type SharedStyleContext = style::context::SharedStyleContext<GeckoSelectorImpl>;
pub type PrivateStyleData = style::data::PrivateStyleData<GeckoSelectorImpl, GeckoComputedValues>;

pub struct GeckoSelectorImpl;

#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)]
pub enum PseudoElement {
    Before,
    After,
    FirstLine,
    // TODO: Probably a few more are missing here

    // https://mxr.mozilla.org/mozilla-central/source/layout/style/nsCSSAnonBoxList.h
    MozNonElement,
    MozAnonymousBlock,
    MozAnonymousPositionedBlock,
    MozMathMLAnonymousBlock,
    MozXULAnonymousBlock,

    MozHorizontalFramesetBorder,
    MozVerticalFramesetBorder,
    MozLineFrame,
    MozButtonContent,
    MozButtonLabel,
    MozCellContent,
    MozDropdownList,
    MozFieldsetContent,
    MozFramesetBlank,
    MozDisplayComboboxControlFrame,

    MozHTMLCanvasContent,
    MozInlineTable,
    MozTable,
    MozTableCell,
    MozTableColumnGroup,
    MozTableColumn,
    MozTableOuter,
    MozTableRowGroup,
    MozTableRow,

    MozCanvas,
    MozPageBreak,
    MozPage,
    MozPageContent,
    MozPageSequence,
    MozScrolledContent,
    MozScrolledCanvas,
    MozScrolledPageSequence,
    MozColumnContent,
    MozViewport,
    MozViewportScroll,
    MozAnonymousFlexItem,
    MozAnonymousGridItem,

    MozRuby,
    MozRubyBase,
    MozRubyBaseContainer,
    MozRubyText,
    MozRubyTextContainer,

    MozTreeColumn,
    MozTreeRow,
    MozTreeSeparator,
    MozTreeCell,
    MozTreeIndentation,
    MozTreeLine,
    MozTreeTwisty,
    MozTreeImage,
    MozTreeCellText,
    MozTreeCheckbox,
    MozTreeProgressMeter,
    MozTreeDropFeedback,

    MozSVGMarkerAnonChild,
    MozSVGOuterSVGAnonChild,
    MozSVGForeignContent,
    MozSVGText,
}

#[derive(Clone, Debug, PartialEq, Eq, HeapSizeOf, Hash)]
pub enum NonTSPseudoClass {
    AnyLink,
    Link,
    Visited,
    Active,
    Focus,
    Hover,
    Enabled,
    Disabled,
    Checked,
    Indeterminate,
    ReadWrite,
    ReadOnly,
}

impl NonTSPseudoClass {
    pub fn state_flag(&self) -> ElementState {
        use self::NonTSPseudoClass::*;
        use style::element_state::*;
        match *self {
            Active => IN_ACTIVE_STATE,
            Focus => IN_FOCUS_STATE,
            Hover => IN_HOVER_STATE,
            Enabled => IN_ENABLED_STATE,
            Disabled => IN_DISABLED_STATE,
            Checked => IN_CHECKED_STATE,
            Indeterminate => IN_INDETERMINATE_STATE,
            ReadOnly | ReadWrite => IN_READ_WRITE_STATE,

            AnyLink |
            Link |
            Visited => ElementState::empty(),
        }
    }
}

impl SelectorImpl for GeckoSelectorImpl {
    type PseudoElement = PseudoElement;
    type NonTSPseudoClass = NonTSPseudoClass;
    fn parse_non_ts_pseudo_class(_context: &ParserContext,
                                 name: &str) -> Result<NonTSPseudoClass, ()> {
        use self::NonTSPseudoClass::*;
        let pseudo_class = match_ignore_ascii_case! { name,
            "any-link" => AnyLink,
            "link" => Link,
            "visited" => Visited,
            "active" => Active,
            "focus" => Focus,
            "hover" => Hover,
            "enabled" => Enabled,
            "disabled" => Disabled,
            "checked" => Checked,
            "indeterminate" => Indeterminate,
            "read-write" => ReadWrite,
            "read-only" => ReadOnly,
            _ => return Err(())
        };

        Ok(pseudo_class)
    }

    fn parse_pseudo_element(context: &ParserContext,
                            name: &str) -> Result<PseudoElement, ()> {
        use self::PseudoElement::*;

        // The braces here are unfortunate, but they're needed for
        // match_ignore_ascii_case! to work as expected.
        match_ignore_ascii_case! { name,
            "before" => { return Ok(Before) },
            "after" => { return Ok(After) },
            "first-line" => { return Ok(FirstLine) },
            _ => {}
        }

        if !context.in_user_agent_stylesheet {
            return Err(())
        }

        Ok(match_ignore_ascii_case! { name,
            "-moz-non-element" => MozNonElement,

            "-moz-anonymous-block" => MozAnonymousBlock,
            "-moz-anonymous-positioned-block" => MozAnonymousPositionedBlock,
            "-moz-mathml-anonymous-block" => MozMathMLAnonymousBlock,
            "-moz-xul-anonymous-block" => MozXULAnonymousBlock,

            "-moz-hframeset-border" => MozHorizontalFramesetBorder,
            "-moz-vframeset-border" => MozVerticalFramesetBorder,

            "-moz-line-frame" => MozLineFrame,

            "-moz-button-content" => MozButtonContent,
            "-moz-buttonlabel" => MozButtonLabel,
            "-moz-cell-content" => MozCellContent,
            "-moz-dropdown-list" => MozDropdownList,
            "-moz-fieldset-content" => MozFieldsetContent,
            "-moz-frameset-blank" => MozFramesetBlank,
            "-moz-display-comboboxcontrol-frame" => MozDisplayComboboxControlFrame,
            "-moz-html-canvas-content" => MozHTMLCanvasContent,

            "-moz-inline-table" => MozInlineTable,
            "-moz-table" => MozTable,
            "-moz-table-cell" => MozTableCell,
            "-moz-table-column-group" => MozTableColumnGroup,
            "-moz-table-column" => MozTableColumn,
            "-moz-table-outer" => MozTableOuter,
            "-moz-table-row-group" => MozTableRowGroup,
            "-moz-table-row" => MozTableRow,

            "-moz-canvas" => MozCanvas,
            "-moz-pagebreak" => MozPageBreak,
            "-moz-page" => MozPage,
            "-moz-pagecontent" => MozPageContent,
            "-moz-page-sequence" => MozPageSequence,
            "-moz-scrolled-content" => MozScrolledContent,
            "-moz-scrolled-canvas" => MozScrolledCanvas,
            "-moz-scrolled-page-sequence" => MozScrolledPageSequence,
            "-moz-column-content" => MozColumnContent,
            "-moz-viewport" => MozViewport,
            "-moz-viewport-scroll" => MozViewportScroll,
            "-moz-anonymous-flex-item" => MozAnonymousFlexItem,
            "-moz-anonymous-grid-item" => MozAnonymousGridItem,
            "-moz-ruby" => MozRuby,
            "-moz-ruby-base" => MozRubyBase,
            "-moz-ruby-base-container" => MozRubyBaseContainer,
            "-moz-ruby-text" => MozRubyText,
            "-moz-ruby-text-container" => MozRubyTextContainer,
            "-moz-tree-column" => MozTreeColumn,
            "-moz-tree-row" => MozTreeRow,
            "-moz-tree-separator" => MozTreeSeparator,
            "-moz-tree-cell" => MozTreeCell,
            "-moz-tree-indentation" => MozTreeIndentation,
            "-moz-tree-line" => MozTreeLine,
            "-moz-tree-twisty" => MozTreeTwisty,
            "-moz-tree-image" => MozTreeImage,
            "-moz-tree-cell-text" => MozTreeCellText,
            "-moz-tree-checkbox" => MozTreeCheckbox,
            "-moz-tree-progressmeter" => MozTreeProgressMeter,
            "-moz-tree-drop-feedback" => MozTreeDropFeedback,
            "-moz-svg-marker-anon-child" => MozSVGMarkerAnonChild,
            "-moz-svg-outer-svg-anon-child" => MozSVGOuterSVGAnonChild,
            "-moz-svg-foreign-content" => MozSVGForeignContent,
            "-moz-svg-text" => MozSVGText,

            _ => return Err(())
        })
    }
}

impl SelectorImplExt for GeckoSelectorImpl {
    type ComputedValues = GeckoComputedValues;

    #[inline]
    fn is_eagerly_cascaded_pseudo_element(pseudo: &PseudoElement) -> bool {
        match *pseudo {
            PseudoElement::Before |
            PseudoElement::After |
            PseudoElement::FirstLine => true,
            _ => false,
        }
    }

    #[inline]
    fn each_pseudo_element<F>(mut fun: F)
        where F: FnMut(PseudoElement) {
        fun(PseudoElement::Before);
        fun(PseudoElement::After);
        fun(PseudoElement::FirstLine);

        fun(PseudoElement::MozNonElement);
        fun(PseudoElement::MozAnonymousBlock);
        fun(PseudoElement::MozAnonymousPositionedBlock);
        fun(PseudoElement::MozMathMLAnonymousBlock);
        fun(PseudoElement::MozXULAnonymousBlock);

        fun(PseudoElement::MozHorizontalFramesetBorder);
        fun(PseudoElement::MozVerticalFramesetBorder);
        fun(PseudoElement::MozLineFrame);
        fun(PseudoElement::MozButtonContent);
        fun(PseudoElement::MozButtonLabel);
        fun(PseudoElement::MozCellContent);
        fun(PseudoElement::MozDropdownList);
        fun(PseudoElement::MozFieldsetContent);
        fun(PseudoElement::MozFramesetBlank);
        fun(PseudoElement::MozDisplayComboboxControlFrame);

        fun(PseudoElement::MozHTMLCanvasContent);
        fun(PseudoElement::MozInlineTable);
        fun(PseudoElement::MozTable);
        fun(PseudoElement::MozTableCell);
        fun(PseudoElement::MozTableColumnGroup);
        fun(PseudoElement::MozTableColumn);
        fun(PseudoElement::MozTableOuter);
        fun(PseudoElement::MozTableRowGroup);
        fun(PseudoElement::MozTableRow);

        fun(PseudoElement::MozCanvas);
        fun(PseudoElement::MozPageBreak);
        fun(PseudoElement::MozPage);
        fun(PseudoElement::MozPageContent);
        fun(PseudoElement::MozPageSequence);
        fun(PseudoElement::MozScrolledContent);
        fun(PseudoElement::MozScrolledCanvas);
        fun(PseudoElement::MozScrolledPageSequence);
        fun(PseudoElement::MozColumnContent);
        fun(PseudoElement::MozViewport);
        fun(PseudoElement::MozViewportScroll);
        fun(PseudoElement::MozAnonymousFlexItem);
        fun(PseudoElement::MozAnonymousGridItem);

        fun(PseudoElement::MozRuby);
        fun(PseudoElement::MozRubyBase);
        fun(PseudoElement::MozRubyBaseContainer);
        fun(PseudoElement::MozRubyText);
        fun(PseudoElement::MozRubyTextContainer);

        fun(PseudoElement::MozTreeColumn);
        fun(PseudoElement::MozTreeRow);
        fun(PseudoElement::MozTreeSeparator);
        fun(PseudoElement::MozTreeCell);
        fun(PseudoElement::MozTreeIndentation);
        fun(PseudoElement::MozTreeLine);
        fun(PseudoElement::MozTreeTwisty);
        fun(PseudoElement::MozTreeImage);
        fun(PseudoElement::MozTreeCellText);
        fun(PseudoElement::MozTreeCheckbox);
        fun(PseudoElement::MozTreeProgressMeter);
        fun(PseudoElement::MozTreeDropFeedback);

        fun(PseudoElement::MozSVGMarkerAnonChild);
        fun(PseudoElement::MozSVGOuterSVGAnonChild);
        fun(PseudoElement::MozSVGForeignContent);
        fun(PseudoElement::MozSVGText);
    }

    #[inline]
    fn pseudo_class_state_flag(pc: &NonTSPseudoClass) -> ElementState {
        pc.state_flag()
    }

    #[inline]
    fn get_user_or_user_agent_stylesheets() -> &'static [Stylesheet] {
        &[]
    }

    #[inline]
    fn get_quirks_mode_stylesheet() -> Option<&'static Stylesheet> {
        None
    }
}
<|endoftext|>


<commit_before>extern crate gcc;

use std::env;
use std::fs;
use std::path::PathBuf;

fn main() {
    let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    fs::remove_dir_all(&out).unwrap();
    fs::create_dir(&out).unwrap();

    gcc::Config::new()
        .file("src/foo.c")
        .define("FOO", None)
        .define("BAR", Some("1"))
        .compile("libfoo.a");

    gcc::Config::new()
        .file("src/bar1.c")
        .file("src/bar2.c")
        .include("src/include")
        .compile("libbar.a");

    let target = std::env::var("TARGET").unwrap();
    let file = target.split("-").next().unwrap();
    let file = format!("src/{}.{}",
                       file,
                       if target.contains("msvc") { "asm" } else { "S" });
    gcc::Config::new()
        .file(file)
        .compile("libasm.a");

    gcc::Config::new()
        .file("src/baz.cpp")
        .cpp(true)
        .compile("libbaz.a");

    if target.contains("windows") {
        gcc::Config::new()
            .file("src/windows.c")
            .compile("libwindows.a");
    }

    // Test that the `windows_registry` module will set PATH by looking for
    // nmake which runs vanilla cl, and then also test it after we remove all
    // the relevant env vars from our own process.
    if target.contains("msvc") {
        let out = out.join("tmp");
        fs::create_dir(&out).unwrap();
        println!("nmake 1");
        let status = gcc::windows_registry::find(&target, "nmake.exe")
            .unwrap()
            .arg("/fsrc/NMakefile")
            .env("OUT_DIR", &out)
            .status()
            .unwrap();
        assert!(status.success());

        fs::remove_dir_all(&out).unwrap();
        fs::create_dir(&out).unwrap();

        env::remove_var("PATH");
        env::remove_var("VCINSTALLDIR");
        env::remove_var("INCLUDE");
        env::remove_var("LIB");
        println!("nmake 2");
        let status = gcc::windows_registry::find(&target, "nmake.exe")
            .unwrap()
            .arg("/fsrc/NMakefile")
            .env("OUT_DIR", &out)
            .status()
            .unwrap();
        assert!(status.success());
        println!("cargo:rustc-link-lib=msvc");
        println!("cargo:rustc-link-search={}", out.display());
    }

    // This tests whether we  can build a library but not link it to the main
    // crate.  The test module will do its own linking.
    gcc::Config::new()
        .cargo_metadata(false)
        .file("src/opt_linkage.c")
        .compile("libOptLinkage.a");

    let out = gcc::Config::new()
        .file("src/expand.c")
        .expand();
    let out = String::from_utf8(out).unwrap();
    assert!(out.contains("hello world"));
}
<commit_msg>Fix nmake tests<commit_after>extern crate gcc;

use std::env;
use std::fs;
use std::path::PathBuf;

fn main() {
    let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    fs::remove_dir_all(&out).unwrap();
    fs::create_dir(&out).unwrap();

    gcc::Config::new()
        .file("src/foo.c")
        .define("FOO", None)
        .define("BAR", Some("1"))
        .compile("libfoo.a");

    gcc::Config::new()
        .file("src/bar1.c")
        .file("src/bar2.c")
        .include("src/include")
        .compile("libbar.a");

    let target = std::env::var("TARGET").unwrap();
    let file = target.split("-").next().unwrap();
    let file = format!("src/{}.{}",
                       file,
                       if target.contains("msvc") { "asm" } else { "S" });
    gcc::Config::new()
        .file(file)
        .compile("libasm.a");

    gcc::Config::new()
        .file("src/baz.cpp")
        .cpp(true)
        .compile("libbaz.a");

    if target.contains("windows") {
        gcc::Config::new()
            .file("src/windows.c")
            .compile("libwindows.a");
    }

    // Test that the `windows_registry` module will set PATH by looking for
    // nmake which runs vanilla cl, and then also test it after we remove all
    // the relevant env vars from our own process.
    if target.contains("msvc") {
        let out = out.join("tmp");
        fs::create_dir(&out).unwrap();
        println!("nmake 1");
        let status = gcc::windows_registry::find(&target, "nmake.exe")
            .unwrap()
            .env_remove("MAKEFLAGS")
            .arg("/fsrc/NMakefile")
            .env("OUT_DIR", &out)
            .status()
            .unwrap();
        assert!(status.success());

        fs::remove_dir_all(&out).unwrap();
        fs::create_dir(&out).unwrap();

        env::remove_var("PATH");
        env::remove_var("VCINSTALLDIR");
        env::remove_var("INCLUDE");
        env::remove_var("LIB");
        println!("nmake 2");
        let status = gcc::windows_registry::find(&target, "nmake.exe")
            .unwrap()
            .env_remove("MAKEFLAGS")
            .arg("/fsrc/NMakefile")
            .env("OUT_DIR", &out)
            .status()
            .unwrap();
        assert!(status.success());
        println!("cargo:rustc-link-lib=msvc");
        println!("cargo:rustc-link-search={}", out.display());
    }

    // This tests whether we  can build a library but not link it to the main
    // crate.  The test module will do its own linking.
    gcc::Config::new()
        .cargo_metadata(false)
        .file("src/opt_linkage.c")
        .compile("libOptLinkage.a");

    let out = gcc::Config::new()
        .file("src/expand.c")
        .expand();
    let out = String::from_utf8(out).unwrap();
    assert!(out.contains("hello world"));
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::io;
use std::rc::{Rc, Weak};
use std::net::{Ipv4Addr, SocketAddr};
use std::time::Instant;
use log::LogLevel;
use mio::{Event, PollOpt, Ready, Token};
use mio::net::UdpSocket;

use super::binary;
use super::client::Client;
use super::connection::{self, Connection, ConnectionId};
use super::datagram_buffer::DatagramBuffer;
use super::ipv4_packet::{IPv4Packet, MAX_PACKET_LENGTH};
use super::packetizer::Packetizer;
use super::selector::Selector;

const TAG: &'static str = "UDPConnection";

pub const IDLE_TIMEOUT_SECONDS: u64 = 2 * 60;

pub struct UDPConnection {
    id: ConnectionId,
    client: Weak<RefCell<Client>>,
    socket: UdpSocket,
    token: Token,
    client_to_network: DatagramBuffer,
    network_to_client: Packetizer,
    closed: bool,
    idle_since: Instant,
}

impl UDPConnection {
    pub fn new(selector: &mut Selector, id: ConnectionId, client: Weak<RefCell<Client>>, reference_packet: &IPv4Packet) -> io::Result<Rc<RefCell<Self>>> {
        let socket = UDPConnection::create_socket(&id)?;
        let raw: &[u8] = reference_packet.raw();
        let ipv4_header = reference_packet.ipv4_header().clone();
        let transport_header = reference_packet.transport_header().as_ref().unwrap().clone();
        let rc = Rc::new(RefCell::new(Self {
            id: id,
            client: client,
            socket: socket,
            token: Token(0), // default value, will be set afterwards
            client_to_network: DatagramBuffer::new(4 * MAX_PACKET_LENGTH),
            network_to_client: Packetizer::new(raw, ipv4_header, transport_header),
            closed: false,
            idle_since: Instant::now(),
        }));

        {
            let rc_clone = rc.clone();
            let handler = move |selector: &mut Selector, ready| {
                let mut self_ref = rc_clone.borrow_mut();
                self_ref.on_ready(selector, ready);
            };
            let mut self_ref = rc.borrow_mut();
            let token = selector.register(&self_ref.socket, handler, Ready::readable(), PollOpt::level())?;
            self_ref.token = token;
        }
        Ok(rc)
    }

    fn create_socket(id: &ConnectionId) -> io::Result<UdpSocket> {
        let autobind_addr = SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 0);
        let udp_socket = UdpSocket::bind(&autobind_addr)?;
        let rewritten_destination = connection::rewritten_destination(id.destination_ip(), id.destination_port()).into();
        udp_socket.connect(rewritten_destination)?;
        Ok(udp_socket)
    }

    fn close(&mut self, selector: &mut Selector) {
        self.closed = true;
        self.disconnect(selector);

        // route is embedded in router which is embedded in client: the client necessarily exists
        let client_rc = self.client.upgrade().expect("expected client not found");
        let mut client = client_rc.borrow_mut();
        client.router().remove(&self.id);
    }

    fn process_send(&mut self, selector: &mut Selector) {
        if let Err(err) = self.write() {
            error!(target: TAG, "{} Cannot write: {}", self.id, err);
            self.close(selector);
        }
    }

    fn process_receive(&mut self, selector: &mut Selector) {
        if let Err(err) = self.read(selector) {
            error!(target: TAG, "{} Cannot read: {}", self.id, err);
            self.close(selector);
        }
    }

    fn read(&mut self, selector: &mut Selector) -> io::Result<()> {
        let ipv4_packet = self.network_to_client.packetize(&mut self.socket)?;
        let client_rc = self.client.upgrade().expect("expected client not found");
        match client_rc.borrow_mut().send_to_client(selector, &ipv4_packet) {
            Ok(_) => {
                debug!(target: TAG, "{} Packet ({} bytes) sent to client", self.id, ipv4_packet.length());
                if log_enabled!(target: TAG, LogLevel::Trace) {
                    binary::to_string(ipv4_packet.raw());
                }
            },
            Err(_) => warn!(target: TAG, "{} Cannot send to client, drop packet", self.id),
        }
        Ok(())
    }

    fn write(&mut self) -> io::Result<()> {
        self.client_to_network.write_to(&mut self.socket)?;
        Ok(())
    }

    fn update_interests(&mut self, selector: &mut Selector) {
        let ready = if self.client_to_network.is_empty() {
            Ready::readable()
        } else {
            Ready::readable() | Ready::writable()
        };
        selector.reregister(&self.socket, self.token, ready, PollOpt::level()).expect("Cannot register on poll");
    }

    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        assert!(!self.closed);
        self.touch();
        let ready = event.readiness();
        if ready.is_writable() {
            self.process_send(selector);
        }
        if !self.closed && ready.is_readable() {
            self.process_receive(selector);
        }
        if !self.closed {
            self.update_interests(selector);
        }
    }

    fn touch(&mut self) {
        self.idle_since = Instant::now();
    }
}

impl Connection for UDPConnection {
    fn id(&self) -> &ConnectionId {
        &self.id
    }

    fn send_to_network(&mut self, selector: &mut Selector, ipv4_packet: &IPv4Packet) {
        match self.client_to_network.read_from(ipv4_packet.payload()) {
            Ok(_) => {
                self.update_interests(selector);
            },
            Err(err) => warn!(target: TAG, "{} Cannot send to network, drop packet: {}", self.id, err),
        }
    }

    fn disconnect(&mut self, selector: &mut Selector) {
        info!(target: TAG, "{} Close", self.id);
        selector.deregister(&self.socket, self.token).unwrap();
        // socket will be closed by RAII
    }

    fn is_expired(&self) -> bool {
        self.idle_since.elapsed().as_secs() > IDLE_TIMEOUT_SECONDS
    }
}
<commit_msg>Improve style<commit_after>use std::cell::RefCell;
use std::io;
use std::net::{Ipv4Addr, SocketAddr};
use std::rc::{Rc, Weak};
use std::time::Instant;
use log::LogLevel;
use mio::{Event, PollOpt, Ready, Token};
use mio::net::UdpSocket;

use super::binary;
use super::client::Client;
use super::connection::{self, Connection, ConnectionId};
use super::datagram_buffer::DatagramBuffer;
use super::ipv4_packet::{IPv4Packet, MAX_PACKET_LENGTH};
use super::packetizer::Packetizer;
use super::selector::Selector;

const TAG: &'static str = "UDPConnection";

pub const IDLE_TIMEOUT_SECONDS: u64 = 2 * 60;

pub struct UDPConnection {
    id: ConnectionId,
    client: Weak<RefCell<Client>>,
    socket: UdpSocket,
    token: Token,
    client_to_network: DatagramBuffer,
    network_to_client: Packetizer,
    closed: bool,
    idle_since: Instant,
}

impl UDPConnection {
    pub fn new(selector: &mut Selector, id: ConnectionId, client: Weak<RefCell<Client>>, reference_packet: &IPv4Packet) -> io::Result<Rc<RefCell<Self>>> {
        let socket = UDPConnection::create_socket(&id)?;
        let raw = reference_packet.raw();
        let ipv4_header = reference_packet.ipv4_header().clone();
        let transport_header = reference_packet.transport_header().as_ref().unwrap().clone();
        let rc = Rc::new(RefCell::new(Self {
            id: id,
            client: client,
            socket: socket,
            token: Token(0), // default value, will be set afterwards
            client_to_network: DatagramBuffer::new(4 * MAX_PACKET_LENGTH),
            network_to_client: Packetizer::new(raw, ipv4_header, transport_header),
            closed: false,
            idle_since: Instant::now(),
        }));

        {
            let rc_clone = rc.clone();
            let handler = move |selector: &mut Selector, ready| {
                let mut self_ref = rc_clone.borrow_mut();
                self_ref.on_ready(selector, ready);
            };
            let mut self_ref = rc.borrow_mut();
            let token = selector.register(&self_ref.socket, handler, Ready::readable(), PollOpt::level())?;
            self_ref.token = token;
        }
        Ok(rc)
    }

    fn create_socket(id: &ConnectionId) -> io::Result<UdpSocket> {
        let autobind_addr = SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 0);
        let udp_socket = UdpSocket::bind(&autobind_addr)?;
        let rewritten_destination = connection::rewritten_destination(id.destination_ip(), id.destination_port()).into();
        udp_socket.connect(rewritten_destination)?;
        Ok(udp_socket)
    }

    fn close(&mut self, selector: &mut Selector) {
        self.closed = true;
        self.disconnect(selector);

        // route is embedded in router which is embedded in client: the client necessarily exists
        let client_rc = self.client.upgrade().expect("expected client not found");
        let mut client = client_rc.borrow_mut();
        client.router().remove(&self.id);
    }

    fn process_send(&mut self, selector: &mut Selector) {
        if let Err(err) = self.write() {
            error!(target: TAG, "{} Cannot write: {}", self.id, err);
            self.close(selector);
        }
    }

    fn process_receive(&mut self, selector: &mut Selector) {
        if let Err(err) = self.read(selector) {
            error!(target: TAG, "{} Cannot read: {}", self.id, err);
            self.close(selector);
        }
    }

    fn read(&mut self, selector: &mut Selector) -> io::Result<()> {
        let ipv4_packet = self.network_to_client.packetize(&mut self.socket)?;
        let client_rc = self.client.upgrade().expect("expected client not found");
        match client_rc.borrow_mut().send_to_client(selector, &ipv4_packet) {
            Ok(_) => {
                debug!(target: TAG, "{} Packet ({} bytes) sent to client", self.id, ipv4_packet.length());
                if log_enabled!(target: TAG, LogLevel::Trace) {
                    binary::to_string(ipv4_packet.raw());
                }
            },
            Err(_) => warn!(target: TAG, "{} Cannot send to client, drop packet", self.id),
        }
        Ok(())
    }

    fn write(&mut self) -> io::Result<()> {
        self.client_to_network.write_to(&mut self.socket)?;
        Ok(())
    }

    fn update_interests(&mut self, selector: &mut Selector) {
        let ready = if self.client_to_network.is_empty() {
            Ready::readable()
        } else {
            Ready::readable() | Ready::writable()
        };
        selector.reregister(&self.socket, self.token, ready, PollOpt::level()).expect("Cannot register on poll");
    }

    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        assert!(!self.closed);
        self.touch();
        let ready = event.readiness();
        if ready.is_writable() {
            self.process_send(selector);
        }
        if !self.closed && ready.is_readable() {
            self.process_receive(selector);
        }
        if !self.closed {
            self.update_interests(selector);
        }
    }

    fn touch(&mut self) {
        self.idle_since = Instant::now();
    }
}

impl Connection for UDPConnection {
    fn id(&self) -> &ConnectionId {
        &self.id
    }

    fn send_to_network(&mut self, selector: &mut Selector, ipv4_packet: &IPv4Packet) {
        match self.client_to_network.read_from(ipv4_packet.payload()) {
            Ok(_) => {
                self.update_interests(selector);
            },
            Err(err) => warn!(target: TAG, "{} Cannot send to network, drop packet: {}", self.id, err),
        }
    }

    fn disconnect(&mut self, selector: &mut Selector) {
        info!(target: TAG, "{} Close", self.id);
        selector.deregister(&self.socket, self.token).unwrap();
        // socket will be closed by RAII
    }

    fn is_expired(&self) -> bool {
        self.idle_since.elapsed().as_secs() > IDLE_TIMEOUT_SECONDS
    }
}
<|endoftext|>


<commit_before>use std::io::Read;

use itertools::Itertools;

use crate::common::ordered;

fn compute_cumulative<'a, I, It>(it: I) -> Vec<usize>
where
    I: IntoIterator<IntoIter = It>,
    It: Iterator<Item = &'a (usize, usize)> + ExactSizeIterator,
{
    let mut it = it.into_iter().copied();
    let mut costs = Vec::with_capacity(it.len());
    costs.push(0);

    let (mut population, mut last_pos) = it.next().unwrap();
    let mut last_cost = 0;

    for (number, pos) in it {
        let (first, last) = ordered(last_pos, pos);
        let new_cost = last_cost + population * (last - first);

        population += number;
        last_pos = pos;
        last_cost = new_cost;

        costs.push(new_cost);
    }

    costs
}

fn read_input(input: &mut dyn Read) -> Vec<(usize, usize)> {
    let mut buf = String::new();
    input.read_to_string(&mut buf).unwrap();

    let mut crabs: Vec<usize> = buf
        .trim_end()
        .split(',')
        .map(|s| s.parse().unwrap())
        .collect();

    crabs.sort_unstable();

    crabs.into_iter().dedup_with_count().collect()
}

pub fn part1(input: &mut dyn Read) -> String {
    let crabs = read_input(input);

    let forwards_costs = compute_cumulative(&crabs);
    let backwards_costs = compute_cumulative(crabs.iter().rev());

    // Note: the optimal position can be proven to be one of the original positions.
    ternary_search(0, forwards_costs.len() - 1, |idx| {
        forwards_costs[idx] + backwards_costs[backwards_costs.len() - 1 - idx]
    })
    .to_string()
}

pub fn sum_until(end: usize) -> usize {
    (end * (1 + end)) / 2
}

fn cost_at(pos: usize, groups: &[(usize, usize)]) -> usize {
    groups
        .iter()
        .map(|&(number, new_pos)| {
            let (first, last) = ordered(pos, new_pos);

            number * sum_until(last - first)
        })
        .sum()
}

fn ternary_search(mut min: usize, mut max: usize, callback: impl Fn(usize) -> usize) -> usize {
    while max - min > 6 {
        let mid1 = min + (max - min) / 3;
        let mid2 = max - (max - min) / 3;

        let cost1 = callback(mid1);
        let cost2 = callback(mid2);

        if cost1 < cost2 {
            max = mid2 - 1
        } else {
            min = mid1 + 1
        }
    }

    // Ternary search isn't effective at such small intervals so we iterate the remaining part
    (min..=max).map(callback).min().unwrap()
}

pub fn part2(input: &mut dyn Read) -> String {
    let groups = read_input(input);

    let min = groups.first().unwrap().1;
    let max = groups.last().unwrap().1;

    ternary_search(min, max, |pos| cost_at(pos, &groups)).to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = &*b"16,1,2,0,4,2,7,1,2,14";

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 37);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 168);
    }

    #[test]
    fn test_maths() {
        assert_eq!(sum_until(1), 1);
        assert_eq!(sum_until(2), 3);
        assert_eq!(sum_until(3), 6);
        assert_eq!(sum_until(4), 10);
    }
}
<commit_msg>Just use the median, obviously<commit_after>use std::io::Read;

use itertools::Itertools;

use crate::common::ordered;

fn read_input(input: &mut dyn Read) -> Vec<usize> {
    let mut buf = String::new();
    input.read_to_string(&mut buf).unwrap();

    let mut crabs: Vec<usize> = buf
        .trim_end()
        .split(',')
        .map(|s| s.parse().unwrap())
        .collect();

    crabs.sort_unstable();

    crabs
}

fn cost_at(pos: usize, crabs: &[usize]) -> usize {
    crabs
        .iter()
        .map(|&crab_pos| {
            if crab_pos > pos {
                crab_pos - pos
            } else {
                pos - crab_pos
            }
        })
        .sum()
}

pub fn part1(input: &mut dyn Read) -> String {
    let crabs = read_input(input);

    let median = crabs[crabs.len() / 2 + (crabs.len() % 2)];

    cost_at(median, &crabs).to_string()
}

pub fn sum_until(end: usize) -> usize {
    (end * (1 + end)) / 2
}

fn cost_at2(pos: usize, groups: &[(usize, usize)]) -> usize {
    groups
        .iter()
        .map(|&(number, new_pos)| {
            let (first, last) = ordered(pos, new_pos);

            number * sum_until(last - first)
        })
        .sum()
}

fn ternary_search(mut min: usize, mut max: usize, callback: impl Fn(usize) -> usize) -> usize {
    while max - min > 6 {
        let mid1 = min + (max - min) / 3;
        let mid2 = max - (max - min) / 3;

        let cost1 = callback(mid1);
        let cost2 = callback(mid2);

        if cost1 < cost2 {
            max = mid2 - 1
        } else {
            min = mid1 + 1
        }
    }

    // Ternary search isn't effective at such small intervals so we iterate the remaining part
    (min..=max).map(callback).min().unwrap()
}

pub fn part2(input: &mut dyn Read) -> String {
    let groups: Vec<_> = read_input(input).into_iter().dedup_with_count().collect();

    let min = groups.first().unwrap().1;
    let max = groups.last().unwrap().1;

    ternary_search(min, max, |pos| cost_at2(pos, &groups)).to_string()
}

#[cfg(test)]
mod tests {
    use crate::test_implementation;

    use super::*;

    const SAMPLE: &[u8] = &*b"16,1,2,0,4,2,7,1,2,14";

    #[test]
    fn sample_part1() {
        test_implementation(part1, SAMPLE, 37);
    }

    #[test]
    fn sample_part2() {
        test_implementation(part2, SAMPLE, 168);
    }

    #[test]
    fn test_maths() {
        assert_eq!(sum_until(1), 1);
        assert_eq!(sum_until(2), 3);
        assert_eq!(sum_until(3), 6);
        assert_eq!(sum_until(4), 10);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

#[test]
fn base() {
    info!("hello");
    info!("hello",);
}

#[test]
fn with_args() {
    info!("hello {}", "cats");
    info!("hello {}", "cats",);
    info!("hello {}", "cats",);
}

#[test]
fn kv() {
    info!("hello {}", "cats", {
        cat_1: "chashu",
        cat_2: "nori",
    });
}

#[test]
fn kv_interpolated_ident_expr() {
    info!("hello {value}", value = "cats", {
        cat_1: "chashu",
        cat_2: "nori",
    });
}
<commit_msg>better macro names<commit_after>#[macro_use]
extern crate log;

#[test]
fn base() {
    info!("hello");
    info!("hello",);
}

#[test]
fn with_args() {
    info!("hello {}", "cats");
    info!("hello {}", "cats",);
    info!("hello {}", "cats",);
}

#[test]
fn named_arg() {
    info!("hello {value}", value = "cats");
}

#[test]
fn kv() {
    info!("hello {}", "cats", {
        cat_1: "chashu",
        cat_2: "nori",
    });
}

#[test]
fn kv_and_named_arg() {
    info!("hello {value}", value = "cats", {
        cat_1: "chashu",
        cat_2: "nori",
    });
}
<|endoftext|>