<commit_before>use serde::Deserialize;
use serde_json as json;

use std::fs::File;
use std::io::{self, Read};
use std::path::Path;

use alacritty_terminal::ansi;
use alacritty_terminal::clipboard::Clipboard;
use alacritty_terminal::config::MockConfig;
use alacritty_terminal::event::{Event, EventListener};
use alacritty_terminal::index::Column;
use alacritty_terminal::term::cell::Cell;
use alacritty_terminal::term::SizeInfo;
use alacritty_terminal::Grid;
use alacritty_terminal::Term;

macro_rules! ref_tests {
    ($($name:ident)*) => {
        $(
            #[test]
            fn $name() {
                let test_dir = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/ref"));
                let test_path = test_dir.join(stringify!($name));
                ref_test(&test_path);
            }
        )*
    }
}

ref_tests! {
    csi_rep
    fish_cc
    indexed_256_colors
    issue_855
    ll
    newline_with_cursor_beyond_scroll_region
    tab_rendering
    tmux_git_log
    tmux_htop
    vim_24bitcolors_bce
    vim_large_window_scroll
    vim_simple_edit
    vttest_cursor_movement_1
    vttest_insert
    vttest_origin_mode_1
    vttest_origin_mode_2
    vttest_scroll
    vttest_tab_clear_set
    zsh_tab_completion
    history
    grid_reset
    row_reset
    zerowidth
    selective_erasure
    colored_reset
    delete_lines
    delete_chars_reset
    alt_reset
    deccolm_reset
    decaln_reset
    insert_blank_reset
    erase_chars_reset
    scroll_up_reset
    clear_underline
}

fn read_u8<P>(path: P) -> Vec<u8>
where
    P: AsRef<Path>,
{
    let mut res = Vec::new();
    File::open(path.as_ref()).unwrap().read_to_end(&mut res).unwrap();

    res
}

fn read_string<P>(path: P) -> Result<String, ::std::io::Error>
where
    P: AsRef<Path>,
{
    let mut res = String::new();
    File::open(path.as_ref()).and_then(|mut f| f.read_to_string(&mut res))?;

    Ok(res)
}

#[derive(Deserialize, Default)]
struct RefConfig {
    history_size: u32,
}

struct Mock;
impl EventListener for Mock {
    fn send_event(&self, _event: Event) {}
}

fn ref_test(dir: &Path) {
    let recording = read_u8(dir.join("alacritty.recording"));
    let serialized_size = read_string(dir.join("size.json")).unwrap();
    let serialized_grid = read_string(dir.join("grid.json")).unwrap();
    let serialized_cfg = read_string(dir.join("config.json")).unwrap();

    let size: SizeInfo = json::from_str(&serialized_size).unwrap();
    let grid: Grid<Cell> = json::from_str(&serialized_grid).unwrap();
    let ref_config: RefConfig = json::from_str(&serialized_cfg).unwrap();

    let mut config = MockConfig::default();
    config.scrolling.set_history(ref_config.history_size);

    let mut terminal = Term::new(&config, &size, Clipboard::new_nop(), Mock);
    let mut parser = ansi::Processor::new();

    for byte in recording {
        parser.advance(&mut terminal, byte, &mut io::sink());
    }

    // Truncate invisible lines from the grid
    let mut term_grid = terminal.grid().clone();
    term_grid.initialize_all(&Cell::default());
    term_grid.truncate();

    if grid != term_grid {
        for i in 0..grid.len() {
            for j in 0..grid.num_cols().0 {
                let cell = term_grid[i][Column(j)];
                let original_cell = grid[i][Column(j)];
                if original_cell != cell {
                    println!(
                        "[{i}][{j}] {original:?} => {now:?}",
                        i = i,
                        j = j,
                        original = original_cell,
                        now = cell,
                    );
                }
            }
        }

        panic!("Ref test failed; grid doesn't match");
    }

    assert_eq!(grid, term_grid);
}
<commit_msg>Remove std::fs::read_to_string reimplementation from tests<commit_after>use serde::Deserialize;
use serde_json as json;

use std::fs::{read_to_string, File};
use std::io::{self, Read};
use std::path::Path;

use alacritty_terminal::ansi;
use alacritty_terminal::clipboard::Clipboard;
use alacritty_terminal::config::MockConfig;
use alacritty_terminal::event::{Event, EventListener};
use alacritty_terminal::index::Column;
use alacritty_terminal::term::cell::Cell;
use alacritty_terminal::term::SizeInfo;
use alacritty_terminal::Grid;
use alacritty_terminal::Term;

macro_rules! ref_tests {
    ($($name:ident)*) => {
        $(
            #[test]
            fn $name() {
                let test_dir = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/ref"));
                let test_path = test_dir.join(stringify!($name));
                ref_test(&test_path);
            }
        )*
    }
}

ref_tests! {
    csi_rep
    fish_cc
    indexed_256_colors
    issue_855
    ll
    newline_with_cursor_beyond_scroll_region
    tab_rendering
    tmux_git_log
    tmux_htop
    vim_24bitcolors_bce
    vim_large_window_scroll
    vim_simple_edit
    vttest_cursor_movement_1
    vttest_insert
    vttest_origin_mode_1
    vttest_origin_mode_2
    vttest_scroll
    vttest_tab_clear_set
    zsh_tab_completion
    history
    grid_reset
    row_reset
    zerowidth
    selective_erasure
    colored_reset
    delete_lines
    delete_chars_reset
    alt_reset
    deccolm_reset
    decaln_reset
    insert_blank_reset
    erase_chars_reset
    scroll_up_reset
    clear_underline
}

fn read_u8<P>(path: P) -> Vec<u8>
where
    P: AsRef<Path>,
{
    let mut res = Vec::new();
    File::open(path.as_ref()).unwrap().read_to_end(&mut res).unwrap();

    res
}

#[derive(Deserialize, Default)]
struct RefConfig {
    history_size: u32,
}

struct Mock;
impl EventListener for Mock {
    fn send_event(&self, _event: Event) {}
}

fn ref_test(dir: &Path) {
    let recording = read_u8(dir.join("alacritty.recording"));
    let serialized_size = read_to_string(dir.join("size.json")).unwrap();
    let serialized_grid = read_to_string(dir.join("grid.json")).unwrap();
    let serialized_cfg = read_to_string(dir.join("config.json")).unwrap();

    let size: SizeInfo = json::from_str(&serialized_size).unwrap();
    let grid: Grid<Cell> = json::from_str(&serialized_grid).unwrap();
    let ref_config: RefConfig = json::from_str(&serialized_cfg).unwrap();

    let mut config = MockConfig::default();
    config.scrolling.set_history(ref_config.history_size);

    let mut terminal = Term::new(&config, &size, Clipboard::new_nop(), Mock);
    let mut parser = ansi::Processor::new();

    for byte in recording {
        parser.advance(&mut terminal, byte, &mut io::sink());
    }

    // Truncate invisible lines from the grid
    let mut term_grid = terminal.grid().clone();
    term_grid.initialize_all(&Cell::default());
    term_grid.truncate();

    if grid != term_grid {
        for i in 0..grid.len() {
            for j in 0..grid.num_cols().0 {
                let cell = term_grid[i][Column(j)];
                let original_cell = grid[i][Column(j)];
                if original_cell != cell {
                    println!(
                        "[{i}][{j}] {original:?} => {now:?}",
                        i = i,
                        j = j,
                        original = original_cell,
                        now = cell,
                    );
                }
            }
        }

        panic!("Ref test failed; grid doesn't match");
    }

    assert_eq!(grid, term_grid);
}
<|endoftext|>


<commit_before>#![allow(unused_mut, unused_variables)]

use {Result, Tape, Value, Walue};
use glyph_positioning::{
    BaseSet,
    LigatureSet,
    Mark1Set,
    Mark2Set,
    Pair,
    PairSet,
    Passage,
    Single,
    SingleFlags,
};
use layout::{Class, Coverage};

/// A table.
#[derive(Clone, Debug)]
pub enum Table {
    SingleAdjustment(SingleAdjustment),
    PairAdjustment(PairAdjustment),
    CursiveAttachment(CursiveAttachment),
    MarkToBaseAttachment(MarkToBaseAttachment),
    MarkToLigatureAttachment(MarkToLigatureAttachment),
    MarkToMarkAttachment(MarkToMarkAttachment),
    ContextPositioning(ContextPositioning),
    ChainContextPositioning(ChainContextPositioning),
    ExtensionPositioning(ExtensionPositioning),
}

/// A table for adjusting single glyphs.
#[derive(Clone, Debug)]
pub enum SingleAdjustment {
    /// Format 1.
    Format1(SingleAdjustment1),
    /// Format 2.
    Format2(SingleAdjustment2),
}

table! {
    @position
    #[doc = "A table for adjusting single glyphs in format 1."]
    pub SingleAdjustment1 { // SinglePosFormat1
        format          (u16        ) = { 1 }, // PosFormat
        coverage_offset (u16        ), // Coverage
        value_flags     (SingleFlags), // ValueFormat

        value (Single) |this, tape, position| { // Value
            tape.take_given((position, this.value_flags))
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },
    }
}

table! {
    @position
    #[doc = "A table for adjusting single glyphs in format 2."]
    pub SingleAdjustment2 { // SinglePosFormat2
        format          (u16        ) = { 2 }, // PosFormat
        coverage_offset (u16        ), // Coverage
        value_flags     (SingleFlags), // ValueFormat
        value_count     (u16        ), // ValueCount

        values (Vec<Single>) |this, tape, position| { // Value
            let mut values = Vec::with_capacity(this.value_count as usize);
            for i in 0..(this.value_count as usize) {
                values.push(try!(tape.take_given((position, this.value_flags))));
            }
            Ok(values)
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },
    }
}

/// A table for adjusting pairs of glyphs.
#[derive(Clone, Debug)]
pub enum PairAdjustment {
    /// Format 1.
    Format1(PairAdjustment1),
    /// Format 2.
    Format2(PairAdjustment2),
}

table! {
    @position
    #[doc = "A table for adjusting pairs of glyphs in format 1."]
    pub PairAdjustment1 { // PairPosFormat1
        format          (u16        ) = { 1 }, // PosFormat
        coverage_offset (u16        ), // Coverage
        value1_flags    (SingleFlags), // ValueFormat1
        value2_flags    (SingleFlags), // ValueFormat2
        pair_set_count  (u16        ), // PairSetCount

        pair_set_offsets (Vec<u16>) |this, tape, position| { // PairSetOffset
            tape.take_given(this.pair_set_count as usize)
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },

        pair_sets (Vec<PairSet>) |this, tape, position| {
            jump_take_given!(tape, position, this.pair_set_count, this.pair_set_offsets,
                             (position, this.value1_flags, this.value2_flags))
        },
    }
}

table! {
    @position
    #[doc = "A table for adjusting pairs of glyphs in format 2."]
    pub PairAdjustment2 { // PairPosFormat2
        format          (u16        ) = { 2 }, // PosFormat
        coverage_offset (u16        ), // Coverage
        value1_flags    (SingleFlags), // ValueFormat1
        value2_flags    (SingleFlags), // ValueFormat2
        class1_offset   (u16        ), // ClassDef1
        class2_offset   (u16        ), // ClassDef2
        class1_count    (u16        ), // Class1Count
        class2_count    (u16        ), // Class2Count

        pair_sets (Vec<Vec<Pair>>) |this, tape, position| { // Class1Record
            let mut values = Vec::with_capacity(this.class1_count as usize);
            for i in 0..(this.class1_count as usize) {
                let mut records = Vec::with_capacity(this.class2_count as usize);
                for j in 0..(this.class2_count as usize) {
                    records.push(try!(tape.take_given((position, this.value1_flags,
                                                       this.value2_flags))));
                }
                values.push(records);
            }
            Ok(values)
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },

        class1 (Class) |this, tape, position| {
            jump_take!(tape, position, this.class1_offset)
        },

        class2 (Class) |this, tape, position| {
            jump_take!(tape, position, this.class2_offset)
        },
    }
}

table! {
    @position
    #[doc = "A table for attaching cursive glyphs."]
    pub CursiveAttachment { // CursivePosFormat1
        format          (u16) = { 1 }, // PosFormat
        coverage_offset (u16), // Coverage
        passage_count   (u16), // EntryExitCount

        passages (Vec<Passage>) |this, tape, position| { // EntryExitRecord
            let mut values = Vec::with_capacity(this.passage_count as usize);
            for i in 0..(this.passage_count as usize) {
                values.push(try!(tape.take_given(position)));
            }
            Ok(values)
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },
    }
}

table! {
    @position
    #[doc = "A table for attaching combining marks to base glyphs."]
    pub MarkToBaseAttachment { // MarkBasePosFormat1
        format               (u16) = { 1 }, // PosFormat
        mark_coverage_offset (u16), // MarkCoverage
        base_coverage_offset (u16), // BaseCoverage
        class_count          (u16), // ClassCount
        mark_set_offset      (u16), // MarkArray
        base_set_offset      (u16), // BaseArray

        mark_coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.mark_coverage_offset)
        },

        base_coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.base_coverage_offset)
        },

        mark_set (Mark1Set) |this, tape, position| {
            jump_take!(tape, position, this.mark_set_offset)
        },

        base_set (BaseSet) |this, tape, position| {
            jump_take_given!(tape, position, this.base_set_offset, this.class_count)
        },
    }
}

table! {
    @position
    #[doc = "A table for attaching combining marks to ligatures."]
    pub MarkToLigatureAttachment { // MarkLigPosFormat1
        format                   (u16) = { 1 }, // PosFormat
        mark_coverage_offset     (u16), // MarkCoverage
        ligature_coverage_offset (u16), // LigatureCoverage
        class_count              (u16), // ClassCount
        mark_set_offset          (u16), // MarkArray
        ligature_set_offset      (u16), // LigatureArray

        mark_coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.mark_coverage_offset)
        },

        ligature_coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.ligature_coverage_offset)
        },

        mark_set (Mark1Set) |this, tape, position| {
            jump_take!(tape, position, this.mark_set_offset)
        },

        ligature_set (LigatureSet) |this, tape, position| {
            jump_take_given!(tape, position, this.ligature_set_offset, this.class_count)
        },
    }
}

table! {
    @position
    #[doc = "A table for attaching combining marks to other marks."]
    pub MarkToMarkAttachment { // MarkMarkPosFormat1
        format                (u16) = { 1 }, // PosFormat
        mark1_coverage_offset (u16), // Mark1Coverage
        mark2_coverage_offset (u16), // Mark2Coverage
        class_count           (u16), // ClassCount
        mark1_set_offset      (u16), // Mark1Array
        mark2_set_offset      (u16), // Mark2Array

        mark1_coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.mark1_coverage_offset)
        },

        mark2_coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.mark2_coverage_offset)
        },

        mark1_set (Mark1Set) |this, tape, position| {
            jump_take!(tape, position, this.mark1_set_offset)
        },

        mark2_set (Mark2Set) |this, tape, position| {
            jump_take_given!(tape, position, this.mark2_set_offset, this.class_count)
        },
    }
}

table! {
    #[doc = "A table for positioning glyphs in a context."]
    pub ContextPositioning {
    }
}

table! {
    #[doc = "A table for positioning glyphs in a chaining context."]
    pub ChainContextPositioning {
    }
}

table! {
    #[doc = "A table for other types of positioning."]
    pub ExtensionPositioning {
    }
}

impl Walue<u16> for Table {
    fn read<T: Tape>(tape: &mut T, kind: u16) -> Result<Self> {
        Ok(match kind {
            1 => Table::SingleAdjustment(try!(tape.take())),
            2 => Table::PairAdjustment(try!(tape.take())),
            3 => Table::CursiveAttachment(try!(tape.take())),
            4 => Table::MarkToBaseAttachment(try!(tape.take())),
            5 => Table::MarkToLigatureAttachment(try!(tape.take())),
            6 => Table::MarkToMarkAttachment(try!(tape.take())),
            7 => Table::ContextPositioning(try!(tape.take())),
            8 => Table::ChainContextPositioning(try!(tape.take())),
            9 => Table::ExtensionPositioning(try!(tape.take())),
            _ => raise!("found an unknown glyph-positioning type"),
        })
    }
}

impl Value for SingleAdjustment {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        Ok(match try!(tape.peek::<u16>()) {
            1 => SingleAdjustment::Format1(try!(tape.take())),
            2 => SingleAdjustment::Format2(try!(tape.take())),
            _ => raise!("found an unknown format of the single-adjustment table"),
        })
    }
}

impl Value for PairAdjustment {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        Ok(match try!(tape.peek::<u16>()) {
            1 => PairAdjustment::Format1(try!(tape.take())),
            2 => PairAdjustment::Format2(try!(tape.take())),
            _ => raise!("found an unknown format of the pair-adjustment table"),
        })
    }
}
<commit_msg>Start to parse the context-positioning table<commit_after>#![allow(unused_mut, unused_variables)]

use {Result, Tape, Value, Walue};
use glyph_positioning::{
    BaseSet,
    LigatureSet,
    Mark1Set,
    Mark2Set,
    Pair,
    PairSet,
    Passage,
    Single,
    SingleFlags,
};
use layout::{Class, Coverage};

/// A table.
#[derive(Clone, Debug)]
pub enum Table {
    SingleAdjustment(SingleAdjustment),
    PairAdjustment(PairAdjustment),
    CursiveAttachment(CursiveAttachment),
    MarkToBaseAttachment(MarkToBaseAttachment),
    MarkToLigatureAttachment(MarkToLigatureAttachment),
    MarkToMarkAttachment(MarkToMarkAttachment),
    ContextPositioning(ContextPositioning),
    ChainContextPositioning(ChainContextPositioning),
    ExtensionPositioning(ExtensionPositioning),
}

/// A table for adjusting single glyphs.
#[derive(Clone, Debug)]
pub enum SingleAdjustment {
    /// Format 1.
    Format1(SingleAdjustment1),
    /// Format 2.
    Format2(SingleAdjustment2),
}

table! {
    @position
    #[doc = "A table for adjusting single glyphs in format 1."]
    pub SingleAdjustment1 { // SinglePosFormat1
        format          (u16        ) = { 1 }, // PosFormat
        coverage_offset (u16        ), // Coverage
        value_flags     (SingleFlags), // ValueFormat

        value (Single) |this, tape, position| { // Value
            tape.take_given((position, this.value_flags))
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },
    }
}

table! {
    @position
    #[doc = "A table for adjusting single glyphs in format 2."]
    pub SingleAdjustment2 { // SinglePosFormat2
        format          (u16        ) = { 2 }, // PosFormat
        coverage_offset (u16        ), // Coverage
        value_flags     (SingleFlags), // ValueFormat
        value_count     (u16        ), // ValueCount

        values (Vec<Single>) |this, tape, position| { // Value
            let mut values = Vec::with_capacity(this.value_count as usize);
            for i in 0..(this.value_count as usize) {
                values.push(try!(tape.take_given((position, this.value_flags))));
            }
            Ok(values)
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },
    }
}

/// A table for adjusting pairs of glyphs.
#[derive(Clone, Debug)]
pub enum PairAdjustment {
    /// Format 1.
    Format1(PairAdjustment1),
    /// Format 2.
    Format2(PairAdjustment2),
}

table! {
    @position
    #[doc = "A table for adjusting pairs of glyphs in format 1."]
    pub PairAdjustment1 { // PairPosFormat1
        format          (u16        ) = { 1 }, // PosFormat
        coverage_offset (u16        ), // Coverage
        value1_flags    (SingleFlags), // ValueFormat1
        value2_flags    (SingleFlags), // ValueFormat2
        pair_set_count  (u16        ), // PairSetCount

        pair_set_offsets (Vec<u16>) |this, tape, position| { // PairSetOffset
            tape.take_given(this.pair_set_count as usize)
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },

        pair_sets (Vec<PairSet>) |this, tape, position| {
            jump_take_given!(tape, position, this.pair_set_count, this.pair_set_offsets,
                             (position, this.value1_flags, this.value2_flags))
        },
    }
}

table! {
    @position
    #[doc = "A table for adjusting pairs of glyphs in format 2."]
    pub PairAdjustment2 { // PairPosFormat2
        format          (u16        ) = { 2 }, // PosFormat
        coverage_offset (u16        ), // Coverage
        value1_flags    (SingleFlags), // ValueFormat1
        value2_flags    (SingleFlags), // ValueFormat2
        class1_offset   (u16        ), // ClassDef1
        class2_offset   (u16        ), // ClassDef2
        class1_count    (u16        ), // Class1Count
        class2_count    (u16        ), // Class2Count

        pair_sets (Vec<Vec<Pair>>) |this, tape, position| { // Class1Record
            let mut values = Vec::with_capacity(this.class1_count as usize);
            for i in 0..(this.class1_count as usize) {
                let mut records = Vec::with_capacity(this.class2_count as usize);
                for j in 0..(this.class2_count as usize) {
                    records.push(try!(tape.take_given((position, this.value1_flags,
                                                       this.value2_flags))));
                }
                values.push(records);
            }
            Ok(values)
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },

        class1 (Class) |this, tape, position| {
            jump_take!(tape, position, this.class1_offset)
        },

        class2 (Class) |this, tape, position| {
            jump_take!(tape, position, this.class2_offset)
        },
    }
}

table! {
    @position
    #[doc = "A table for attaching cursive glyphs."]
    pub CursiveAttachment { // CursivePosFormat1
        format          (u16) = { 1 }, // PosFormat
        coverage_offset (u16), // Coverage
        passage_count   (u16), // EntryExitCount

        passages (Vec<Passage>) |this, tape, position| { // EntryExitRecord
            let mut values = Vec::with_capacity(this.passage_count as usize);
            for i in 0..(this.passage_count as usize) {
                values.push(try!(tape.take_given(position)));
            }
            Ok(values)
        },

        coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.coverage_offset)
        },
    }
}

table! {
    @position
    #[doc = "A table for attaching combining marks to base glyphs."]
    pub MarkToBaseAttachment { // MarkBasePosFormat1
        format               (u16) = { 1 }, // PosFormat
        mark_coverage_offset (u16), // MarkCoverage
        base_coverage_offset (u16), // BaseCoverage
        class_count          (u16), // ClassCount
        mark_set_offset      (u16), // MarkArray
        base_set_offset      (u16), // BaseArray

        mark_coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.mark_coverage_offset)
        },

        base_coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.base_coverage_offset)
        },

        mark_set (Mark1Set) |this, tape, position| {
            jump_take!(tape, position, this.mark_set_offset)
        },

        base_set (BaseSet) |this, tape, position| {
            jump_take_given!(tape, position, this.base_set_offset, this.class_count)
        },
    }
}

table! {
    @position
    #[doc = "A table for attaching combining marks to ligatures."]
    pub MarkToLigatureAttachment { // MarkLigPosFormat1
        format                   (u16) = { 1 }, // PosFormat
        mark_coverage_offset     (u16), // MarkCoverage
        ligature_coverage_offset (u16), // LigatureCoverage
        class_count              (u16), // ClassCount
        mark_set_offset          (u16), // MarkArray
        ligature_set_offset      (u16), // LigatureArray

        mark_coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.mark_coverage_offset)
        },

        ligature_coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.ligature_coverage_offset)
        },

        mark_set (Mark1Set) |this, tape, position| {
            jump_take!(tape, position, this.mark_set_offset)
        },

        ligature_set (LigatureSet) |this, tape, position| {
            jump_take_given!(tape, position, this.ligature_set_offset, this.class_count)
        },
    }
}

table! {
    @position
    #[doc = "A table for attaching combining marks to other marks."]
    pub MarkToMarkAttachment { // MarkMarkPosFormat1
        format                (u16) = { 1 }, // PosFormat
        mark1_coverage_offset (u16), // Mark1Coverage
        mark2_coverage_offset (u16), // Mark2Coverage
        class_count           (u16), // ClassCount
        mark1_set_offset      (u16), // Mark1Array
        mark2_set_offset      (u16), // Mark2Array

        mark1_coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.mark1_coverage_offset)
        },

        mark2_coverage (Coverage) |this, tape, position| {
            jump_take!(tape, position, this.mark2_coverage_offset)
        },

        mark1_set (Mark1Set) |this, tape, position| {
            jump_take!(tape, position, this.mark1_set_offset)
        },

        mark2_set (Mark2Set) |this, tape, position| {
            jump_take_given!(tape, position, this.mark2_set_offset, this.class_count)
        },
    }
}

/// A table for positioning glyphs in a context.
#[derive(Clone, Debug)]
pub enum ContextPositioning {
    /// Format 1.
    Format1(ContextPositioning1),
    /// Format 2.
    Format2(ContextPositioning2),
    /// Format 3.
    Format3(ContextPositioning3),
}

table! {
    #[doc = "A table for positioning glyphs in a context in format 1."]
    pub ContextPositioning1 {
        format (u16) = { 1 }, // PosFormat
    }
}

table! {
    #[doc = "A table for positioning glyphs in a context in format 2."]
    pub ContextPositioning2 {
        format (u16) = { 2 }, // PosFormat
    }
}

table! {
    #[doc = "A table for positioning glyphs in a context in format 3."]
    pub ContextPositioning3 {
        format (u16) = { 3 }, // PosFormat
    }
}

table! {
    #[doc = "A table for positioning glyphs in a chaining context."]
    pub ChainContextPositioning {
    }
}

table! {
    #[doc = "A table for other types of positioning."]
    pub ExtensionPositioning {
    }
}

impl Walue<u16> for Table {
    fn read<T: Tape>(tape: &mut T, kind: u16) -> Result<Self> {
        Ok(match kind {
            1 => Table::SingleAdjustment(try!(tape.take())),
            2 => Table::PairAdjustment(try!(tape.take())),
            3 => Table::CursiveAttachment(try!(tape.take())),
            4 => Table::MarkToBaseAttachment(try!(tape.take())),
            5 => Table::MarkToLigatureAttachment(try!(tape.take())),
            6 => Table::MarkToMarkAttachment(try!(tape.take())),
            7 => Table::ContextPositioning(try!(tape.take())),
            8 => Table::ChainContextPositioning(try!(tape.take())),
            9 => Table::ExtensionPositioning(try!(tape.take())),
            _ => raise!("found an unknown glyph-positioning type"),
        })
    }
}

impl Value for SingleAdjustment {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        Ok(match try!(tape.peek::<u16>()) {
            1 => SingleAdjustment::Format1(try!(tape.take())),
            2 => SingleAdjustment::Format2(try!(tape.take())),
            _ => raise!("found an unknown format of the single-adjustment table"),
        })
    }
}

impl Value for PairAdjustment {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        Ok(match try!(tape.peek::<u16>()) {
            1 => PairAdjustment::Format1(try!(tape.take())),
            2 => PairAdjustment::Format2(try!(tape.take())),
            _ => raise!("found an unknown format of the pair-adjustment table"),
        })
    }
}

impl Value for ContextPositioning {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        Ok(match try!(tape.peek::<u16>()) {
            1 => ContextPositioning::Format1(try!(tape.take())),
            2 => ContextPositioning::Format2(try!(tape.take())),
            3 => ContextPositioning::Format3(try!(tape.take())),
            _ => raise!("found an unknown format of the context-positioning table"),
        })
    }
}
<|endoftext|>


<commit_before>use engine::Game;
use gui::screens::{self, Screen, ScreenChange};
use gui::{Console, Colors, Key};
use gui::chars;
use util::units::{Direction, Point};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map_location: Point,
    info_location: Point,
    message_location: Point,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        Box::new(
            GameScreen {
                map_location: Point::new(16, 1),
                info_location: Point::new(1, 1),
                message_location: Point::new(16, 41),
            }
        )
    }
}

impl Screen for GameScreen {

    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.world.walk(Direction::Up);
                },
                Key::Down => {
                    game.world.walk(Direction::Down);
                },
                Key::Left => {
                    game.world.walk(Direction::Left);
                },
                Key::Right => {
                    game.world.walk(Direction::Right);
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        return None;
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.render_map(game, console);

        let repr = game.world.player.repr;
        let pos = game.world.player.pos;

        console.put_plain(self.map_location + pos, repr);

        self.draw_borders(game, console);
    }
}

impl GameScreen {

    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        console.put_plain(self.map_location + Point::new(-1, -1), chars::NW as char);
        console.put_plain(self.map_location + Point::new(63, -1), chars::NE as char);
        console.put_plain(self.map_location + Point::new(-1, 38), chars::SW as char);
        console.put_plain(self.map_location + Point::new(63, 38), chars::SE as char);

        for x in 0..63 {
            console.put_plain(self.map_location + Point::new(x, -1), chars::HLINE as char);
            console.put_plain(self.map_location + Point::new(x, 38), chars::HLINE as char);
        }

        for y in 0..38 {
            console.put_plain(self.map_location + Point::new(-1, y), chars::VLINE as char);
            console.put_plain(self.map_location + Point::new(63, y), chars::VLINE as char);
        }

        console.put_plain(self.map_location + Point::new(0, -1), 'M');
        console.put_plain(self.map_location + Point::new(1, -1), 'a');
        console.put_plain(self.map_location + Point::new(2, -1), 'p');

        console.put_plain(self.info_location + Point::new(-1, -1), chars::NW as char);
        console.put_plain(self.info_location + Point::new(13, -1), chars::NE as char);
        console.put_plain(self.info_location + Point::new(-1, 48), chars::SW as char);
        console.put_plain(self.info_location + Point::new(13, 48), chars::SE as char);

        for x in 0..13 {
            console.put_plain(self.info_location + Point::new(x, -1), chars::HLINE as char);
            console.put_plain(self.info_location + Point::new(x, 48), chars::HLINE as char);
        }

        for y in 0..48 {
            console.put_plain(self.info_location + Point::new(-1, y), chars::VLINE as char);
            console.put_plain(self.info_location + Point::new(13, y), chars::VLINE as char);
        }

        console.put_plain(self.info_location + Point::new(0, -1), 'I');
        console.put_plain(self.info_location + Point::new(1, -1), 'n');
        console.put_plain(self.info_location + Point::new(2, -1), 'f');
        console.put_plain(self.info_location + Point::new(3, -1), 'o');

        console.put_plain(self.message_location + Point::new(-1, -1), chars::NW as char);
        console.put_plain(self.message_location + Point::new(63, -1), chars::NE as char);
        console.put_plain(self.message_location + Point::new(-1,  8), chars::SW as char);
        console.put_plain(self.message_location + Point::new(63,  8), chars::SE as char);

        for x in 0..63 {
            console.put_plain(self.message_location + Point::new(x, -1), chars::HLINE as char);
            console.put_plain(self.message_location + Point::new(x,  8), chars::HLINE as char);
        }

        for y in 0..8 {
            console.put_plain(self.message_location + Point::new(-1, y), chars::VLINE as char);
            console.put_plain(self.message_location + Point::new(63, y), chars::VLINE as char);
        }

        console.put_plain(self.message_location + Point::new(0, -1), 'M');
        console.put_plain(self.message_location + Point::new(1, -1), 'e');
        console.put_plain(self.message_location + Point::new(2, -1), 's');
        console.put_plain(self.message_location + Point::new(3, -1), 's');
        console.put_plain(self.message_location + Point::new(4, -1), 'a');
        console.put_plain(self.message_location + Point::new(5, -1), 'g');
        console.put_plain(self.message_location + Point::new(6, -1), 'e');
        console.put_plain(self.message_location + Point::new(7, -1), 's');

    }

    #[allow(unused)]
    fn render_map(&self, game: &mut Game, console: &mut Console) {
        let map = &(game.world.map);

        for (y, line) in map.tiles.iter().enumerate() {
            for (x, cell) in line.iter().enumerate() {
                console.put(self.map_location + Point::new(x as i32, y as i32), ' ', Colors::white, cell.b_color());
            }
        }
    }

}
<commit_msg>Use print_plain messages instead of individual put_plain<commit_after>use engine::Game;
use gui::screens::{self, Screen, ScreenChange};
use gui::{Console, Colors, Key};
use gui::chars;
use util::units::{Direction, Point};

#[allow(missing_copy_implementations)]
pub struct GameScreen {
    map_location: Point,
    info_location: Point,
    message_location: Point,
}

impl GameScreen {
    pub fn new() -> Box<Screen> {
        Box::new(
            GameScreen {
                map_location: Point::new(16, 1),
                info_location: Point::new(1, 1),
                message_location: Point::new(16, 41),
            }
        )
    }
}

impl Screen for GameScreen {

    #[allow(unused)]
    fn input(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        if let Some(key) = console.check_for_keypress() {
            match key {
                Key::Up => {
                    game.world.walk(Direction::Up);
                },
                Key::Down => {
                    game.world.walk(Direction::Down);
                },
                Key::Left => {
                    game.world.walk(Direction::Left);
                },
                Key::Right => {
                    game.world.walk(Direction::Right);
                },
                Key::Escape => {
                    return Some(ScreenChange::AddScreen(screens::PauseScreen::new()));
                },
                _ => {}
            }
        }

        None
    }

    #[allow(unused)]
    fn update(&mut self, game: &mut Game, console: &mut Console) -> Option<ScreenChange> {
        return None;
    }

    #[allow(unused)]
    fn render(&mut self, game: &mut Game, console: &mut Console) {
        self.render_map(game, console);

        let repr = game.world.player.repr;
        let pos = game.world.player.pos;

        console.put_plain(self.map_location + pos, repr);

        self.draw_borders(game, console);
    }
}

impl GameScreen {

    #[allow(unused)]
    fn draw_borders(&self, game: &mut Game, console: &mut Console) {
        console.put_plain(self.map_location + Point::new(-1, -1), chars::NW as char);
        console.put_plain(self.map_location + Point::new(63, -1), chars::NE as char);
        console.put_plain(self.map_location + Point::new(-1, 38), chars::SW as char);
        console.put_plain(self.map_location + Point::new(63, 38), chars::SE as char);

        for x in 0..63 {
            console.put_plain(self.map_location + Point::new(x, -1), chars::HLINE as char);
            console.put_plain(self.map_location + Point::new(x, 38), chars::HLINE as char);
        }

        for y in 0..38 {
            console.put_plain(self.map_location + Point::new(-1, y), chars::VLINE as char);
            console.put_plain(self.map_location + Point::new(63, y), chars::VLINE as char);
        }

        console.print_plain(self.map_location + Point::new(0, -1), "Map");

        console.put_plain(self.info_location + Point::new(-1, -1), chars::NW as char);
        console.put_plain(self.info_location + Point::new(13, -1), chars::NE as char);
        console.put_plain(self.info_location + Point::new(-1, 48), chars::SW as char);
        console.put_plain(self.info_location + Point::new(13, 48), chars::SE as char);

        for x in 0..13 {
            console.put_plain(self.info_location + Point::new(x, -1), chars::HLINE as char);
            console.put_plain(self.info_location + Point::new(x, 48), chars::HLINE as char);
        }

        for y in 0..48 {
            console.put_plain(self.info_location + Point::new(-1, y), chars::VLINE as char);
            console.put_plain(self.info_location + Point::new(13, y), chars::VLINE as char);
        }

        console.print_plain(self.info_location + Point::new(0, -1), "Info");

        console.put_plain(self.message_location + Point::new(-1, -1), chars::NW as char);
        console.put_plain(self.message_location + Point::new(63, -1), chars::NE as char);
        console.put_plain(self.message_location + Point::new(-1,  8), chars::SW as char);
        console.put_plain(self.message_location + Point::new(63,  8), chars::SE as char);

        for x in 0..63 {
            console.put_plain(self.message_location + Point::new(x, -1), chars::HLINE as char);
            console.put_plain(self.message_location + Point::new(x,  8), chars::HLINE as char);
        }

        for y in 0..8 {
            console.put_plain(self.message_location + Point::new(-1, y), chars::VLINE as char);
            console.put_plain(self.message_location + Point::new(63, y), chars::VLINE as char);
        }

        console.print_plain(self.message_location + Point::new(0, -1), "Messages");
    }

    #[allow(unused)]
    fn render_map(&self, game: &mut Game, console: &mut Console) {
        let map = &(game.world.map);

        for (y, line) in map.tiles.iter().enumerate() {
            for (x, cell) in line.iter().enumerate() {
                console.put(self.map_location + Point::new(x as i32, y as i32), ' ', Colors::white, cell.b_color());
            }
        }
    }

}
<|endoftext|>


<commit_before>/* diosix hypervisor manifest file-system management
 *
 * (c) Chris Williams, 2020-2021.
 *
 * See LICENSE for usage and copying.
 */

use super::physmem;
use super::error::Cause;
use super::capsule;
use super::hardware;
use super::loader;
use super::virtmem::Mapping;
use super::vcore::Priority;
use dmfs::{ManifestImageIter, ManifestObject, ManifestObjectType, ManifestObjectData};
use alloc::string::String;
use alloc::vec::Vec;

/* bring in the built-in dmfs image */
use core::slice;
use core::intrinsics::transmute;
extern "C"
{
    static _binary_dmfs_img_start: u8;
    static _binary_dmfs_img_size: u8;
}

/* convert the included dmfs image into a byte slice */
macro_rules! get_dmfs_image
{
    () =>
    {
        unsafe
        {
            slice::from_raw_parts
            (
                transmute(&_binary_dmfs_img_start),
                transmute(&_binary_dmfs_img_size)
            )
        }
    }
}

/* return a list of a DMFS image's asset names and descriptions
   <= array of (names, descriptions) of image's assets */
pub fn list_assets() ->  Result<Vec<(String, String)>, Cause>
{
    let image = get_dmfs_image!();
    let manifest = match ManifestImageIter::from_slice(image)
    {
        Ok(m) => m,
        Err(_) => return Err(Cause::ManifestBadFS)
    };

    let mut list: Vec<(String, String)> = Vec::new();
    for asset in manifest
    {
        list.push((asset.get_name(), asset.get_description()));
    }

    Ok(list)
}

/* look up an asset from the given DMFS image by its name */
pub fn get_named_asset(name: &str) -> Result<ManifestObject, Cause>
{
    let image = get_dmfs_image!();
    let manifest = match ManifestImageIter::from_slice(image)
    {
        Ok(m) => m,
        Err(_) => return Err(Cause::ManifestBadFS)
    };

    for asset in manifest
    {
        /* sadly no simple strcmp() in rust? */
        if asset.get_name().as_str().starts_with(name) == true && asset.get_name().len() == name.len()
        {
            return Ok(asset);
        }
    }

    Err(Cause::ManifestNoSuchAsset)
}

/* parse the hypervisor's bundled manifest, creating services and capsules as required,
   and output any included boot banner messages, during system start up */
pub fn unpack_at_boot() -> Result<(), Cause>
{
    let image = get_dmfs_image!();
    let manifest = match ManifestImageIter::from_slice(image)
    {
        Ok(m) => m,
        Err(_) => return Err(Cause::ManifestBadFS)
    };

    for asset in manifest
    {
        match asset.get_type()
        {
            /* only unpack and process boot messages and system services at startup */
            ManifestObjectType::BootMsg => load_asset(asset)?,
            ManifestObjectType::SystemService => load_asset(asset)?,
            ManifestObjectType::GuestOS => load_asset(asset)?,
            _ => ()
        }
    }

    Ok(())
}

/* process the given asset, such as printing it to the debug output stream if it's a boot message
   or parsing it and running it if it's an executable, from the given DMFS image
   => asset = manifest asset to parse and process into memory
*/
pub fn load_asset(asset: ManifestObject) -> Result<(), Cause>
{
    let image = get_dmfs_image!();
    let properties = asset.get_properties();
    let content = match asset.get_contents()
    {
        ManifestObjectData::Bytes(b) => b.as_slice(),
        ManifestObjectData::Region(r) => &image[r.start..r.end]
    };

    match asset.get_type()
    {
        /* print the included boot message */
        ManifestObjectType::BootMsg =>
        {
            hvdebugraw!("\n{}\n\n", String::from_utf8_lossy(content));
            debughousekeeper!(); /* ensure the message is seen */
        },

        /* create and run a system service */
        ManifestObjectType::SystemService => match create_capsule_from_exec(content, Some(properties))
        {
            Ok(_) => hvdebug!("Created system service {} ({}) {} bytes",
                        asset.get_name(), asset.get_description(), asset.get_contents_size()),
            Err(_e) => hvdebug!("Failed to create capsule for system service {}: {:?}", asset.get_name(), _e)
        },

        /* create an included guest OS (which does not have any special permissions) */
        ManifestObjectType::GuestOS => match create_capsule_from_exec(content, None)
        {
            Ok(_) => hvdebug!("Created guest OS {} ({}) {} bytes",
                        asset.get_name(), asset.get_description(), asset.get_contents_size()),
            Err(_e) => hvdebug!("Failed to create capsule for system service {}: {:?}", asset.get_name(), _e)
        },

        t => hvdebug!("Found manifest object type {:?}", t)
    }

    Ok(())
}

/* create a capsule from an executable in a DMFS image
   => binary = slice containing the executable to parse and load
      properties = permissions and other properties to grant the capsule, or None
   <= Ok, or an error code
*/
fn create_capsule_from_exec(binary: &[u8], properties: Option<Vec<String>>) -> Result<(), Cause>
{
    /* create capsule with the given properties */
    let capid = capsule::create(properties)?;

    /* assign one virtual CPU core to the capsule */
    let cpus = 1;

    /* reserve 128MB of physical RAM for the capsule */
    let size = 128 * 1024 * 1024;
    let ram = physmem::alloc_region(size)?;

    /* create device tree blob for the virtual hardware available to the guest
    capsule and copy into the end of the region's physical RAM.
    a zero-length DTB indicates something went wrong */
    let guest_dtb = hardware::clone_dtb_for_capsule(cpus, 0, ram.base(), ram.size())?;
    if guest_dtb.len() == 0
    {
        return Err(Cause::BootDeviceTreeBad);
    }

    let guest_dtb_base = ram.fill_end(guest_dtb)?;

    /* map that physical RAM into the capsule */
    let mut mapping = Mapping::new();
    mapping.set_physical(ram);
    mapping.identity_mapping()?;
    capsule::map_memory(capid, mapping)?;

    /* parse + copy the capsule's binary into its physical RAM */
    let entry = loader::load(ram, binary)?;

    /* create virtual CPU cores for the capsule as required */
    for vcoreid in 0..cpus
    {
        capsule::add_vcore(capid, vcoreid, entry, guest_dtb_base, Priority::High)?;
    }

    Ok(())
}<commit_msg>Display capsule ID in creation debug output<commit_after>/* diosix hypervisor manifest file-system management
 *
 * (c) Chris Williams, 2020-2021.
 *
 * See LICENSE for usage and copying.
 */

use super::physmem;
use super::error::Cause;
use super::capsule;
use super::hardware;
use super::loader;
use super::virtmem::Mapping;
use super::vcore::Priority;
use dmfs::{ManifestImageIter, ManifestObject, ManifestObjectType, ManifestObjectData};
use alloc::string::String;
use alloc::vec::Vec;

/* bring in the built-in dmfs image */
use core::slice;
use core::intrinsics::transmute;
extern "C"
{
    static _binary_dmfs_img_start: u8;
    static _binary_dmfs_img_size: u8;
}

/* convert the included dmfs image into a byte slice */
macro_rules! get_dmfs_image
{
    () =>
    {
        unsafe
        {
            slice::from_raw_parts
            (
                transmute(&_binary_dmfs_img_start),
                transmute(&_binary_dmfs_img_size)
            )
        }
    }
}

/* return a list of a DMFS image's asset names and descriptions
   <= array of (names, descriptions) of image's assets */
pub fn list_assets() ->  Result<Vec<(String, String)>, Cause>
{
    let image = get_dmfs_image!();
    let manifest = match ManifestImageIter::from_slice(image)
    {
        Ok(m) => m,
        Err(_) => return Err(Cause::ManifestBadFS)
    };

    let mut list: Vec<(String, String)> = Vec::new();
    for asset in manifest
    {
        list.push((asset.get_name(), asset.get_description()));
    }

    Ok(list)
}

/* look up an asset from the given DMFS image by its name */
pub fn get_named_asset(name: &str) -> Result<ManifestObject, Cause>
{
    let image = get_dmfs_image!();
    let manifest = match ManifestImageIter::from_slice(image)
    {
        Ok(m) => m,
        Err(_) => return Err(Cause::ManifestBadFS)
    };

    for asset in manifest
    {
        /* sadly no simple strcmp() in rust? */
        if asset.get_name().as_str().starts_with(name) == true && asset.get_name().len() == name.len()
        {
            return Ok(asset);
        }
    }

    Err(Cause::ManifestNoSuchAsset)
}

/* parse the hypervisor's bundled manifest, creating services and capsules as required,
   and output any included boot banner messages, during system start up */
pub fn unpack_at_boot() -> Result<(), Cause>
{
    let image = get_dmfs_image!();
    let manifest = match ManifestImageIter::from_slice(image)
    {
        Ok(m) => m,
        Err(_) => return Err(Cause::ManifestBadFS)
    };

    for asset in manifest
    {
        match asset.get_type()
        {
            /* only unpack and process boot messages and system services at startup */
            ManifestObjectType::BootMsg => load_asset(asset)?,
            ManifestObjectType::SystemService => load_asset(asset)?,
            ManifestObjectType::GuestOS => load_asset(asset)?,
            _ => ()
        }
    }

    Ok(())
}

/* process the given asset, such as printing it to the debug output stream if it's a boot message
   or parsing it and running it if it's an executable, from the given DMFS image
   => asset = manifest asset to parse and process into memory
*/
pub fn load_asset(asset: ManifestObject) -> Result<(), Cause>
{
    let image = get_dmfs_image!();
    let properties = asset.get_properties();
    let content = match asset.get_contents()
    {
        ManifestObjectData::Bytes(b) => b.as_slice(),
        ManifestObjectData::Region(r) => &image[r.start..r.end]
    };

    match asset.get_type()
    {
        /* print the included boot message */
        ManifestObjectType::BootMsg =>
        {
            hvdebugraw!("\n{}\n\n", String::from_utf8_lossy(content));
            debughousekeeper!(); /* ensure the message is seen */
        },

        /* create and run a system service */
        ManifestObjectType::SystemService => match create_capsule_from_exec(content, Some(properties))
        {
            Ok(cid) => hvdebug!("Created system service {} ({}) {} bytes (capsule {})",
                        asset.get_name(), asset.get_description(), asset.get_contents_size(), cid),
            Err(_e) => hvdebug!("Failed to create capsule for system service {}: {:?}", asset.get_name(), _e)
        },

        /* create an included guest OS (which does not have any special permissions) */
        ManifestObjectType::GuestOS => match create_capsule_from_exec(content, None)
        {
            Ok(cid) => hvdebug!("Created guest OS {} ({}) {} bytes (capsule {})",
                        asset.get_name(), asset.get_description(), asset.get_contents_size(), cid),
            Err(_e) => hvdebug!("Failed to create capsule for system service {}: {:?}", asset.get_name(), _e)
        },

        t => hvdebug!("Found manifest object type {:?}", t)
    }

    Ok(())
}

/* create a capsule from an executable in a DMFS image
   => binary = slice containing the executable to parse and load
      properties = permissions and other properties to grant the capsule, or None
   <= Ok with capusle ID, or an error code
*/
fn create_capsule_from_exec(binary: &[u8], properties: Option<Vec<String>>) -> Result<capsule::CapsuleID, Cause>
{
    /* assign one virtual CPU core to the capsule */
    let cpus = 1;

    /* create capsule with the given properties */
    let capid = capsule::create(properties, cpus)?;

    /* reserve 128MB of physical RAM for the capsule */
    let size = 128 * 1024 * 1024;
    let ram = physmem::alloc_region(size)?;

    /* create device tree blob for the virtual hardware available to the guest
    capsule and copy into the end of the region's physical RAM.
    a zero-length DTB indicates something went wrong */
    let guest_dtb = hardware::clone_dtb_for_capsule(cpus, 0, ram.base(), ram.size())?;
    if guest_dtb.len() == 0
    {
        return Err(Cause::BootDeviceTreeBad);
    }
    let guest_dtb_base = ram.fill_end(guest_dtb)?;

    /* map that physical RAM into the capsule */
    let mut mapping = Mapping::new();
    mapping.set_physical(ram);
    mapping.identity_mapping()?;
    capsule::map_memory(capid, mapping)?;

    /* parse + copy the capsule's binary into its physical RAM */
    let entry = loader::load(ram, binary)?;

    /* create virtual CPU cores for the capsule as required */
    for vcoreid in 0..cpus
    {
        capsule::add_vcore(capid, vcoreid, entry, guest_dtb_base, Priority::High)?;
    }

    Ok(capid)
}<|endoftext|>


<commit_before>/*
 * Copyright (c) the nom-lua contributors. All rights reserved.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation. This file is also subject
 * to the Linking exception provided in the LICENSE file that
 * accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#![feature(test)]

extern crate test;
extern crate nom_lua;

use test::Bencher;
use nom_lua::number;

#[bench]
fn parse_hex_int(b: &mut Bencher) {
    let ints: Vec<String> =
        test::black_box((0..32)
                        .map(|i| format!("0x{:X}", i).to_string())
                        .collect());

    b.iter(|| {
        for i in ints.iter() {
            number::parse_number(i.as_bytes());
        }
    });
}

#[bench]
fn parse_int(b: &mut Bencher) {
    let ints: Vec<String> =
        test::black_box((0..32)
                        .map(|i| format!("{}", i).to_string())
                        .collect());

    b.iter(|| {
        for i in ints.iter() {
            number::parse_number(i.as_bytes());
        }
    });
}

#[bench]
fn parse_float(b: &mut Bencher) {
    let ints: Vec<String> =
        test::black_box((0..32)
                        .map(|i| format!("{}", i as f32).to_string())
                        .collect());

    b.iter(|| {
        for i in ints.iter() {
            number::parse_number(i.as_bytes());
        }
    });
}
<commit_msg>More clippy lints<commit_after>/*
 * Copyright (c) the nom-lua contributors. All rights reserved.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation. This file is also subject
 * to the Linking exception provided in the LICENSE file that
 * accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#![feature(test)]

extern crate test;
extern crate nom_lua;

use test::Bencher;
use nom_lua::number;

#[bench]
fn parse_hex_int(b: &mut Bencher) {
    let ints: Vec<String> =
        test::black_box((0..32)
                        .map(|i| format!("0x{:X}", i).to_string())
                        .collect());

    b.iter(|| {
        for i in &ints {
            number::parse_number(i.as_bytes());
        }
    });
}

#[bench]
fn parse_int(b: &mut Bencher) {
    let ints: Vec<String> =
        test::black_box((0..32)
                        .map(|i| format!("{}", i).to_string())
                        .collect());

    b.iter(|| {
        for i in &ints {
            number::parse_number(i.as_bytes());
        }
    });
}

#[bench]
fn parse_float(b: &mut Bencher) {
    let ints: Vec<String> =
        test::black_box((0..32)
                        .map(|i| format!("{}", i as f32).to_string())
                        .collect());

    b.iter(|| {
        for i in &ints {
            number::parse_number(i.as_bytes());
        }
    });
}
<|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/. */

#![feature(thread_local, link_args, plugin, box_syntax, int_uint)]

#![allow(experimental, non_camel_case_types, unstable)]
#![deny(unused_imports, unused_variables, unused_mut)]

#[macro_use]
extern crate log;
#[plugin]
extern crate "plugins" as servo_plugins;

extern crate servo;
extern crate compositing;

extern crate azure;
extern crate geom;
extern crate gfx;
extern crate gleam;
extern crate glutin_app;
extern crate js;
extern crate layers;
extern crate png;
extern crate script;

extern crate "net" as servo_net;
extern crate "msg" as servo_msg;
extern crate util;
extern crate style;
extern crate stb_image;

extern crate libc;
extern crate "url" as std_url;

#[cfg(target_os="macos")]
extern crate cgl;
#[cfg(target_os="macos")]
extern crate cocoa;
#[cfg(target_os="macos")]
extern crate core_graphics;
#[cfg(target_os="macos")]
extern crate core_text;

// Must come first.
pub mod macros;

pub mod browser;
pub mod browser_host;
pub mod command_line;
pub mod cookie;
pub mod core;
pub mod drag_data;
pub mod eutil;
pub mod frame;
pub mod interfaces;
pub mod print_settings;
pub mod process_message;
pub mod render_handler;
pub mod request;
pub mod request_context;
pub mod response;
pub mod stream;
pub mod string;
pub mod string_list;
pub mod string_map;
pub mod string_multimap;
pub mod stubs;
pub mod switches;
pub mod task;
pub mod types;
pub mod urlrequest;
pub mod v8;
pub mod values;
pub mod window;
pub mod wrappers;
pub mod xml_reader;
pub mod zip_reader;
<commit_msg>Add [no_link] attribute to plugins crate<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/. */

#![feature(thread_local, link_args, plugin, box_syntax, int_uint)]

#![allow(experimental, non_camel_case_types, unstable)]
#![deny(unused_imports, unused_variables, unused_mut)]

#[macro_use]
extern crate log;
#[plugin] #[no_link]
extern crate "plugins" as servo_plugins;

extern crate servo;
extern crate compositing;

extern crate azure;
extern crate geom;
extern crate gfx;
extern crate gleam;
extern crate glutin_app;
extern crate js;
extern crate layers;
extern crate png;
extern crate script;

extern crate "net" as servo_net;
extern crate "msg" as servo_msg;
extern crate util;
extern crate style;
extern crate stb_image;

extern crate libc;
extern crate "url" as std_url;

#[cfg(target_os="macos")]
extern crate cgl;
#[cfg(target_os="macos")]
extern crate cocoa;
#[cfg(target_os="macos")]
extern crate core_graphics;
#[cfg(target_os="macos")]
extern crate core_text;

// Must come first.
pub mod macros;

pub mod browser;
pub mod browser_host;
pub mod command_line;
pub mod cookie;
pub mod core;
pub mod drag_data;
pub mod eutil;
pub mod frame;
pub mod interfaces;
pub mod print_settings;
pub mod process_message;
pub mod render_handler;
pub mod request;
pub mod request_context;
pub mod response;
pub mod stream;
pub mod string;
pub mod string_list;
pub mod string_map;
pub mod string_multimap;
pub mod stubs;
pub mod switches;
pub mod task;
pub mod types;
pub mod urlrequest;
pub mod v8;
pub mod values;
pub mod window;
pub mod wrappers;
pub mod xml_reader;
pub mod zip_reader;
<|endoftext|>


<commit_before>use options::parser::MatchedFlags;
use options::{flags, Misfire};

use fs::dir_action::{DirAction, RecurseOptions};

impl DirAction {

    /// Determine which action to perform when trying to list a directory.
    pub fn deduce(matches: &MatchedFlags) -> Result<DirAction, Misfire> {
        let recurse = matches.has(&flags::RECURSE)?;
        let list    = matches.has(&flags::LIST_DIRS)?;
        let tree    = matches.has(&flags::TREE)?;

        // Early check for --level when it wouldn’t do anything
        if !recurse && !tree && matches.get(&flags::LEVEL)?.is_some() {
            return Err(Misfire::Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE));
        }

        match (recurse, list, tree) {

            // You can't --list-dirs along with --recurse or --tree because
            // they already automatically list directories.
            (true,  true,  _    )  => Err(Misfire::Conflict(&flags::RECURSE, &flags::LIST_DIRS)),
            (_,     true,  true )  => Err(Misfire::Conflict(&flags::TREE,    &flags::LIST_DIRS)),

            (_   ,  _,     true )  => Ok(DirAction::Recurse(RecurseOptions::deduce(matches, true)?)),
            (true,  false, false)  => Ok(DirAction::Recurse(RecurseOptions::deduce(matches, false)?)),
            (false, true,  _    )  => Ok(DirAction::AsFile),
            (false, false, _    )  => Ok(DirAction::List),
        }
    }
}

impl RecurseOptions {

    /// Determine which files should be recursed into.
    pub fn deduce(matches: &MatchedFlags, tree: bool) -> Result<RecurseOptions, Misfire> {
        let max_depth = if let Some(level) = matches.get(&flags::LEVEL)? {
            match level.to_string_lossy().parse() {
                Ok(l)   => Some(l),
                Err(e)  => return Err(Misfire::FailedParse(e)),
            }
        }
        else {
            None
        };

        Ok(RecurseOptions { tree, max_depth })
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use options::flags;
    use options::parser::Flag;

    macro_rules! test {
        ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => {
            #[test]
            fn $name() {
                use options::parser::Arg;
                use options::test::parse_for_test;
                use options::test::Strictnesses::*;

                static TEST_ARGS: &[&Arg] = &[&flags::RECURSE, &flags::LIST_DIRS, &flags::TREE, &flags::LEVEL ];
                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
                    assert_eq!(result, $result);
                }
            }
        };
    }

    // Default behaviour
    test!(empty:           DirAction <- [];               Both => Ok(DirAction::List));

    // Listing files as directories
    test!(dirs_short:      DirAction <- ["-d"];           Both => Ok(DirAction::AsFile));
    test!(dirs_long:       DirAction <- ["--list-dirs"];  Both => Ok(DirAction::AsFile));

    // Recursing
    use self::DirAction::Recurse;
    test!(rec_short:       DirAction <- ["-R"];                           Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: None })));
    test!(rec_long:        DirAction <- ["--recurse"];                    Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: None })));
    test!(rec_lim_short:   DirAction <- ["-RL4"];                         Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(4) })));
    test!(rec_lim_short_2: DirAction <- ["-RL=5"];                        Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(5) })));
    test!(rec_lim_long:    DirAction <- ["--recurse", "--level", "666"];  Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(666) })));
    test!(rec_lim_long_2:  DirAction <- ["--recurse", "--level=0118"];    Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(118) })));
    test!(rec_tree:        DirAction <- ["--recurse", "--tree"];          Both => Ok(Recurse(RecurseOptions { tree: true,  max_depth: None })));
    test!(rec_short_tree:  DirAction <- ["--tree", "--recurse"];          Both => Ok(Recurse(RecurseOptions { tree: true,  max_depth: None })));

    // Errors
    test!(error:           DirAction <- ["--list-dirs", "--recurse"];     Both => Err(Misfire::Conflict(&flags::RECURSE, &flags::LIST_DIRS)));
    test!(error_2:         DirAction <- ["--list-dirs", "--tree"];        Both => Err(Misfire::Conflict(&flags::TREE,    &flags::LIST_DIRS)));
    test!(underwaterlevel: DirAction <- ["--level=4"];                    Both => Err(Misfire::Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE)));

    // Overriding
    test!(overriding_1:    DirAction <- ["-RL=6", "-L=7"];                Last => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(7) })));
    test!(overriding_2:    DirAction <- ["-RL=6", "-L=7"];            Complain => Err(Misfire::Duplicate(Flag::Short(b'L'), Flag::Short(b'L'))));
}
<commit_msg>Make the dir action a bit more lenient<commit_after>use options::parser::MatchedFlags;
use options::{flags, Misfire};

use fs::dir_action::{DirAction, RecurseOptions};

impl DirAction {

    /// Determine which action to perform when trying to list a directory.
    pub fn deduce(matches: &MatchedFlags) -> Result<DirAction, Misfire> {
        let recurse = matches.has(&flags::RECURSE)?;
        let as_file = matches.has(&flags::LIST_DIRS)?;
        let tree    = matches.has(&flags::TREE)?;

        if matches.is_strict() {
            // Early check for --level when it wouldn’t do anything
            if !recurse && !tree && matches.count(&flags::LEVEL) > 0 {
                return Err(Misfire::Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE));
            }
            else if recurse && as_file {
                return Err(Misfire::Conflict(&flags::RECURSE, &flags::LIST_DIRS));
            }
            else if tree && as_file {
                return Err(Misfire::Conflict(&flags::TREE, &flags::LIST_DIRS));
            }
        }

        if tree {
            Ok(DirAction::Recurse(RecurseOptions::deduce(matches, true)?))
        }
        else if recurse {
            Ok(DirAction::Recurse(RecurseOptions::deduce(matches, false)?))
        }
        else if as_file {
            Ok(DirAction::AsFile)
        }
        else {
            Ok(DirAction::List)
        }
    }
}

impl RecurseOptions {

    /// Determine which files should be recursed into.
    pub fn deduce(matches: &MatchedFlags, tree: bool) -> Result<RecurseOptions, Misfire> {
        let max_depth = if let Some(level) = matches.get(&flags::LEVEL)? {
            match level.to_string_lossy().parse() {
                Ok(l)   => Some(l),
                Err(e)  => return Err(Misfire::FailedParse(e)),
            }
        }
        else {
            None
        };

        Ok(RecurseOptions { tree, max_depth })
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use options::flags;
    use options::parser::Flag;

    macro_rules! test {
        ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => {
            #[test]
            fn $name() {
                use options::parser::Arg;
                use options::test::parse_for_test;
                use options::test::Strictnesses::*;

                static TEST_ARGS: &[&Arg] = &[&flags::RECURSE, &flags::LIST_DIRS, &flags::TREE, &flags::LEVEL ];
                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
                    assert_eq!(result, $result);
                }
            }
        };
    }

    // Default behaviour
    test!(empty:           DirAction <- [];               Both => Ok(DirAction::List));

    // Listing files as directories
    test!(dirs_short:      DirAction <- ["-d"];           Both => Ok(DirAction::AsFile));
    test!(dirs_long:       DirAction <- ["--list-dirs"];  Both => Ok(DirAction::AsFile));

    // Recursing
    use self::DirAction::Recurse;
    test!(rec_short:       DirAction <- ["-R"];                           Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: None })));
    test!(rec_long:        DirAction <- ["--recurse"];                    Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: None })));
    test!(rec_lim_short:   DirAction <- ["-RL4"];                         Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(4) })));
    test!(rec_lim_short_2: DirAction <- ["-RL=5"];                        Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(5) })));
    test!(rec_lim_long:    DirAction <- ["--recurse", "--level", "666"];  Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(666) })));
    test!(rec_lim_long_2:  DirAction <- ["--recurse", "--level=0118"];    Both => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(118) })));
    test!(tree:            DirAction <- ["--tree"];                       Both => Ok(Recurse(RecurseOptions { tree: true,  max_depth: None })));
    test!(rec_tree:        DirAction <- ["--recurse", "--tree"];          Both => Ok(Recurse(RecurseOptions { tree: true,  max_depth: None })));
    test!(rec_short_tree:  DirAction <- ["-TR"];                          Both => Ok(Recurse(RecurseOptions { tree: true,  max_depth: None })));

    // Overriding --list-dirs, --recurse, and --tree
    test!(dirs_recurse:    DirAction <- ["--list-dirs", "--recurse"];     Last => Ok(Recurse(RecurseOptions { tree: false, max_depth: None })));
    test!(dirs_tree:       DirAction <- ["--list-dirs", "--tree"];        Last => Ok(Recurse(RecurseOptions { tree: true,  max_depth: None })));
    test!(just_level:      DirAction <- ["--level=4"];                    Last => Ok(DirAction::List));

    test!(dirs_recurse_2:  DirAction <- ["--list-dirs", "--recurse"]; Complain => Err(Misfire::Conflict(&flags::RECURSE, &flags::LIST_DIRS)));
    test!(dirs_tree_2:     DirAction <- ["--list-dirs", "--tree"];    Complain => Err(Misfire::Conflict(&flags::TREE,    &flags::LIST_DIRS)));
    test!(just_level_2:    DirAction <- ["--level=4"];                Complain => Err(Misfire::Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE)));

    // Overriding levels
    test!(overriding_1:    DirAction <- ["-RL=6", "-L=7"];                Last => Ok(Recurse(RecurseOptions { tree: false, max_depth: Some(7) })));
    test!(overriding_2:    DirAction <- ["-RL=6", "-L=7"];            Complain => Err(Misfire::Duplicate(Flag::Short(b'L'), Flag::Short(b'L'))));
}
<|endoftext|>


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

use std::{ffi::OsString,
          io,
          path::PathBuf,
          process::{self,
                    Command},
          ptr};

use winapi::{shared::minwindef::{DWORD,
                                 FALSE,
                                 LPDWORD},
             um::{handleapi,
                  processthreadsapi,
                  winnt::{HANDLE,
                          PROCESS_QUERY_LIMITED_INFORMATION,
                          PROCESS_TERMINATE}}};

use super::Signal;
use crate::error::{Error,
                   Result};

const STILL_ACTIVE: u32 = 259;

pub type Pid = DWORD;
pub type SignalCode = DWORD;

pub fn become_command(command: PathBuf, args: &[OsString]) -> Result<()> {
    become_child_command(command, args)
}

/// Get process identifier of calling process.
pub fn current_pid() -> u32 { unsafe { processthreadsapi::GetCurrentProcessId() as u32 } }

pub fn handle_from_pid(pid: Pid) -> Option<HANDLE> {
    unsafe {
        let proc_handle = processthreadsapi::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
                                                         | PROCESS_TERMINATE,
                                                         FALSE,
                                                         pid);

        // we expect this to happen if the process died
        // before OpenProcess completes
        if proc_handle == ptr::null_mut() {
            return None;
        } else {
            return Some(proc_handle);
        }
    }
}

/// Determines if a process is running with the given process identifier.
pub fn is_alive(pid: Pid) -> bool {
    match handle_from_pid(pid) {
        Some(handle) => {
            let exit_status = exit_status(handle).expect("Failed to get exit status");
            unsafe {
                let _ = handleapi::CloseHandle(handle);
            }
            exit_status == STILL_ACTIVE
        }
        None => false,
    }
}

/// Executes a command as a child process and exits with the child's exit code.
///
/// Note that if successful, this function will not return.
///
/// # Failures
///
/// * If the child process cannot be created
fn become_child_command(command: PathBuf, args: &[OsString]) -> Result<()> {
    debug!("Calling child process: ({:?}) {:?}",
           command.display(),
           &args);
    let status = Command::new(command).args(args).status()?;
    // Let's honor the exit codes from the child process we finished running
    process::exit(status.code().unwrap())
}

fn exit_status(handle: HANDLE) -> Result<u32> {
    let mut exit_status: u32 = 0;

    unsafe {
        let ret = processthreadsapi::GetExitCodeProcess(handle, &mut exit_status as LPDWORD);
        if ret == 0 {
            return Err(Error::GetExitCodeProcessFailed(format!(
                "Failed to retrieve Exit Code: {}",
                io::Error::last_os_error()
            )));
        }
    }

    Ok(exit_status)
}
<commit_msg>Remove unused SignalCode type alias on Windows<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{ffi::OsString,
          io,
          path::PathBuf,
          process::{self,
                    Command},
          ptr};

use winapi::{shared::minwindef::{DWORD,
                                 FALSE,
                                 LPDWORD},
             um::{handleapi,
                  processthreadsapi,
                  winnt::{HANDLE,
                          PROCESS_QUERY_LIMITED_INFORMATION,
                          PROCESS_TERMINATE}}};

use super::Signal;
use crate::error::{Error,
                   Result};

const STILL_ACTIVE: u32 = 259;

pub type Pid = DWORD;

pub fn become_command(command: PathBuf, args: &[OsString]) -> Result<()> {
    become_child_command(command, args)
}

/// Get process identifier of calling process.
pub fn current_pid() -> u32 { unsafe { processthreadsapi::GetCurrentProcessId() as u32 } }

pub fn handle_from_pid(pid: Pid) -> Option<HANDLE> {
    unsafe {
        let proc_handle = processthreadsapi::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION
                                                         | PROCESS_TERMINATE,
                                                         FALSE,
                                                         pid);

        // we expect this to happen if the process died
        // before OpenProcess completes
        if proc_handle == ptr::null_mut() {
            return None;
        } else {
            return Some(proc_handle);
        }
    }
}

/// Determines if a process is running with the given process identifier.
pub fn is_alive(pid: Pid) -> bool {
    match handle_from_pid(pid) {
        Some(handle) => {
            let exit_status = exit_status(handle).expect("Failed to get exit status");
            unsafe {
                let _ = handleapi::CloseHandle(handle);
            }
            exit_status == STILL_ACTIVE
        }
        None => false,
    }
}

/// Executes a command as a child process and exits with the child's exit code.
///
/// Note that if successful, this function will not return.
///
/// # Failures
///
/// * If the child process cannot be created
fn become_child_command(command: PathBuf, args: &[OsString]) -> Result<()> {
    debug!("Calling child process: ({:?}) {:?}",
           command.display(),
           &args);
    let status = Command::new(command).args(args).status()?;
    // Let's honor the exit codes from the child process we finished running
    process::exit(status.code().unwrap())
}

fn exit_status(handle: HANDLE) -> Result<u32> {
    let mut exit_status: u32 = 0;

    unsafe {
        let ret = processthreadsapi::GetExitCodeProcess(handle, &mut exit_status as LPDWORD);
        if ret == 0 {
            return Err(Error::GetExitCodeProcessFailed(format!(
                "Failed to retrieve Exit Code: {}",
                io::Error::last_os_error()
            )));
        }
    }

    Ok(exit_status)
}
<|endoftext|>


<commit_before>extern crate stdweb;

use std::rc::Rc;

use stdweb::unstable::TryInto;
use stdweb::web::{
    IEventTarget,
    INode,
    HtmlElement,
    document,
    WebSocket,
};

use stdweb::web::event::{
    IEvent,
    IKeyboardEvent,
    IMessageEvent,
    KeyPressEvent,
    SocketOpenEvent,
    SocketCloseEvent,
    SocketErrorEvent,
    SocketMessageEvent,
};

use stdweb::web::html_element::InputElement;

// Shamelessly stolen from webplatform's TodoMVC example.
macro_rules! enclose {
    ( ($( $x:ident ),*) $y:expr ) => {
        {
            $(let $x = $x.clone();)*
            $y
        }
    };
}

fn main() {
    stdweb::initialize();

    let output_div: HtmlElement = document().query_selector( ".output" ).unwrap().try_into().unwrap();
    let output_msg = Rc::new(move |msg: &str| {
        let elem = document().create_element("p");
        elem.set_text_content(msg);
        if let Some(child) = output_div.first_child() {
            output_div.insert_before(&elem, &child);
        } else {
            output_div.append_child(&elem);
        }
    });

    output_msg("> Connecting...");

    let ws = WebSocket::new("wss://echo.websocket.org").unwrap();

    ws.add_event_listener( enclose!( (output_msg) move |_: SocketOpenEvent| {
        output_msg("> Opened connection");
    }));

    ws.add_event_listener( enclose!( (output_msg) move |_: SocketErrorEvent| {
        output_msg("> Connection Errored");
    }));

    ws.add_event_listener( enclose!( (output_msg) move |event: SocketCloseEvent| {
        output_msg(&format!("> Connection Closed: {}", event.reason()));
    }));

    ws.add_event_listener( enclose!( (output_msg) move |event: SocketMessageEvent| {
        output_msg(&event.data().into_text().unwrap());
    }));

    let text_entry: InputElement = document().query_selector( ".form input" ).unwrap().try_into().unwrap();
    text_entry.add_event_listener( enclose!( (text_entry) move |event: KeyPressEvent| {
        if event.key() == "Enter" {
            event.prevent_default();

            let text: String = text_entry.value().try_into().unwrap();
            if text.is_empty() == false {
                text_entry.set_value("");
                ws.send_text(&text);
            }
        }
    }));

    stdweb::event_loop();
}
<commit_msg>Fix `echo` example (#118)<commit_after>extern crate stdweb;

use std::rc::Rc;

use stdweb::unstable::TryInto;
use stdweb::web::{
    IParentNode,
    IEventTarget,
    INode,
    HtmlElement,
    document,
    WebSocket,
};

use stdweb::web::event::{
    IEvent,
    IKeyboardEvent,
    IMessageEvent,
    KeyPressEvent,
    SocketOpenEvent,
    SocketCloseEvent,
    SocketErrorEvent,
    SocketMessageEvent,
};

use stdweb::web::html_element::InputElement;

// Shamelessly stolen from webplatform's TodoMVC example.
macro_rules! enclose {
    ( ($( $x:ident ),*) $y:expr ) => {
        {
            $(let $x = $x.clone();)*
            $y
        }
    };
}

fn main() {
    stdweb::initialize();

    let output_div: HtmlElement = document().query_selector( ".output" ).unwrap().unwrap().try_into().unwrap();
    let output_msg = Rc::new(move |msg: &str| {
        let elem = document().create_element("p").unwrap();
        elem.set_text_content(msg);
        if let Some(child) = output_div.first_child() {
            output_div.insert_before(&elem, &child);
        } else {
            output_div.append_child(&elem);
        }
    });

    output_msg("> Connecting...");

    let ws = WebSocket::new("wss://echo.websocket.org").unwrap();

    ws.add_event_listener( enclose!( (output_msg) move |_: SocketOpenEvent| {
        output_msg("> Opened connection");
    }));

    ws.add_event_listener( enclose!( (output_msg) move |_: SocketErrorEvent| {
        output_msg("> Connection Errored");
    }));

    ws.add_event_listener( enclose!( (output_msg) move |event: SocketCloseEvent| {
        output_msg(&format!("> Connection Closed: {}", event.reason()));
    }));

    ws.add_event_listener( enclose!( (output_msg) move |event: SocketMessageEvent| {
        output_msg(&event.data().into_text().unwrap());
    }));

    let text_entry: InputElement = document().query_selector( ".form input" ).unwrap().unwrap().try_into().unwrap();
    text_entry.add_event_listener( enclose!( (text_entry) move |event: KeyPressEvent| {
        if event.key() == "Enter" {
            event.prevent_default();

            let text: String = text_entry.value().try_into().unwrap();
            if text.is_empty() == false {
                text_entry.set_value("");
                ws.send_text(&text);
            }
        }
    }));

    stdweb::event_loop();
}
<|endoftext|>