<commit_before>use rustbox::Color;
use rustbox::Key;
use rustbox::{RB_BOLD, RB_NORMAL};

use crate::game;
use crate::lila;

use super::MenuResult;
use super::RBStyle;
use super::Renderer;
use super::View;

pub struct GameView {
    name: String,
    pub pov: game::ConnectedPov,
    pub input: Vec<char>,
}

impl GameView {
    pub fn new(session: &lila::Session, name: String, url: String) -> GameView {
        let connected_pov = game::ConnectedPov::new(session, &url);

        return GameView {
            name: name,
            pov: connected_pov,
            input: vec!(),
        };
    }

    fn handle_input(&mut self) {
        if self.input.len() == 4 { // assume move for now
            let from: String = self.input[0..2].iter().cloned().collect();
            let to: String = self.input[2..4].iter().cloned().collect();
            self.pov.send_move(from, to);
            self.input.clear();
        }
    }

    pub fn render_latency(&self, r: &mut Renderer, x: usize, y: usize, latency: &game::LatencyRecorder) {
        let style = RBStyle { style: RB_NORMAL, fg: Color::Cyan, bg: Color::Black };
        r.print(x, y+13, style, &format!("{:3}ms", latency.average()));
    }

    pub fn render_pov(&self, r: &mut Renderer, x: usize, y: usize, pov: &game::Pov) {
        if let Some(crowd) = &pov.crowd {
            let opponent_present = crowd.opponent_from(pov.orientation());
            let player_present = crowd.player_from(pov.orientation());
            self.render_player(r, x + 1, y + 2, &pov.opponent, opponent_present);
            self.render_player(r, x + 1, y + 14, &pov.player, player_present);
            self.render_watchers(r, x + 1, y + 18, &crowd);
        } else {
            self.render_player(r, x + 1, y + 2, &pov.opponent, true);
            self.render_player(r, x + 1, y + 14, &pov.player, true);
        }
        let fen = pov.game.fen.clone();
        self.render_fen(r, x, y, fen, pov.orientation() == game::Color::white, &pov.game);
        match pov.clock {
            Some(ref clock) => {
                self.render_clock(r, x + 19, y + 3, clock.from(!pov.orientation()));
                self.render_clock(r, x + 19, y + 12, clock.from(pov.orientation()));
            },
            None => ()
        };
        if pov.movable() {
            let style = RBStyle { style: RB_BOLD, fg: Color::White, bg: Color::Black };
            r.print(5, 16, style, &format!("Move {}▍          ", self.input.iter().cloned().collect::<String>()));
        }
        self.render_last_move(r, x + 26, y + 12, &pov.game);
    }

    pub fn render_player(&self, r: &mut Renderer, x: usize, y: usize, player: &game::Player, present: bool) {
        let style = RBStyle { style: RB_BOLD, fg: Color::White, bg: Color::Black };
        let style_absent = RBStyle { style: RB_BOLD, fg: Color::Red, bg: Color::Black };
        r.print(x, y, style, &format!("{:4}", player.rating.unwrap_or(1500)));
        match player.user {
            Some(ref user) => {
                r.print(x + 5, y,  if present { style } else { style_absent }, &format!("{}", user.username));
            },
            None => ()
        };
    }

    pub fn render_watchers(&self, r: &mut Renderer, x: usize, y: usize, crowd: &game::Crowd) {
        let style = RBStyle { style: RB_BOLD, fg: Color::White, bg: Color::Black };
        r.print(x, y, style, &format!("Watchers: {:4}", crowd.watchers.nb));
        if let Some(anons) = &crowd.watchers.anons {
            r.print(x, y + 1, style, &format!("Anonymous: {:3}", anons));
        }
        if let Some(users) = &crowd.watchers.users {
            for (i, user) in users.iter().enumerate() {
                r.print(x, y + 2 + i, style, &format!("{}", user));
            }
        }

    }

    pub fn render_last_move(&self, r: &mut Renderer, x: usize, y: usize, game: &game::Game) {
        let color = if game.player == game::Color::black {
            RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: Color::Black }
        } else {
            RBStyle { style: RB_BOLD, fg: Color::Blue, bg: Color::Black }
        };
        r.print(x, y, color, &format!("{}           ", game.lastMoveSan.as_ref().unwrap_or(&"".to_string())));
    }

    pub fn render_clock(&self, r: &mut Renderer, x: usize, y: usize, time: f64) {
        r.print(x, y, RBStyle { style: RB_BOLD, fg: if time < 10f64 { Color::Red } else { Color::White }, bg: Color::Black }, &format!("{:04.1}", time));
    }

    fn highlighed(san: &Option<String>, x: usize, y: usize) -> bool {
        if let Some(san) = san {
            let san = san
                .replace("a", "1")
                .replace("b", "2")
                .replace("c", "3")
                .replace("d", "4")
                .replace("e", "5")
                .replace("f", "6")
                .replace("g", "7")
                .replace("h", "8");
            if san[0..2] == format!("{}{}", x, y) || san[2..4] == format!("{}{}", x, y) {
                return true;
            }
        }
        false
    }

    pub fn render_fen(&self, r: &mut Renderer, x: usize, y: usize, fen: String, orientation: bool, game: &game::Game) {
        let _text_style  = RBStyle { style: RB_BOLD, fg: Color::White, bg:    Color::Black };
        let border      = RBStyle { style: RB_NORMAL, fg: Color::Cyan, bg:   Color::Black };

        //r.print(x + 3, y +  1, text_style, &fen);
        r.print(x + 5, y +  3, border, "╔═════════════════╗");
        r.print(x + 5, y + 12, border, "╚═════════════════╝");
        if orientation {
            r.print(x + 7, y + 13, border,   "a b c d e f g h");
        } else {
            r.print(x + 7, y + 13, border,   "h g f e d c b a");
        }

        // TODO: fen parser
        // r1bqkb1r/ppp1pppp/2n2n2/3p4/4P3/3P1P2/PPP3PP/RNBQKBNR w KQkq - 1 4
        let mut fen = fen.split(' ').next().unwrap().to_string();
        if !orientation {
            fen = fen.chars().rev().collect();
        }
        for (y2, row) in fen.split('/').enumerate() {
            if y2 >= 8 {
                break; // temp workaround for crazyhouse
            }
            let row = row
                .replace("8", "········")
                .replace("7", "·······")
                .replace("6", "······")
                .replace("5", "·····")
                .replace("4", "····")
                .replace("3", "···")
                .replace("2", "··")
                .replace("1", "·");
            if orientation {
                r.print(x + 3, 4 + y + y2, border, &format!("{} ║", 9-(y2+1)));
            } else {
                r.print(x + 3, 4 + y + y2, border, &format!("{} ║", y2+1));
            }
            r.print(x + 23, 4 + y + y2, border, "║");
            for (x2, char) in row.chars().enumerate() {
                let (san_x, san_y) = if orientation {
                    (x2 + 1, 9 - (y2 + 1))
                } else {
                    (9 - (x2 + 1), y2 + 1)
                };
                let bg = if Self::highlighed(&game.lastMove, san_x, san_y) {
                    Color::Magenta
                } else {
                    Color::Black
                };
                let color = if char == '·' {
                    if (y2 + x2) % 2 == 0 {
                        RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: bg }
                    } else {
                        RBStyle { style: RB_BOLD, fg: Color::Blue, bg: bg }
                    }
                } else {
                    if char.is_uppercase() {
                        RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: bg }
                    } else {
                        RBStyle { style: RB_BOLD, fg: Color::Blue, bg: bg }
                    }
                };
                r.print(7 + x + x2*2, 4 + y + y2, color, &char.to_uppercase().collect::<String>());
            }
        }
    }
}

impl View for GameView {
    fn tick(&mut self) {
        self.pov.pov.lock().ok().map(|mut p| {
            p.tick();
        });
    }

    fn render(&self, r: &mut Renderer) {
        self.pov.latency.lock().ok().map(|l| self.render_latency(r, 0, 0, &l));
        self.pov.pov.lock().ok().map(|p| self.render_pov(r, 0, 0, &p));
    }

    fn name(&self) -> String {
        self.name.to_owned()
    }

    fn key_event(&mut self, key: Key) -> MenuResult {
        match key {
            Key::Enter => {
                self.handle_input();
            }
            Key::Char(x) => {
                self.input.push(x);
            }
            Key::Backspace => {
                self.input.pop();
            }
            _ => ()
        }
        MenuResult::None
    }
}
<commit_msg>use last move from uci when san is missing<commit_after>use rustbox::Color;
use rustbox::Key;
use rustbox::{RB_BOLD, RB_NORMAL};

use crate::game;
use crate::lila;

use super::MenuResult;
use super::RBStyle;
use super::Renderer;
use super::View;

pub struct GameView {
    name: String,
    pub pov: game::ConnectedPov,
    pub input: Vec<char>,
}

impl GameView {
    pub fn new(session: &lila::Session, name: String, url: String) -> GameView {
        let connected_pov = game::ConnectedPov::new(session, &url);

        return GameView {
            name: name,
            pov: connected_pov,
            input: vec!(),
        };
    }

    fn handle_input(&mut self) {
        if self.input.len() == 4 { // assume move for now
            let from: String = self.input[0..2].iter().cloned().collect();
            let to: String = self.input[2..4].iter().cloned().collect();
            self.pov.send_move(from, to);
            self.input.clear();
        }
    }

    pub fn render_latency(&self, r: &mut Renderer, x: usize, y: usize, latency: &game::LatencyRecorder) {
        let style = RBStyle { style: RB_NORMAL, fg: Color::Cyan, bg: Color::Black };
        r.print(x, y+13, style, &format!("{:3}ms", latency.average()));
    }

    pub fn render_pov(&self, r: &mut Renderer, x: usize, y: usize, pov: &game::Pov) {
        if let Some(crowd) = &pov.crowd {
            let opponent_present = crowd.opponent_from(pov.orientation());
            let player_present = crowd.player_from(pov.orientation());
            self.render_player(r, x + 1, y + 2, &pov.opponent, opponent_present);
            self.render_player(r, x + 1, y + 14, &pov.player, player_present);
            self.render_watchers(r, x + 1, y + 18, &crowd);
        } else {
            self.render_player(r, x + 1, y + 2, &pov.opponent, true);
            self.render_player(r, x + 1, y + 14, &pov.player, true);
        }
        let fen = pov.game.fen.clone();
        self.render_fen(r, x, y, fen, pov.orientation() == game::Color::white, &pov.game);
        match pov.clock {
            Some(ref clock) => {
                self.render_clock(r, x + 19, y + 3, clock.from(!pov.orientation()));
                self.render_clock(r, x + 19, y + 12, clock.from(pov.orientation()));
            },
            None => ()
        };
        if pov.movable() {
            let style = RBStyle { style: RB_BOLD, fg: Color::White, bg: Color::Black };
            r.print(5, 16, style, &format!("Move {}▍          ", self.input.iter().cloned().collect::<String>()));
        }
        self.render_last_move(r, x + 26, y + 12, &pov.game);
    }

    pub fn render_player(&self, r: &mut Renderer, x: usize, y: usize, player: &game::Player, present: bool) {
        let style = RBStyle { style: RB_BOLD, fg: Color::White, bg: Color::Black };
        let style_absent = RBStyle { style: RB_BOLD, fg: Color::Red, bg: Color::Black };
        r.print(x, y, style, &format!("{:4}", player.rating.unwrap_or(1500)));
        match player.user {
            Some(ref user) => {
                r.print(x + 5, y,  if present { style } else { style_absent }, &format!("{}", user.username));
            },
            None => ()
        };
    }

    pub fn render_watchers(&self, r: &mut Renderer, x: usize, y: usize, crowd: &game::Crowd) {
        let style = RBStyle { style: RB_BOLD, fg: Color::White, bg: Color::Black };
        r.print(x, y, style, &format!("Watchers: {:4}", crowd.watchers.nb));
        if let Some(anons) = &crowd.watchers.anons {
            r.print(x, y + 1, style, &format!("Anonymous: {:3}", anons));
        }
        if let Some(users) = &crowd.watchers.users {
            for (i, user) in users.iter().enumerate() {
                r.print(x, y + 2 + i, style, &format!("{}", user));
            }
        }

    }

    pub fn render_last_move(&self, r: &mut Renderer, x: usize, y: usize, game: &game::Game) {
        let color = if game.player == game::Color::black {
            RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: Color::Black }
        } else {
            RBStyle { style: RB_BOLD, fg: Color::Blue, bg: Color::Black }
        };
        r.print(x, y, color, &format!("{}           ", game.lastMoveSan.as_ref().or(game.lastMove.as_ref()).unwrap_or(&"".to_string())));
    }

    pub fn render_clock(&self, r: &mut Renderer, x: usize, y: usize, time: f64) {
        r.print(x, y, RBStyle { style: RB_BOLD, fg: if time < 10f64 { Color::Red } else { Color::White }, bg: Color::Black }, &format!("{:04.1}", time));
    }

    fn highlighed(uci: &Option<String>, x: usize, y: usize) -> bool {
        if let Some(uci) = uci {
            let uci = uci
                .replace("a", "1")
                .replace("b", "2")
                .replace("c", "3")
                .replace("d", "4")
                .replace("e", "5")
                .replace("f", "6")
                .replace("g", "7")
                .replace("h", "8");
            if uci[0..2] == format!("{}{}", x, y) || uci[2..4] == format!("{}{}", x, y) {
                return true;
            }
        }
        false
    }

    pub fn render_fen(&self, r: &mut Renderer, x: usize, y: usize, fen: String, orientation: bool, game: &game::Game) {
        let _text_style  = RBStyle { style: RB_BOLD, fg: Color::White, bg:    Color::Black };
        let border      = RBStyle { style: RB_NORMAL, fg: Color::Cyan, bg:   Color::Black };

        //r.print(x + 3, y +  1, text_style, &fen);
        r.print(x + 5, y +  3, border, "╔═════════════════╗");
        r.print(x + 5, y + 12, border, "╚═════════════════╝");
        if orientation {
            r.print(x + 7, y + 13, border,   "a b c d e f g h");
        } else {
            r.print(x + 7, y + 13, border,   "h g f e d c b a");
        }

        // TODO: fen parser
        // r1bqkb1r/ppp1pppp/2n2n2/3p4/4P3/3P1P2/PPP3PP/RNBQKBNR w KQkq - 1 4
        let mut fen = fen.split(' ').next().unwrap().to_string();
        if !orientation {
            fen = fen.chars().rev().collect();
        }
        for (y2, row) in fen.split('/').enumerate() {
            if y2 >= 8 {
                break; // temp workaround for crazyhouse
            }
            let row = row
                .replace("8", "········")
                .replace("7", "·······")
                .replace("6", "······")
                .replace("5", "·····")
                .replace("4", "····")
                .replace("3", "···")
                .replace("2", "··")
                .replace("1", "·");
            if orientation {
                r.print(x + 3, 4 + y + y2, border, &format!("{} ║", 9-(y2+1)));
            } else {
                r.print(x + 3, 4 + y + y2, border, &format!("{} ║", y2+1));
            }
            r.print(x + 23, 4 + y + y2, border, "║");
            for (x2, char) in row.chars().enumerate() {
                let (uci_x, uci_y) = if orientation {
                    (x2 + 1, 9 - (y2 + 1))
                } else {
                    (9 - (x2 + 1), y2 + 1)
                };
                let bg = if Self::highlighed(&game.lastMove, uci_x, uci_y) {
                    Color::Magenta
                } else {
                    Color::Black
                };
                let color = if char == '·' {
                    if (y2 + x2) % 2 == 0 {
                        RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: bg }
                    } else {
                        RBStyle { style: RB_BOLD, fg: Color::Blue, bg: bg }
                    }
                } else {
                    if char.is_uppercase() {
                        RBStyle { style: RB_NORMAL, fg: Color::Yellow, bg: bg }
                    } else {
                        RBStyle { style: RB_BOLD, fg: Color::Blue, bg: bg }
                    }
                };
                r.print(7 + x + x2*2, 4 + y + y2, color, &char.to_uppercase().collect::<String>());
            }
        }
    }
}

impl View for GameView {
    fn tick(&mut self) {
        self.pov.pov.lock().ok().map(|mut p| {
            p.tick();
        });
    }

    fn render(&self, r: &mut Renderer) {
        self.pov.latency.lock().ok().map(|l| self.render_latency(r, 0, 0, &l));
        self.pov.pov.lock().ok().map(|p| self.render_pov(r, 0, 0, &p));
    }

    fn name(&self) -> String {
        self.name.to_owned()
    }

    fn key_event(&mut self, key: Key) -> MenuResult {
        match key {
            Key::Enter => {
                self.handle_input();
            }
            Key::Char(x) => {
                self.input.push(x);
            }
            Key::Backspace => {
                self.input.pop();
            }
            _ => ()
        }
        MenuResult::None
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::path::PathBuf;
use std::sync::Arc;

use filemap::{FileMap, FileName};
use index::{ByteIndex, ByteOffset};

#[derive(Debug)]
pub struct CodeMap {
    files: Vec<Arc<FileMap>>,
}

impl CodeMap {
    /// Creates an empty `CodeMap`.
    pub fn new() -> CodeMap {
        CodeMap { files: Vec::new() }
    }

    /// The next start index to use for a new filemap
    fn next_start_index(&self) -> ByteIndex {
        let end_index = self.files
            .last()
            .map(|x| x.span().end())
            .unwrap_or(ByteIndex::none());

        // Add one byte of padding between each file
        end_index + ByteOffset(1)
    }

    /// Adds a filemap to the codemap with the given name and source string
    pub fn add_filemap(&mut self, name: FileName, src: String) -> Arc<FileMap> {
        let file = Arc::new(FileMap::new(name, src, self.next_start_index()));
        self.files.push(file.clone());
        file
    }

    /// Adds a filemap to the codemap with the given name and source string
    pub fn add_filemap_from_disk<P: Into<PathBuf>>(&mut self, name: P) -> io::Result<Arc<FileMap>> {
        let file = Arc::new(FileMap::from_disk(name, self.next_start_index())?);
        self.files.push(file.clone());
        Ok(file)
    }

    /// Looks up the `File` that contains the specified byte index.
    pub fn find_file(&self, index: ByteIndex) -> Option<&Arc<FileMap>> {
        use std::cmp::Ordering;

        self.files
            .binary_search_by(|file| match () {
                () if file.span().start() > index => Ordering::Greater,
                () if file.span().end() < index => Ordering::Less,
                () => Ordering::Equal,
            })
            .ok()
            .map(|i| &self.files[i])
    }
}
<commit_msg>Derive Default for CodeMap.<commit_after>use std::io;
use std::path::PathBuf;
use std::sync::Arc;

use filemap::{FileMap, FileName};
use index::{ByteIndex, ByteOffset};

#[derive(Debug, Default)]
pub struct CodeMap {
    files: Vec<Arc<FileMap>>,
}

impl CodeMap {
    /// Creates an empty `CodeMap`.
    pub fn new() -> CodeMap {
        CodeMap::default()
    }

    /// The next start index to use for a new filemap
    fn next_start_index(&self) -> ByteIndex {
        let end_index = self.files
            .last()
            .map(|x| x.span().end())
            .unwrap_or(ByteIndex::none());

        // Add one byte of padding between each file
        end_index + ByteOffset(1)
    }

    /// Adds a filemap to the codemap with the given name and source string
    pub fn add_filemap(&mut self, name: FileName, src: String) -> Arc<FileMap> {
        let file = Arc::new(FileMap::new(name, src, self.next_start_index()));
        self.files.push(file.clone());
        file
    }

    /// Adds a filemap to the codemap with the given name and source string
    pub fn add_filemap_from_disk<P: Into<PathBuf>>(&mut self, name: P) -> io::Result<Arc<FileMap>> {
        let file = Arc::new(FileMap::from_disk(name, self.next_start_index())?);
        self.files.push(file.clone());
        Ok(file)
    }

    /// Looks up the `File` that contains the specified byte index.
    pub fn find_file(&self, index: ByteIndex) -> Option<&Arc<FileMap>> {
        use std::cmp::Ordering;

        self.files
            .binary_search_by(|file| match () {
                () if file.span().start() > index => Ordering::Greater,
                () if file.span().end() < index => Ordering::Less,
                () => Ordering::Equal,
            })
            .ok()
            .map(|i| &self.files[i])
    }
}
<|endoftext|>


<commit_before>macro_rules! impl_integer_reductions {
    { $name:ident, $scalar:ty } => {
        impl<const LANES: usize> crate::$name<LANES>
        where
            Self: crate::LanesAtMost32
        {
            /// Produces the sum of the lanes of the vector, with wrapping addition.
            #[inline]
            pub fn wrapping_sum(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_add_ordered(self, 0) }
            }

            /// Produces the sum of the lanes of the vector, with wrapping multiplication.
            #[inline]
            pub fn wrapping_product(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_mul_ordered(self, 1) }
            }

            /// Sequentially performs bitwise "and" between the lanes of the vector.
            #[inline]
            pub fn and_lanes(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_and(self) }
            }

            /// Sequentially performs bitwise "or" between the lanes of the vector.
            #[inline]
            pub fn or_lanes(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_or(self) }
            }

            /// Sequentially performs bitwise "xor" between the lanes of the vector.
            #[inline]
            pub fn xor_lanes(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_xor(self) }
            }

            /// Returns the maximum lane in the vector.
            #[inline]
            pub fn max_lane(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_max(self) }
            }

            /// Returns the minimum lane in the vector.
            #[inline]
            pub fn min_lane(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_min(self) }
            }
        }
    }
}

macro_rules! impl_float_reductions {
    { $name:ident, $scalar:ty } => {
        impl<const LANES: usize> crate::$name<LANES>
        where
            Self: crate::LanesAtMost32
        {
            /// Produces the sum of the lanes of the vector.
            #[inline]
            pub fn sum(self) -> $scalar {
                // f32 SIMD sum is inaccurate on i586
                if cfg!(target_arch = "i586") && core::mem::size_of::<$scalar>() == 4 {
                    self.as_slice().iter().sum()
                } else {
                    unsafe { crate::intrinsics::simd_reduce_add_ordered(self, 0.) }
                }
            }

            /// Produces the sum of the lanes of the vector.
            #[inline]
            pub fn product(self) -> $scalar {
                // f32 SIMD product is inaccurate on i586
                if cfg!(target_arch = "i586") && core::mem::size_of::<$scalar>() == 4 {
                    self.as_slice().iter().product()
                } else {
                    unsafe { crate::intrinsics::simd_reduce_mul_ordered(self, 1.) }
                }
            }

            /// Returns the maximum lane in the vector.
            ///
            /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
            /// return either.  This function will not return `NaN` unless all lanes are `NaN`.
            #[inline]
            pub fn max_lane(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_max(self) }
            }

            /// Returns the minimum lane in the vector.
            ///
            /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
            /// return either.  This function will not return `NaN` unless all lanes are `NaN`.
            #[inline]
            pub fn min_lane(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_min(self) }
            }
        }
    }
}

macro_rules! impl_full_mask_reductions {
    { $name:ident, $inner:ident } => {
        impl<const LANES: usize> crate::$name<LANES>
        where
            crate::$inner<LANES>: crate::LanesAtMost32
        {
            /// Returns true if any lane is set, or false otherwise.
            #[inline]
            pub fn any(self) -> bool {
                unsafe { crate::intrinsics::simd_reduce_any(self.to_int()) }
            }

            /// Returns true if all lanes are set, or false otherwise.
            #[inline]
            pub fn all(self) -> bool {
                unsafe { crate::intrinsics::simd_reduce_all(self.to_int()) }
            }
        }
    }
}

macro_rules! impl_opaque_mask_reductions {
    { $name:ident, $inner:ident, $bits_ty:ident } => {
        impl<const LANES: usize> $name<LANES>
        where
            $bits_ty<LANES>: crate::LanesAtMost32
        {
            /// Returns true if any lane is set, or false otherwise.
            #[inline]
            pub fn any(self) -> bool {
                self.0.any()
            }

            /// Returns true if all lanes are set, or false otherwise.
            #[inline]
            pub fn all(self) -> bool {
                self.0.all()
            }
        }
    }
}

impl<const LANES: usize> crate::BitMask<LANES>
where
    crate::BitMask<LANES>: crate::LanesAtMost32,
{
    /// Returns true if any lane is set, or false otherwise.
    #[inline]
    pub fn any(self) -> bool {
        self != Self::splat(false)
    }

    /// Returns true if all lanes are set, or false otherwise.
    #[inline]
    pub fn all(self) -> bool {
        self == Self::splat(true)
    }
}
<commit_msg>Fix i586 detection<commit_after>macro_rules! impl_integer_reductions {
    { $name:ident, $scalar:ty } => {
        impl<const LANES: usize> crate::$name<LANES>
        where
            Self: crate::LanesAtMost32
        {
            /// Produces the sum of the lanes of the vector, with wrapping addition.
            #[inline]
            pub fn wrapping_sum(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_add_ordered(self, 0) }
            }

            /// Produces the sum of the lanes of the vector, with wrapping multiplication.
            #[inline]
            pub fn wrapping_product(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_mul_ordered(self, 1) }
            }

            /// Sequentially performs bitwise "and" between the lanes of the vector.
            #[inline]
            pub fn and_lanes(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_and(self) }
            }

            /// Sequentially performs bitwise "or" between the lanes of the vector.
            #[inline]
            pub fn or_lanes(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_or(self) }
            }

            /// Sequentially performs bitwise "xor" between the lanes of the vector.
            #[inline]
            pub fn xor_lanes(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_xor(self) }
            }

            /// Returns the maximum lane in the vector.
            #[inline]
            pub fn max_lane(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_max(self) }
            }

            /// Returns the minimum lane in the vector.
            #[inline]
            pub fn min_lane(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_min(self) }
            }
        }
    }
}

macro_rules! impl_float_reductions {
    { $name:ident, $scalar:ty } => {
        impl<const LANES: usize> crate::$name<LANES>
        where
            Self: crate::LanesAtMost32
        {

            /// Produces the sum of the lanes of the vector.
            #[inline]
            pub fn sum(self) -> $scalar {
                // f32 SIMD sum is inaccurate on i586
                if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && core::mem::size_of::<$scalar>() == 4 {
                    self.as_slice().iter().sum()
                } else {
                    unsafe { crate::intrinsics::simd_reduce_add_ordered(self, 0.) }
                }
            }

            /// Produces the sum of the lanes of the vector.
            #[inline]
            pub fn product(self) -> $scalar {
                // f32 SIMD product is inaccurate on i586
                if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) && core::mem::size_of::<$scalar>() == 4 {
                    self.as_slice().iter().product()
                } else {
                    unsafe { crate::intrinsics::simd_reduce_mul_ordered(self, 1.) }
                }
            }

            /// Returns the maximum lane in the vector.
            ///
            /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
            /// return either.  This function will not return `NaN` unless all lanes are `NaN`.
            #[inline]
            pub fn max_lane(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_max(self) }
            }

            /// Returns the minimum lane in the vector.
            ///
            /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
            /// return either.  This function will not return `NaN` unless all lanes are `NaN`.
            #[inline]
            pub fn min_lane(self) -> $scalar {
                unsafe { crate::intrinsics::simd_reduce_min(self) }
            }
        }
    }
}

macro_rules! impl_full_mask_reductions {
    { $name:ident, $inner:ident } => {
        impl<const LANES: usize> crate::$name<LANES>
        where
            crate::$inner<LANES>: crate::LanesAtMost32
        {
            /// Returns true if any lane is set, or false otherwise.
            #[inline]
            pub fn any(self) -> bool {
                unsafe { crate::intrinsics::simd_reduce_any(self.to_int()) }
            }

            /// Returns true if all lanes are set, or false otherwise.
            #[inline]
            pub fn all(self) -> bool {
                unsafe { crate::intrinsics::simd_reduce_all(self.to_int()) }
            }
        }
    }
}

macro_rules! impl_opaque_mask_reductions {
    { $name:ident, $inner:ident, $bits_ty:ident } => {
        impl<const LANES: usize> $name<LANES>
        where
            $bits_ty<LANES>: crate::LanesAtMost32
        {
            /// Returns true if any lane is set, or false otherwise.
            #[inline]
            pub fn any(self) -> bool {
                self.0.any()
            }

            /// Returns true if all lanes are set, or false otherwise.
            #[inline]
            pub fn all(self) -> bool {
                self.0.all()
            }
        }
    }
}

impl<const LANES: usize> crate::BitMask<LANES>
where
    crate::BitMask<LANES>: crate::LanesAtMost32,
{
    /// Returns true if any lane is set, or false otherwise.
    #[inline]
    pub fn any(self) -> bool {
        self != Self::splat(false)
    }

    /// Returns true if all lanes are set, or false otherwise.
    #[inline]
    pub fn all(self) -> bool {
        self == Self::splat(true)
    }
}
<|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(libc, path, rustc_private, thread_local)]

#[macro_use]
extern crate log;

extern crate compositing;
extern crate devtools;
extern crate net;
extern crate msg;
#[macro_use]
extern crate util;
extern crate script;
extern crate layout;
extern crate gfx;
extern crate libc;
extern crate url;

use compositing::CompositorEventListener;
use compositing::windowing::{WindowEvent, WindowMethods};

#[cfg(not(test))]
use compositing::{CompositorProxy, CompositorTask, Constellation};
#[cfg(not(test))]
use msg::constellation_msg::Msg as ConstellationMsg;
#[cfg(not(test))]
use msg::constellation_msg::ConstellationChan;
#[cfg(not(test))]
use script::dom::bindings::codegen::RegisterBindings;

#[cfg(not(test))]
use net::image_cache_task::ImageCacheTask;
#[cfg(not(test))]
use net::resource_task::new_resource_task;
#[cfg(not(test))]
use net::storage_task::{StorageTaskFactory, StorageTask};
#[cfg(not(test))]
use gfx::font_cache_task::FontCacheTask;
#[cfg(not(test))]
use util::time::TimeProfiler;
#[cfg(not(test))]
use util::memory::MemoryProfiler;
#[cfg(not(test))]
use util::opts;
#[cfg(not(test))]
use util::taskpool::TaskPool;

#[cfg(not(test))]
use std::rc::Rc;
#[cfg(not(test))]
use std::sync::mpsc::channel;
#[cfg(not(test))]
use std::thread::Builder;

pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

impl Browser  {
    #[cfg(not(test))]
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
    where Window: WindowMethods + 'static {
        use std::env;

        ::util::opts::set_experimental_enabled(opts::get().enable_experimental);
        let opts = opts::get();
        RegisterBindings::RegisterProxyHandlers();

        let shared_task_pool = TaskPool::new(8);

        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let time_profiler_chan = TimeProfiler::create(opts.time_profiler_period);
        let memory_profiler_chan = MemoryProfiler::create(opts.memory_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        let opts_clone = opts.clone();
        let time_profiler_chan_clone = time_profiler_chan.clone();
        let memory_profiler_chan_clone = memory_profiler_chan.clone();

        let (result_chan, result_port) = channel();
        let compositor_proxy_for_constellation = compositor_proxy.clone_compositor_proxy();
        Builder::new()
            .spawn(move || {
            let opts = &opts_clone;
            // Create a Servo instance.
            let resource_task = new_resource_task(opts.user_agent.clone());
            // If we are emitting an output file, then we need to block on
            // image load or we risk emitting an output file missing the
            // image.
            let image_cache_task = if opts.output_file.is_some() {
                ImageCacheTask::new_sync(resource_task.clone(), shared_task_pool,
                                         time_profiler_chan_clone.clone())
            } else {
                ImageCacheTask::new(resource_task.clone(), shared_task_pool,
                                    time_profiler_chan_clone.clone())
            };
            let font_cache_task = FontCacheTask::new(resource_task.clone());
            let storage_task: StorageTask = StorageTaskFactory::new();
            let constellation_chan = Constellation::<layout::layout_task::LayoutTask,
                                                     script::script_task::ScriptTask>::start(
                                                          compositor_proxy_for_constellation,
                                                          resource_task,
                                                          image_cache_task,
                                                          font_cache_task,
                                                          time_profiler_chan_clone,
                                                          memory_profiler_chan_clone,
                                                          devtools_chan,
                                                          storage_task);

            // Send the URL command to the constellation.
            let cwd = env::current_dir().unwrap();
            for url in opts.urls.iter() {
                let url = match url::Url::parse(&*url) {
                    Ok(url) => url,
                    Err(url::ParseError::RelativeUrlWithoutBase)
                    => url::Url::from_file_path(&*cwd.join(&*url)).unwrap(),
                    Err(_) => panic!("URL parsing failed"),
                };

                let ConstellationChan(ref chan) = constellation_chan;
                chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap();
            }

            // Send the constallation Chan as the result
            result_chan.send(constellation_chan).unwrap();
        });

        let constellation_chan = result_port.recv().unwrap();

        debug!("preparing to enter main loop");
        let compositor = CompositorTask::create(window,
                                                compositor_proxy,
                                                compositor_receiver,
                                                constellation_chan,
                                                time_profiler_chan,
                                                memory_profiler_chan);

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_event(&mut self, event: WindowEvent) -> bool {
        self.compositor.handle_event(event)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn get_title_for_main_frame(&self) {
        self.compositor.get_title_for_main_frame()
    }

    pub fn shutdown(mut self) {
        self.compositor.shutdown();
    }
}

<commit_msg>auto merge of #5308 : Ms2ger/servo/main-spawn, r=jdm<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(libc, path, rustc_private, thread_local)]

#[macro_use]
extern crate log;

extern crate compositing;
extern crate devtools;
extern crate net;
extern crate msg;
#[macro_use]
extern crate util;
extern crate script;
extern crate layout;
extern crate gfx;
extern crate libc;
extern crate url;

use compositing::CompositorEventListener;
use compositing::windowing::{WindowEvent, WindowMethods};

#[cfg(not(test))]
use compositing::{CompositorProxy, CompositorTask, Constellation};
#[cfg(not(test))]
use msg::constellation_msg::Msg as ConstellationMsg;
#[cfg(not(test))]
use msg::constellation_msg::ConstellationChan;
#[cfg(not(test))]
use script::dom::bindings::codegen::RegisterBindings;

#[cfg(not(test))]
use net::image_cache_task::ImageCacheTask;
#[cfg(not(test))]
use net::resource_task::new_resource_task;
#[cfg(not(test))]
use net::storage_task::{StorageTaskFactory, StorageTask};
#[cfg(not(test))]
use gfx::font_cache_task::FontCacheTask;
#[cfg(not(test))]
use util::time::TimeProfiler;
#[cfg(not(test))]
use util::memory::MemoryProfiler;
#[cfg(not(test))]
use util::opts;
#[cfg(not(test))]
use util::taskpool::TaskPool;

#[cfg(not(test))]
use std::rc::Rc;

pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

impl Browser  {
    #[cfg(not(test))]
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
    where Window: WindowMethods + 'static {
        use std::env;

        ::util::opts::set_experimental_enabled(opts::get().enable_experimental);
        let opts = opts::get();
        RegisterBindings::RegisterProxyHandlers();

        let shared_task_pool = TaskPool::new(8);

        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let time_profiler_chan = TimeProfiler::create(opts.time_profiler_period);
        let memory_profiler_chan = MemoryProfiler::create(opts.memory_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        // Create a Servo instance.
        let resource_task = new_resource_task(opts.user_agent.clone());

        // If we are emitting an output file, then we need to block on
        // image load or we risk emitting an output file missing the
        // image.
        let image_cache_task = if opts.output_file.is_some() {
            ImageCacheTask::new_sync(resource_task.clone(), shared_task_pool,
                                     time_profiler_chan.clone())
        } else {
            ImageCacheTask::new(resource_task.clone(), shared_task_pool,
                                time_profiler_chan.clone())
        };

        let font_cache_task = FontCacheTask::new(resource_task.clone());
        let storage_task: StorageTask = StorageTaskFactory::new();

        let constellation_chan = Constellation::<layout::layout_task::LayoutTask,
                                                 script::script_task::ScriptTask>::start(
                                                      compositor_proxy.clone_compositor_proxy(),
                                                      resource_task,
                                                      image_cache_task,
                                                      font_cache_task,
                                                      time_profiler_chan.clone(),
                                                      memory_profiler_chan.clone(),
                                                      devtools_chan,
                                                      storage_task);

        // Send the URL command to the constellation.
        let cwd = env::current_dir().unwrap();
        for url in opts.urls.iter() {
            let url = match url::Url::parse(&*url) {
                Ok(url) => url,
                Err(url::ParseError::RelativeUrlWithoutBase)
                => url::Url::from_file_path(&*cwd.join(&*url)).unwrap(),
                Err(_) => panic!("URL parsing failed"),
            };

            let ConstellationChan(ref chan) = constellation_chan;
            chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap();
        }

        debug!("preparing to enter main loop");
        let compositor = CompositorTask::create(window,
                                                compositor_proxy,
                                                compositor_receiver,
                                                constellation_chan,
                                                time_profiler_chan,
                                                memory_profiler_chan);

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_event(&mut self, event: WindowEvent) -> bool {
        self.compositor.handle_event(event)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn get_title_for_main_frame(&self) {
        self.compositor.get_title_for_main_frame()
    }

    pub fn shutdown(mut self) {
        self.compositor.shutdown();
    }
}

<|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 hyper::header::Headers;
use hyper::method::Method;
use std::cell::{Cell, RefCell};
use url::{Origin, Url};

/// A [request context](https://fetch.spec.whatwg.org/#concept-request-context)
#[derive(Copy, Clone, PartialEq)]
pub enum Context {
    Audio, Beacon, CSPreport, Download, Embed, Eventsource,
    Favicon, Fetch, Font, Form, Frame, Hyperlink, IFrame, Image,
    ImageSet, Import, Internal, Location, Manifest, MetaRefresh, Object,
    Ping, Plugin, Prefetch, PreRender, Script, ServiceWorker, SharedWorker,
    Subresource, Style, Track, Video, Worker, XMLHttpRequest, XSLT
}

/// A [request context frame type](https://fetch.spec.whatwg.org/#concept-request-context-frame-type)
#[derive(Copy, Clone, PartialEq)]
pub enum ContextFrameType {
    Auxiliary,
    TopLevel,
    Nested,
    ContextNone
}

/// A [referer](https://fetch.spec.whatwg.org/#concept-request-referrer)
#[derive(Clone, PartialEq)]
pub enum Referer {
    NoReferer,
    Client,
    RefererUrl(Url)
}

/// A [request mode](https://fetch.spec.whatwg.org/#concept-request-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum RequestMode {
    Navigate,
    SameOrigin,
    NoCORS,
    CORSMode
}

/// Request [credentials mode](https://fetch.spec.whatwg.org/#concept-request-credentials-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum CredentialsMode {
    Omit,
    CredentialsSameOrigin,
    Include
}

/// [Cache mode](https://fetch.spec.whatwg.org/#concept-request-cache-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum CacheMode {
    Default,
    NoStore,
    Reload,
    NoCache,
    ForceCache,
    OnlyIfCached
}

/// [Redirect mode](https://fetch.spec.whatwg.org/#concept-request-redirect-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum RedirectMode {
    Follow,
    Error,
    Manual
}

/// [Response tainting](https://fetch.spec.whatwg.org/#concept-request-response-tainting)
#[derive(Copy, Clone, PartialEq)]
pub enum ResponseTainting {
    Basic,
    CORSTainting,
    Opaque
}

/// A [Request](https://fetch.spec.whatwg.org/#requests) as defined by the Fetch spec
#[derive(Clone)]
pub struct Request {
    pub method: RefCell<Method>,
    pub local_urls_only: bool,
    // Use the last method on url_list to act as spec url field
    pub url_list: RefCell<Vec<Url>>,
    pub headers: RefCell<Headers>,
    pub unsafe_request: bool,
    pub body: Option<Vec<u8>>,
    pub preserve_content_codings: bool,
    // pub client: GlobalRef, // XXXManishearth copy over only the relevant fields of the global scope,
                              // not the entire scope to avoid the libscript dependency
    pub is_service_worker_global_scope: bool,
    pub skip_service_worker: Cell<bool>,
    pub context: Context,
    pub context_frame_type: ContextFrameType,
    pub origin: Origin,
    pub force_origin_header: bool,
    pub omit_origin_header: bool,
    pub same_origin_data: Cell<bool>,
    pub referer: Referer,
    pub authentication: bool,
    pub synchronous: bool,
    pub use_cors_preflight: bool,
    pub mode: RequestMode,
    pub credentials_mode: CredentialsMode,
    pub use_url_credentials: bool,
    pub cache_mode: Cell<CacheMode>,
    pub redirect_mode: Cell<RedirectMode>,
    pub redirect_count: Cell<u32>,
    pub response_tainting: Cell<ResponseTainting>
}

impl Request {
    pub fn new(url: Url, context: Context, origin: Origin, is_service_worker_global_scope: bool) -> Request {
         Request {
            method: RefCell::new(Method::Get),
            local_urls_only: false,
            url_list: RefCell::new(vec![url]),
            headers: RefCell::new(Headers::new()),
            unsafe_request: false,
            body: None,
            preserve_content_codings: false,
            is_service_worker_global_scope: is_service_worker_global_scope,
            skip_service_worker: Cell::new(false),
            context: context,
            context_frame_type: ContextFrameType::ContextNone,
            origin: origin,
            force_origin_header: false,
            omit_origin_header: false,
            same_origin_data: Cell::new(false),
            referer: Referer::Client,
            authentication: false,
            synchronous: false,
            use_cors_preflight: false,
            mode: RequestMode::NoCORS,
            credentials_mode: CredentialsMode::Omit,
            use_url_credentials: false,
            cache_mode: Cell::new(CacheMode::Default),
            redirect_mode: Cell::new(RedirectMode::Follow),
            redirect_count: Cell::new(0),
            response_tainting: Cell::new(ResponseTainting::Basic)
        }
    }

    pub fn get_last_url_string(&self) -> String {
        self.url_list.borrow().last().unwrap().serialize()
    }

    pub fn current_url(&self) -> Url {
        self.url_list.borrow().last().unwrap().clone()
    }
}
<commit_msg>Auto merge of #9516 - KiChjang:potential-cors-request, r=nikkisquared<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 hyper::header::Headers;
use hyper::method::Method;
use std::cell::{Cell, RefCell};
use url::{Origin, Url};

/// A [request context](https://fetch.spec.whatwg.org/#concept-request-context)
#[derive(Copy, Clone, PartialEq)]
pub enum Context {
    Audio, Beacon, CSPreport, Download, Embed, Eventsource,
    Favicon, Fetch, Font, Form, Frame, Hyperlink, IFrame, Image,
    ImageSet, Import, Internal, Location, Manifest, MetaRefresh, Object,
    Ping, Plugin, Prefetch, PreRender, Script, ServiceWorker, SharedWorker,
    Subresource, Style, Track, Video, Worker, XMLHttpRequest, XSLT
}

/// A [request context frame type](https://fetch.spec.whatwg.org/#concept-request-context-frame-type)
#[derive(Copy, Clone, PartialEq)]
pub enum ContextFrameType {
    Auxiliary,
    TopLevel,
    Nested,
    ContextNone
}

/// A [referer](https://fetch.spec.whatwg.org/#concept-request-referrer)
#[derive(Clone, PartialEq)]
pub enum Referer {
    NoReferer,
    Client,
    RefererUrl(Url)
}

/// A [request mode](https://fetch.spec.whatwg.org/#concept-request-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum RequestMode {
    Navigate,
    SameOrigin,
    NoCORS,
    CORSMode
}

/// Request [credentials mode](https://fetch.spec.whatwg.org/#concept-request-credentials-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum CredentialsMode {
    Omit,
    CredentialsSameOrigin,
    Include
}

/// [Cache mode](https://fetch.spec.whatwg.org/#concept-request-cache-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum CacheMode {
    Default,
    NoStore,
    Reload,
    NoCache,
    ForceCache,
    OnlyIfCached
}

/// [Redirect mode](https://fetch.spec.whatwg.org/#concept-request-redirect-mode)
#[derive(Copy, Clone, PartialEq)]
pub enum RedirectMode {
    Follow,
    Error,
    Manual
}

/// [Response tainting](https://fetch.spec.whatwg.org/#concept-request-response-tainting)
#[derive(Copy, Clone, PartialEq)]
pub enum ResponseTainting {
    Basic,
    CORSTainting,
    Opaque
}

/// [CORS settings attribute](https://html.spec.whatwg.org/multipage/#attr-crossorigin-anonymous)
pub enum CORSSettings {
    Anonymous,
    UseCredentials
}

/// A [Request](https://fetch.spec.whatwg.org/#requests) as defined by the Fetch spec
#[derive(Clone)]
pub struct Request {
    pub method: RefCell<Method>,
    pub local_urls_only: bool,
    // Use the last method on url_list to act as spec url field
    pub url_list: RefCell<Vec<Url>>,
    pub headers: RefCell<Headers>,
    pub unsafe_request: bool,
    pub body: Option<Vec<u8>>,
    pub preserve_content_codings: bool,
    // pub client: GlobalRef, // XXXManishearth copy over only the relevant fields of the global scope,
                              // not the entire scope to avoid the libscript dependency
    pub is_service_worker_global_scope: bool,
    pub skip_service_worker: Cell<bool>,
    pub context: Context,
    pub context_frame_type: ContextFrameType,
    pub origin: Origin,
    pub force_origin_header: bool,
    pub omit_origin_header: bool,
    pub same_origin_data: Cell<bool>,
    pub referer: Referer,
    pub authentication: bool,
    pub synchronous: bool,
    pub use_cors_preflight: bool,
    pub mode: RequestMode,
    pub credentials_mode: CredentialsMode,
    pub use_url_credentials: bool,
    pub cache_mode: Cell<CacheMode>,
    pub redirect_mode: Cell<RedirectMode>,
    pub redirect_count: Cell<u32>,
    pub response_tainting: Cell<ResponseTainting>
}

impl Request {
    pub fn new(url: Url,
               context: Context,
               origin: Origin,
               is_service_worker_global_scope: bool) -> Request {
         Request {
            method: RefCell::new(Method::Get),
            local_urls_only: false,
            url_list: RefCell::new(vec![url]),
            headers: RefCell::new(Headers::new()),
            unsafe_request: false,
            body: None,
            preserve_content_codings: false,
            is_service_worker_global_scope: is_service_worker_global_scope,
            skip_service_worker: Cell::new(false),
            context: context,
            context_frame_type: ContextFrameType::ContextNone,
            origin: origin,
            force_origin_header: false,
            omit_origin_header: false,
            same_origin_data: Cell::new(false),
            referer: Referer::Client,
            authentication: false,
            synchronous: false,
            use_cors_preflight: false,
            mode: RequestMode::NoCORS,
            credentials_mode: CredentialsMode::Omit,
            use_url_credentials: false,
            cache_mode: Cell::new(CacheMode::Default),
            redirect_mode: Cell::new(RedirectMode::Follow),
            redirect_count: Cell::new(0),
            response_tainting: Cell::new(ResponseTainting::Basic)
        }
    }

    /// https://html.spec.whatwg.org/multipage/#create-a-potential-cors-request
    pub fn potential_cors_request(url: Url,
                               cors_attribute_state: Option<CORSSettings>,
                               context: Context,
                               is_service_worker_global_scope: bool,
                               same_origin_fallback: bool) -> Request {
        let origin = url.origin();
        Request {
            method: RefCell::new(Method::Get),
            local_urls_only: false,
            url_list: RefCell::new(vec![url]),
            headers: RefCell::new(Headers::new()),
            unsafe_request: false,
            body: None,
            preserve_content_codings: false,
            is_service_worker_global_scope: is_service_worker_global_scope,
            skip_service_worker: Cell::new(false),
            context: context,
            context_frame_type: ContextFrameType::ContextNone,
            origin: origin,
            force_origin_header: false,
            same_origin_data: Cell::new(false),
            omit_origin_header: false,
            referer: Referer::Client,
            authentication: false,
            synchronous: false,
            use_cors_preflight: false,
            // Step 1-2
            mode: match cors_attribute_state {
                Some(_) => RequestMode::CORSMode,
                None if same_origin_fallback => RequestMode::SameOrigin,
                None => RequestMode::NoCORS
            },
            // Step 3-4
            credentials_mode: match cors_attribute_state {
                Some(CORSSettings::Anonymous) => CredentialsMode::CredentialsSameOrigin,
                _ => CredentialsMode::Include,
            },
            use_url_credentials: true,
            cache_mode: Cell::new(CacheMode::Default),
            redirect_mode: Cell::new(RedirectMode::Follow),
            redirect_count: Cell::new(0),
            response_tainting: Cell::new(ResponseTainting::Basic)
        }
    }

    pub fn get_last_url_string(&self) -> String {
        self.url_list.borrow().last().unwrap().serialize()
    }

    pub fn current_url(&self) -> Url {
        self.url_list.borrow().last().unwrap().clone()
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    constants, error::Error, layout::Layout, secure_backend::StorageLocation::RemoteStorage,
    SingleBackend,
};
use libra_crypto::ed25519::Ed25519PublicKey;
use libra_global_constants::{ASSOCIATION_KEY, OPERATOR_KEY};
use libra_secure_storage::KVStorage;
use libra_types::transaction::{Transaction, TransactionPayload};
use std::{fs::File, io::Write, path::PathBuf};
use structopt::StructOpt;
use vm_genesis::ValidatorRegistration;

// TODO(davidiw) add operator_address, since that will eventually be the identity producing this.
/// Note, it is implicitly expected that the storage supports
/// a namespace but one has not been set.
#[derive(Debug, StructOpt)]
pub struct Genesis {
    #[structopt(flatten)]
    pub backend: SingleBackend,
    #[structopt(long)]
    pub path: Option<PathBuf>,
}

impl Genesis {
    pub fn execute(self) -> Result<Transaction, Error> {
        let layout = self.layout()?;
        let association_key = self.association(&layout)?;
        let validators = self.validators(&layout)?;

        let genesis = vm_genesis::encode_genesis_transaction_with_validator(
            association_key,
            &validators,
            None,
        );

        if let Some(path) = self.path {
            let mut file = File::create(path).map_err(|e| {
                Error::UnexpectedError(format!("Unable to create genesis file: {}", e.to_string()))
            })?;
            let bytes = lcs::to_bytes(&genesis).map_err(|e| {
                Error::UnexpectedError(format!("Unable to serialize genesis: {}", e.to_string()))
            })?;
            file.write_all(&bytes).map_err(|e| {
                Error::UnexpectedError(format!("Unable to write genesis file: {}", e.to_string()))
            })?;
        }

        Ok(genesis)
    }

    /// Retrieves association key from the remote storage. Note, at this point in time, genesis
    /// only supports a single association key.
    pub fn association(&self, layout: &Layout) -> Result<Ed25519PublicKey, Error> {
        let association_config = self.backend.backend.clone();
        let association_config = association_config.set_namespace(layout.association[0].clone());

        let association_storage = association_config.create_storage(RemoteStorage)?;

        let association_key = association_storage
            .get(ASSOCIATION_KEY)
            .map_err(|e| Error::RemoteStorageReadError(ASSOCIATION_KEY, e.to_string()))?;
        association_key
            .value
            .ed25519_public_key()
            .map_err(|e| Error::RemoteStorageReadError(ASSOCIATION_KEY, e.to_string()))
    }

    /// Retrieves a layout from the remote storage.
    pub fn layout(&self) -> Result<Layout, Error> {
        let common_config = self.backend.backend.clone();
        let common_config = common_config.set_namespace(constants::COMMON_NS.into());

        let common_storage = common_config.create_storage(RemoteStorage)?;

        let layout = common_storage
            .get(constants::LAYOUT)
            .and_then(|v| v.value.string())
            .map_err(|e| Error::RemoteStorageReadError(constants::LAYOUT, e.to_string()))?;
        Layout::parse(&layout)
            .map_err(|e| Error::RemoteStorageReadError(constants::LAYOUT, e.to_string()))
    }

    /// Produces a set of ValidatorRegistration from the remote storage.
    pub fn validators(&self, layout: &Layout) -> Result<Vec<ValidatorRegistration>, Error> {
        let mut validators = Vec::new();
        for operator in layout.operators.iter() {
            let validator_config = self.backend.backend.clone();
            let validator_config = validator_config.set_namespace(operator.into());

            let validator_storage = validator_config.create_storage(RemoteStorage)?;

            let key = validator_storage
                .get(OPERATOR_KEY)
                .map_err(|e| Error::RemoteStorageReadError(OPERATOR_KEY, e.to_string()))?
                .value
                .ed25519_public_key()
                .map_err(|e| Error::RemoteStorageReadError(OPERATOR_KEY, e.to_string()))?;

            let txn = validator_storage
                .get(constants::VALIDATOR_CONFIG)
                .map_err(|e| {
                    Error::RemoteStorageReadError(constants::VALIDATOR_CONFIG, e.to_string())
                })?
                .value;
            let txn = txn.transaction().unwrap();
            let txn = txn.as_signed_user_txn().unwrap().payload();
            let txn = if let TransactionPayload::Script(script) = txn {
                script.clone()
            } else {
                return Err(Error::UnexpectedError("Found invalid registration".into()));
            };

            validators.push((key, txn));
        }

        Ok(validators)
    }
}
<commit_msg>[management] For now, allow arbitrary scripts on pre-mainnet<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    constants, error::Error, layout::Layout, secure_backend::StorageLocation::RemoteStorage,
    SingleBackend,
};
use libra_crypto::ed25519::Ed25519PublicKey;
use libra_global_constants::{ASSOCIATION_KEY, OPERATOR_KEY};
use libra_secure_storage::KVStorage;
use libra_types::transaction::{Transaction, TransactionPayload};
use std::{fs::File, io::Write, path::PathBuf};
use structopt::StructOpt;
use vm_genesis::ValidatorRegistration;

// TODO(davidiw) add operator_address, since that will eventually be the identity producing this.
/// Note, it is implicitly expected that the storage supports
/// a namespace but one has not been set.
#[derive(Debug, StructOpt)]
pub struct Genesis {
    #[structopt(flatten)]
    pub backend: SingleBackend,
    #[structopt(long)]
    pub path: Option<PathBuf>,
}

impl Genesis {
    pub fn execute(self) -> Result<Transaction, Error> {
        let layout = self.layout()?;
        let association_key = self.association(&layout)?;
        let validators = self.validators(&layout)?;

        let genesis = vm_genesis::encode_genesis_transaction_with_validator(
            association_key,
            &validators,
            Some(libra_types::on_chain_config::VMPublishingOption::CustomScripts),
        );

        if let Some(path) = self.path {
            let mut file = File::create(path).map_err(|e| {
                Error::UnexpectedError(format!("Unable to create genesis file: {}", e.to_string()))
            })?;
            let bytes = lcs::to_bytes(&genesis).map_err(|e| {
                Error::UnexpectedError(format!("Unable to serialize genesis: {}", e.to_string()))
            })?;
            file.write_all(&bytes).map_err(|e| {
                Error::UnexpectedError(format!("Unable to write genesis file: {}", e.to_string()))
            })?;
        }

        Ok(genesis)
    }

    /// Retrieves association key from the remote storage. Note, at this point in time, genesis
    /// only supports a single association key.
    pub fn association(&self, layout: &Layout) -> Result<Ed25519PublicKey, Error> {
        let association_config = self.backend.backend.clone();
        let association_config = association_config.set_namespace(layout.association[0].clone());

        let association_storage = association_config.create_storage(RemoteStorage)?;

        let association_key = association_storage
            .get(ASSOCIATION_KEY)
            .map_err(|e| Error::RemoteStorageReadError(ASSOCIATION_KEY, e.to_string()))?;
        association_key
            .value
            .ed25519_public_key()
            .map_err(|e| Error::RemoteStorageReadError(ASSOCIATION_KEY, e.to_string()))
    }

    /// Retrieves a layout from the remote storage.
    pub fn layout(&self) -> Result<Layout, Error> {
        let common_config = self.backend.backend.clone();
        let common_config = common_config.set_namespace(constants::COMMON_NS.into());

        let common_storage = common_config.create_storage(RemoteStorage)?;

        let layout = common_storage
            .get(constants::LAYOUT)
            .and_then(|v| v.value.string())
            .map_err(|e| Error::RemoteStorageReadError(constants::LAYOUT, e.to_string()))?;
        Layout::parse(&layout)
            .map_err(|e| Error::RemoteStorageReadError(constants::LAYOUT, e.to_string()))
    }

    /// Produces a set of ValidatorRegistration from the remote storage.
    pub fn validators(&self, layout: &Layout) -> Result<Vec<ValidatorRegistration>, Error> {
        let mut validators = Vec::new();
        for operator in layout.operators.iter() {
            let validator_config = self.backend.backend.clone();
            let validator_config = validator_config.set_namespace(operator.into());

            let validator_storage = validator_config.create_storage(RemoteStorage)?;

            let key = validator_storage
                .get(OPERATOR_KEY)
                .map_err(|e| Error::RemoteStorageReadError(OPERATOR_KEY, e.to_string()))?
                .value
                .ed25519_public_key()
                .map_err(|e| Error::RemoteStorageReadError(OPERATOR_KEY, e.to_string()))?;

            let txn = validator_storage
                .get(constants::VALIDATOR_CONFIG)
                .map_err(|e| {
                    Error::RemoteStorageReadError(constants::VALIDATOR_CONFIG, e.to_string())
                })?
                .value;
            let txn = txn.transaction().unwrap();
            let txn = txn.as_signed_user_txn().unwrap().payload();
            let txn = if let TransactionPayload::Script(script) = txn {
                script.clone()
            } else {
                return Err(Error::UnexpectedError("Found invalid registration".into()));
            };

            validators.push((key, txn));
        }

        Ok(validators)
    }
}
<|endoftext|>


<commit_before>#[doc = "Rust wrappers around the raw JS apis"];

import bg = jsapi::bindgen;
import libc::types::os::arch::c95::{size_t, c_uint};
import std::map::{hashmap, str_hash};

export rt;
export cx;
export jsobj;
export methods;
export compartment;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

type rt = @rt_rsrc;

struct rt_rsrc {
    let ptr : *JSRuntime;
    new(p : {ptr: *JSRuntime}) {
        self.ptr = p.ptr;
    }
    drop {
        JS_Finish(self.ptr);
    }
}

fn rt() -> rt {
    @rt_rsrc({ptr: JS_Init(default_heapsize)})
}

impl rt {
    fn cx() -> cx {
        @cx_rsrc({ptr: JS_NewContext(self.ptr, default_stacksize as size_t),
                  rt: self})
    }
}

// ___________________________________________________________________________
// contexts

type cx = @cx_rsrc;

struct cx_rsrc {
    let ptr : *JSContext;
    let rt: rt;
    let classes: hashmap<~str, @JSClass>;

    new(rec : {ptr: *JSContext, rt: rt}) {
        self.ptr = rec.ptr;
        self.rt = rec.rt;
        self.classes = str_hash();
    }
    drop {
        JS_DestroyContext(self.ptr);
    }
}

impl cx {
    fn rooted_obj(obj: *JSObject) -> jsobj {
        let jsobj = @jsobj_rsrc({cx: self, cxptr: self.ptr, ptr: obj});
        JS_AddObjectRoot(self.ptr, ptr::addr_of(jsobj.ptr));
        jsobj
    }

    fn set_default_options_and_version() {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT);
        self.set_version(JSVERSION_LATEST);
    }

    fn set_options(v: c_uint) {
        JS_SetOptions(self.ptr, v);
    }

    fn set_version(v: i32) {
        JS_SetVersion(self.ptr, v);
    }

    fn set_logging_error_reporter() {
        JS_SetErrorReporter(self.ptr, reportError);
    }

    fn set_error_reporter(reportfn: *u8) {
        JS_SetErrorReporter(self.ptr, reportfn);
    }

    fn new_compartment(globclsfn: fn(name_pool) -> JSClass) -> Result<compartment,()> {
        let np = name_pool();
        let globcls = @globclsfn(np);
        let globobj = JS_NewGlobalObject(self.ptr, ptr::to_unsafe_ptr(&*globcls), null());
        result(JS_InitStandardClasses(self.ptr, globobj)).chain(|_ok| {
            let compartment = @{cx: self,
                                name_pool: np,
                                mut global_funcs: ~[],
                                mut global_props: ~[],
                                global_class: globcls,
                                global_obj: self.rooted_obj(globobj),
                                global_protos: str_hash()
                               };
            self.set_cx_private(ptr::to_unsafe_ptr(&*compartment) as *());
            Ok(compartment)
        })
    }

    fn evaluate_script(glob: jsobj, bytes: ~[u8], filename: ~str, line_num: uint)
                    -> Result<(),()> {
        vec::as_buf(bytes, |bytes_ptr, bytes_len| {
            str::as_c_str(filename, |filename_cstr| {
                let bytes_ptr = bytes_ptr as *c_char;
                let rval: jsval = JSVAL_NULL;
                #debug["Evaluating script from %s with bytes %?", filename, bytes];
                if JS_EvaluateScript(self.ptr, glob.ptr,
                                     bytes_ptr, bytes_len as c_uint,
                                     filename_cstr, line_num as c_uint,
                                     ptr::addr_of(rval)) == ERR {
                    #debug["...err!"];
                    Err(())
                } else {
                    // we could return the script result but then we'd have
                    // to root it and so forth and, really, who cares?
                    #debug["...ok!"];
                    Ok(())
                }
            })
        })
    }

    fn lookup_class_name(s: ~str) ->  @JSClass {
      option::expect(self.classes.find(s),
           #fmt("Class %s not found in class table", s))
    }

    unsafe fn get_cx_private() -> *() {
        unsafe::reinterpret_cast(&JS_GetContextPrivate(self.ptr))
    }

    unsafe fn set_cx_private(data: *()) {
        JS_SetContextPrivate(self.ptr, unsafe::reinterpret_cast(&data));
    }

    unsafe fn get_obj_private(obj: *JSObject) -> *() {
        unsafe::reinterpret_cast(&JS_GetPrivate(obj))
    }

    unsafe fn set_obj_private(obj: *JSObject, data: *()) {
        JS_SetPrivate(obj, unsafe::reinterpret_cast(&data));
    }
}

extern fn reportError(_cx: *JSContext,
                     msg: *c_char,
                     report: *JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {~"none"};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        #error["Error at %s:%?: %s\n", fname, lineno, msg];
    }
}

// ___________________________________________________________________________
// compartment

type bare_compartment = {
    cx: cx,
    name_pool: name_pool,
    mut global_funcs: ~[@~[JSFunctionSpec]],
    mut global_props: ~[@~[JSPropertySpec]],
    global_class: @JSClass,
    global_obj: jsobj,
    global_protos: hashmap<~str, jsobj>
};

trait methods {
    fn define_functions(specfn: fn(name_pool) -> ~[JSFunctionSpec]) -> Result<(),()>;
    fn define_properties(specfn: fn() -> ~[JSPropertySpec]) -> Result<(),()>;
    fn define_property(name: ~str, value: jsval, getter: JSPropertyOp,
                       setter: JSStrictPropertyOp, attrs: c_uint) -> Result<(),()>;
    fn new_object(class_name: ~str, proto: *JSObject, parent: *JSObject) -> Result<jsobj, ()>;
    fn new_object_with_proto(class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()>;
    fn register_class(class_fn: fn(bare_compartment) -> JSClass);
    fn get_global_proto(name: ~str) -> jsobj;
    fn stash_global_proto(name: ~str, proto: jsobj);
    fn add_name(name: ~str) -> *c_char;
}

type compartment = @bare_compartment;

impl bare_compartment : methods {
    fn define_functions(specfn: fn(name_pool) -> ~[JSFunctionSpec]) -> Result<(),()> {
        let specvec = @specfn(self.name_pool);
        vec::push(self.global_funcs, specvec);
        vec::as_buf(*specvec, |specs, _len| {
            result(JS_DefineFunctions(self.cx.ptr, self.global_obj.ptr, specs))
        })
    }
    fn define_properties(specfn: fn() -> ~[JSPropertySpec]) -> Result<(),()> {
        let specvec = @specfn();
        vec::push(self.global_props, specvec);
        vec::as_buf(*specvec, |specs, _len| {
            result(JS_DefineProperties(self.cx.ptr, self.global_obj.ptr, specs))
        })
    }
    fn define_property(name: ~str, value: jsval, getter: JSPropertyOp, setter: JSStrictPropertyOp,
                       attrs: c_uint)
                    -> Result<(),()> {
        result(JS_DefineProperty(self.cx.ptr, self.global_obj.ptr, self.add_name(name),
                                 value, getter, setter, attrs))
    }
    fn new_object(class_name: ~str, proto: *JSObject, parent: *JSObject)
               -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                  proto, parent));
        result_obj(obj)
    }
    fn new_object_with_proto(class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let proto = option::expect(self.global_protos.find(proto_name),
           #fmt("new_object_with_proto: expected to find %s in the proto \
              table", proto_name));
        let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                  proto.ptr, parent));
        result_obj(obj)
    }
    fn get_global_proto(name: ~str) -> jsobj {
        self.global_protos.get(name)
    }
    fn stash_global_proto(name: ~str, proto: jsobj) {
        if !self.global_protos.insert(name, proto) {
            fail ~"Duplicate global prototype registered; you're gonna have a bad time."
        }
    }
    fn register_class(class_fn: fn(bare_compartment) -> JSClass) {
        let classptr = @class_fn(self);
        if !self.cx.classes.insert(
            unsafe { str::unsafe::from_c_str(classptr.name) },
            classptr) {
            fail ~"Duplicate JSClass registered; you're gonna have a bad time."
        }
    }
    fn add_name(name: ~str) -> *c_char {
        self.name_pool.add(copy name)
    }
}

// ___________________________________________________________________________
// objects

type jsobj = @jsobj_rsrc;

struct jsobj_rsrc {
    let cx : cx;
    let cxptr : *JSContext;
    let ptr : *JSObject;
    new(rec : {cx: cx, cxptr: *JSContext, ptr: *JSObject}) {
        self.cx = rec.cx;
        self.cxptr = rec.cxptr;
        self.ptr = rec.ptr;
    }
    drop {
        JS_RemoveObjectRoot(self.cxptr, ptr::addr_of(self.ptr));
    }
}

// ___________________________________________________________________________
// random utilities

trait to_jsstr {
    fn to_jsstr(cx: cx) -> *JSString;
}

impl ~str : to_jsstr {
    fn to_jsstr(cx: cx) -> *JSString {
        str::as_buf(self, |buf, len| {
            let cbuf = unsafe { unsafe::reinterpret_cast(&buf) };
            bg::JS_NewStringCopyN(cx.ptr, cbuf, len as size_t)
        })
    }
}

#[cfg(test)]
mod test {

    #[test]
    fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.set_default_options_and_version();
        cx.set_logging_error_reporter();
        cx.new_compartment(global::global_class).chain(|comp| {
            comp.define_functions(global::debug_fns);

            let bytes = str::to_bytes(~"debug(22);");
            cx.evaluate_script(comp.global_obj, bytes, ~"test", 1u)
        });
    }

}
<commit_msg>Fix build breaks<commit_after>#[doc = "Rust wrappers around the raw JS apis"];

import bg = jsapi::bindgen;
import libc::types::os::arch::c95::{size_t, c_uint};
import std::map::{hashmap, str_hash};

export rt;
export cx;
export jsobj;
export methods;
export compartment;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

type rt = @rt_rsrc;

struct rt_rsrc {
    ptr : *JSRuntime,
    drop {
        JS_Finish(self.ptr);
    }
}

fn new_runtime(p : {ptr: *JSRuntime}) -> rt {
    return @rt_rsrc {
        ptr: p.ptr
    }
}

impl rt {
    fn cx() -> cx {
        new_context({ ptr: JS_NewContext(self.ptr, default_stacksize as size_t),
                      rt: self})
    }
}

fn rt() -> rt {
    return new_runtime({ptr: JS_Init(default_heapsize)})
}

// ___________________________________________________________________________
// contexts

type cx = @cx_rsrc;

struct cx_rsrc {
    ptr : *JSContext,
    rt: rt,
    classes: hashmap<~str, @JSClass>,

    drop {
        JS_DestroyContext(self.ptr);
    }
}

fn new_context(rec : {ptr: *JSContext, rt: rt}) -> cx {
    return @cx_rsrc {
        ptr: rec.ptr,
        rt: rec.rt,
        classes: str_hash()
    }
}

impl cx {
    fn rooted_obj(obj: *JSObject) -> jsobj {
        let jsobj = @jsobj_rsrc {cx: self, cxptr: self.ptr, ptr: obj};
        JS_AddObjectRoot(self.ptr, ptr::addr_of(jsobj.ptr));
        jsobj
    }

    fn set_default_options_and_version() {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT);
        self.set_version(JSVERSION_LATEST);
    }

    fn set_options(v: c_uint) {
        JS_SetOptions(self.ptr, v);
    }

    fn set_version(v: i32) {
        JS_SetVersion(self.ptr, v);
    }

    fn set_logging_error_reporter() {
        JS_SetErrorReporter(self.ptr, reportError);
    }

    fn set_error_reporter(reportfn: *u8) {
        JS_SetErrorReporter(self.ptr, reportfn);
    }

    fn new_compartment(globclsfn: fn(name_pool) -> JSClass) -> Result<compartment,()> {
        let np = name_pool();
        let globcls = @globclsfn(np);
        let globobj = JS_NewGlobalObject(self.ptr, ptr::to_unsafe_ptr(&*globcls), null());
        result(JS_InitStandardClasses(self.ptr, globobj)).chain(|_ok| {
            let compartment = @{cx: self,
                                name_pool: np,
                                mut global_funcs: ~[],
                                mut global_props: ~[],
                                global_class: globcls,
                                global_obj: self.rooted_obj(globobj),
                                global_protos: str_hash()
                               };
            self.set_cx_private(ptr::to_unsafe_ptr(&*compartment) as *());
            Ok(compartment)
        })
    }

    fn evaluate_script(glob: jsobj, bytes: ~[u8], filename: ~str, line_num: uint)
                    -> Result<(),()> {
        vec::as_buf(bytes, |bytes_ptr, bytes_len| {
            str::as_c_str(filename, |filename_cstr| {
                let bytes_ptr = bytes_ptr as *c_char;
                let rval: jsval = JSVAL_NULL;
                #debug["Evaluating script from %s with bytes %?", filename, bytes];
                if JS_EvaluateScript(self.ptr, glob.ptr,
                                     bytes_ptr, bytes_len as c_uint,
                                     filename_cstr, line_num as c_uint,
                                     ptr::addr_of(rval)) == ERR {
                    #debug["...err!"];
                    Err(())
                } else {
                    // we could return the script result but then we'd have
                    // to root it and so forth and, really, who cares?
                    #debug["...ok!"];
                    Ok(())
                }
            })
        })
    }

    fn lookup_class_name(s: ~str) ->  @JSClass {
      option::expect(self.classes.find(s),
           #fmt("Class %s not found in class table", s))
    }

    unsafe fn get_cx_private() -> *() {
        unsafe::reinterpret_cast(&JS_GetContextPrivate(self.ptr))
    }

    unsafe fn set_cx_private(data: *()) {
        JS_SetContextPrivate(self.ptr, unsafe::reinterpret_cast(&data));
    }

    unsafe fn get_obj_private(obj: *JSObject) -> *() {
        unsafe::reinterpret_cast(&JS_GetPrivate(obj))
    }

    unsafe fn set_obj_private(obj: *JSObject, data: *()) {
        JS_SetPrivate(obj, unsafe::reinterpret_cast(&data));
    }
}

extern fn reportError(_cx: *JSContext,
                     msg: *c_char,
                     report: *JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {~"none"};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        #error["Error at %s:%?: %s\n", fname, lineno, msg];
    }
}

// ___________________________________________________________________________
// compartment

type bare_compartment = {
    cx: cx,
    name_pool: name_pool,
    mut global_funcs: ~[@~[JSFunctionSpec]],
    mut global_props: ~[@~[JSPropertySpec]],
    global_class: @JSClass,
    global_obj: jsobj,
    global_protos: hashmap<~str, jsobj>
};

trait methods {
    fn define_functions(specfn: fn(name_pool) -> ~[JSFunctionSpec]) -> Result<(),()>;
    fn define_properties(specfn: fn() -> ~[JSPropertySpec]) -> Result<(),()>;
    fn define_property(name: ~str, value: jsval, getter: JSPropertyOp,
                       setter: JSStrictPropertyOp, attrs: c_uint) -> Result<(),()>;
    fn new_object(class_name: ~str, proto: *JSObject, parent: *JSObject) -> Result<jsobj, ()>;
    fn new_object_with_proto(class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()>;
    fn register_class(class_fn: fn(bare_compartment) -> JSClass);
    fn get_global_proto(name: ~str) -> jsobj;
    fn stash_global_proto(name: ~str, proto: jsobj);
    fn add_name(name: ~str) -> *c_char;
}

type compartment = @bare_compartment;

impl bare_compartment : methods {
    fn define_functions(specfn: fn(name_pool) -> ~[JSFunctionSpec]) -> Result<(),()> {
        let specvec = @specfn(self.name_pool);
        vec::push(self.global_funcs, specvec);
        vec::as_buf(*specvec, |specs, _len| {
            result(JS_DefineFunctions(self.cx.ptr, self.global_obj.ptr, specs))
        })
    }
    fn define_properties(specfn: fn() -> ~[JSPropertySpec]) -> Result<(),()> {
        let specvec = @specfn();
        vec::push(self.global_props, specvec);
        vec::as_buf(*specvec, |specs, _len| {
            result(JS_DefineProperties(self.cx.ptr, self.global_obj.ptr, specs))
        })
    }
    fn define_property(name: ~str, value: jsval, getter: JSPropertyOp, setter: JSStrictPropertyOp,
                       attrs: c_uint)
                    -> Result<(),()> {
        result(JS_DefineProperty(self.cx.ptr, self.global_obj.ptr, self.add_name(name),
                                 value, getter, setter, attrs))
    }
    fn new_object(class_name: ~str, proto: *JSObject, parent: *JSObject)
               -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                  proto, parent));
        result_obj(obj)
    }
    fn new_object_with_proto(class_name: ~str, proto_name: ~str, parent: *JSObject)
                          -> Result<jsobj, ()> {
        let classptr = self.cx.lookup_class_name(class_name);
        let proto = option::expect(self.global_protos.find(proto_name),
           #fmt("new_object_with_proto: expected to find %s in the proto \
              table", proto_name));
        let obj = self.cx.rooted_obj(JS_NewObject(self.cx.ptr, ptr::to_unsafe_ptr(&*classptr),
                                                  proto.ptr, parent));
        result_obj(obj)
    }
    fn get_global_proto(name: ~str) -> jsobj {
        self.global_protos.get(name)
    }
    fn stash_global_proto(name: ~str, proto: jsobj) {
        if !self.global_protos.insert(name, proto) {
            fail ~"Duplicate global prototype registered; you're gonna have a bad time."
        }
    }
    fn register_class(class_fn: fn(bare_compartment) -> JSClass) {
        let classptr = @class_fn(self);
        if !self.cx.classes.insert(
            unsafe { str::unsafe::from_c_str(classptr.name) },
            classptr) {
            fail ~"Duplicate JSClass registered; you're gonna have a bad time."
        }
    }
    fn add_name(name: ~str) -> *c_char {
        self.name_pool.add(copy name)
    }
}

// ___________________________________________________________________________
// objects

type jsobj = @jsobj_rsrc;

struct jsobj_rsrc {
    cx : cx,
    cxptr : *JSContext,
    ptr : *JSObject,
    drop {
        JS_RemoveObjectRoot(self.cxptr, ptr::addr_of(self.ptr));
    }
}

impl jsobj_rsrc {
    fn new_object(rec : {cx: cx, cxptr: *JSContext, ptr: *JSObject}) -> jsobj {
        return @jsobj_rsrc {
            cx: rec.cx,
            cxptr: rec.cxptr,
            ptr: rec.ptr
        }
    }
}

// ___________________________________________________________________________
// random utilities

trait to_jsstr {
    fn to_jsstr(cx: cx) -> *JSString;
}

impl ~str : to_jsstr {
    fn to_jsstr(cx: cx) -> *JSString {
        str::as_buf(self, |buf, len| {
            let cbuf = unsafe { unsafe::reinterpret_cast(&buf) };
            bg::JS_NewStringCopyN(cx.ptr, cbuf, len as size_t)
        })
    }
}

#[cfg(test)]
mod test {

    #[test]
    fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.set_default_options_and_version();
        cx.set_logging_error_reporter();
        cx.new_compartment(global::global_class).chain(|comp| {
            comp.define_functions(global::debug_fns);

            let bytes = str::to_bytes(~"debug(22);");
            cx.evaluate_script(comp.global_obj, bytes, ~"test", 1u)
        });
    }

}
<|endoftext|>


<commit_before>// Kevin Cantu
// additional string functions I've wanted in Rust

/* so far including:
   splitfn
   lines
   words
   intercalate
*/

use std;

// a more general split
// unicode safe
// using a function, e.g., char::is_whitespace instead of single u8
fn splitfn(ss: str, sepf: block(cc: char)->bool) -> [str] {
   let vv: [str] = [];
   let accum: str = "";
   let ends_with_sep: bool = false;

   str::iter_chars(ss, {|cc|
      if sepf(cc) {
         vv += [accum];
         accum = "";
         ends_with_sep = true;
      } else {
         str::push_char(accum, cc);
         ends_with_sep = false;
      }
   });
   if str::char_len(accum) != 0u || ends_with_sep {
      vv += [accum];
   }
   ret vv;
}

#[test]
fn test_splitfn_a () {
   let data = "ประเทศไทย中华Việt Nam";
   assert ["ประเทศไทย中",
           "Việt Nam"]
      == splitfn (data, {|cc| cc == '华'});
}

fn lines (ss: str) -> [str] {
   ret splitfn(ss, {|cc| cc == '\n'});
}

#[test]
fn test_lines_splitfn () {
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["", "Mary had a little lamb", "Little lamb", "Little lamb", ""]
      == lines(data);
}

fn words (ss: str) -> [str] {
   ret vec::filter( splitfn(ss, {|cc| char::is_whitespace(cc)}),
                    {|w| 0u < str::char_len(w)});
}

#[test]
fn test_words_splitfn () {
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["Mary","had","a","little","lamb","Little","lamb","Little","lamb"]
      == words(data);
}

#[test]
fn test_example () {
   // TODO: correct documentation for str::char_range_at
   let s = "Clam chowder, hot sauce, pork rinds";
   let i = 0u;
   while i < str::char_len(s) {

     let {ch, next} = str::char_range_at(s, i);
     // TODO: why can't I use _ch in this record assignment to silence warnings?

     //log(debug, ch);
     //std::io::println(#fmt("%c",ch));
     i = next;
   }
}

// insert a str between elements of [str]
// then concatenate them all
fn intercalate (sep: str, xs: [str]) -> str {
   check vec::is_not_empty(xs);

   ret vec::foldl ( vec::head(xs),
                    vec::tail(xs),
                    {|acc,s| acc + sep + s});
}

#[test]
fn intercalate_test_a () {
   let vv   =  ["abc","def","ghi","jkl","mno"];
   assert "abcXXdefXXghiXXjklXXmno" == intercalate("XX", vv);
}

<commit_msg>removed intercalate: it is equivalent to str::connect<commit_after>// Kevin Cantu
// additional string functions I've wanted in Rust

/* so far including:
   splitfn
   lines
   words
*/

use std;

// a more general split
// unicode safe
// using a function, e.g., char::is_whitespace instead of single u8
fn splitfn(ss: str, sepf: block(cc: char)->bool) -> [str] {
   let vv: [str] = [];
   let accum: str = "";
   let ends_with_sep: bool = false;

   str::iter_chars(ss, {|cc|
      if sepf(cc) {
         vv += [accum];
         accum = "";
         ends_with_sep = true;
      } else {
         str::push_char(accum, cc);
         ends_with_sep = false;
      }
   });
   if str::char_len(accum) != 0u || ends_with_sep {
      vv += [accum];
   }
   ret vv;
}

#[test]
fn test_splitfn_a () {
   let data = "ประเทศไทย中华Việt Nam";
   assert ["ประเทศไทย中",
           "Việt Nam"]
      == splitfn (data, {|cc| cc == '华'});
}

fn lines (ss: str) -> [str] {
   ret splitfn(ss, {|cc| cc == '\n'});
}

#[test]
fn test_lines_splitfn () {
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["", "Mary had a little lamb", "Little lamb", "Little lamb", ""]
      == lines(data);
}

fn words (ss: str) -> [str] {
   ret vec::filter( splitfn(ss, {|cc| char::is_whitespace(cc)}),
                    {|w| 0u < str::char_len(w)});
}

#[test]
fn test_words_splitfn () {
   let data = "\nMary had a little lamb\nLittle lamb\nLittle lamb\n";

   assert ["Mary","had","a","little","lamb","Little","lamb","Little","lamb"]
      == words(data);
}

#[test]
fn test_example () {
   // TODO: correct documentation for str::char_range_at
   let s = "Clam chowder, hot sauce, pork rinds";
   let i = 0u;
   while i < str::char_len(s) {

     let {ch, next} = str::char_range_at(s, i);
     // TODO: why can't I use _ch in this record assignment to silence warnings?

     //log(debug, ch);
     //std::io::println(#fmt("%c",ch));
     i = next;
   }
}

<|endoftext|>


<commit_before>//! Scan the file looking for pointer-sized values that fall within an
//! executable section. Then, step backwards and ensure that the target
//! looks like either:
//!
//!   1. the end of a function, or
//!   2. filler between functions
//!
//! This analysis pass should be particularly useful for finding callbacks,
//! such as the start address passed to `CreateThread`.
//!
//! TODO: but doesn't help find callbacks referenced relatively - need
//! disassembly for this.
//!
//! This analysis pass is also good at handling global vtables.
//! Its especially important when CFGuard metadata is not present.
//!
//! Assumes:
//!   - pointers are 32-bits on x32 and 64-bits on x64 (*not* 32-bits on x64)

use anyhow::Result;
use byteorder::ByteOrder;

use crate::{aspace::AddressSpace, loader::pe::PE, module::Permissions, VA};

pub fn find_pe_nonrelocated_executable_pointers(pe: &PE) -> Result<Vec<VA>> {
    let mut candidates: Vec<VA> = vec![];

    // look for hardcoded pointers into the executable section of the PE.
    // note: this often finds jump tables, too. more filtering is below.
    // note: also finds many exception handlers. see filtering below.
    for section in pe.module.sections.iter() {
        let vstart: VA = section.virtual_range.start;
        let vsize = (section.virtual_range.end - section.virtual_range.start) as usize;
        let sec_buf = pe.module.address_space.read_bytes(vstart, vsize)?;

        if let crate::module::Arch::X64 = pe.module.arch {
            candidates.extend(
                sec_buf
                    .windows(8)
                    .map(|b| byteorder::LittleEndian::read_u64(b) as VA)
                    .filter(|&va| pe.module.probe_va(va, Permissions::X)),
            )
        } else {
            candidates.extend(
                sec_buf
                    .windows(4)
                    .map(|b| byteorder::LittleEndian::read_u32(b) as VA)
                    .filter(|&va| pe.module.probe_va(va, Permissions::X)),
            )
        }
    }

    // CC debug filler, x86win_patterns.xml#L4
    const CC: u8 = 0xCC;
    // NOP filler, x86win_patterns.xml#L6
    const NOP: u8 = 0x90;
    // RET(N) of prior function, x86win_patterns.xml#L7
    const RET: u8 = 0xC3;

    // TODO: ensure these are not pointers themselves

    // now, assert that the prior byte must be a either a RET or filler byte.
    // this should filter out almost all jump tables, etc.
    // should also filter out almost all exception handlers, too.
    Ok(candidates
        .into_iter()
        .filter(|&va| {
            if let Ok(b) = pe.module.address_space.read_u8(va - 1) {
                matches!(b, CC | NOP | RET)
            } else {
                false
            }
        })
        .filter(|&va| {
            if let Ok(ptr) = pe.module.read_va_at_va(va) {
                // the candidate is valid pointer, so its probably not an instruction.
                !pe.module.probe_va(ptr, Permissions::R)
            } else {
                true
            }
        })
        .collect())
}
<commit_msg>analysis: pointers: should not be strings<commit_after>//! Scan the file looking for pointer-sized values that fall within an
//! executable section. Then, step backwards and ensure that the target
//! looks like either:
//!
//!   1. the end of a function, or
//!   2. filler between functions
//!
//! This analysis pass should be particularly useful for finding callbacks,
//! such as the start address passed to `CreateThread`.
//!
//! TODO: but doesn't help find callbacks referenced relatively - need
//! disassembly for this.
//!
//! This analysis pass is also good at handling global vtables.
//! Its especially important when CFGuard metadata is not present.
//!
//! Assumes:
//!   - pointers are 32-bits on x32 and 64-bits on x64 (*not* 32-bits on x64)

use anyhow::Result;
use byteorder::ByteOrder;

use crate::{aspace::AddressSpace, loader::pe::PE, module::Permissions, VA};

pub fn find_pe_nonrelocated_executable_pointers(pe: &PE) -> Result<Vec<VA>> {
    let mut candidates: Vec<VA> = vec![];

    // look for hardcoded pointers into the executable section of the PE.
    // note: this often finds jump tables, too. more filtering is below.
    // note: also finds many exception handlers. see filtering below.
    for section in pe.module.sections.iter() {
        let vstart: VA = section.virtual_range.start;
        let vsize = (section.virtual_range.end - section.virtual_range.start) as usize;
        let sec_buf = pe.module.address_space.read_bytes(vstart, vsize)?;

        if let crate::module::Arch::X64 = pe.module.arch {
            candidates.extend(
                sec_buf
                    .windows(8)
                    .map(|b| byteorder::LittleEndian::read_u64(b) as VA)
                    .filter(|&va| pe.module.probe_va(va, Permissions::X)),
            )
        } else {
            candidates.extend(
                sec_buf
                    .windows(4)
                    .map(|b| byteorder::LittleEndian::read_u32(b) as VA)
                    .filter(|&va| pe.module.probe_va(va, Permissions::X)),
            )
        }
    }

    // CC debug filler, x86win_patterns.xml#L4
    const CC: u8 = 0xCC;
    // NOP filler, x86win_patterns.xml#L6
    const NOP: u8 = 0x90;
    // RET(N) of prior function, x86win_patterns.xml#L7
    const RET: u8 = 0xC3;

    // now, assert that the prior byte must be a either a RET or filler byte.
    // this should filter out almost all jump tables, etc.
    // should also filter out almost all exception handlers, too.
    // should not be an ASCII string (as seen in 32-bit kernel32)
    Ok(candidates
        .into_iter()
        .filter(|&va| {
            if let Ok(b) = pe.module.address_space.read_u8(va - 1) {
                matches!(b, CC | NOP | RET)
            } else {
                false
            }
        })
        .filter(|&va| {
            if let Ok(ptr) = pe.module.read_va_at_va(va) {
                // the candidate is valid pointer, so its probably not an instruction.
                !pe.module.probe_va(ptr, Permissions::R)
            } else {
                true
            }
        })
        .filter(|&va| matches!(pe.module.address_space.read_ascii(va), Err(_)))
        .collect())
}
<|endoftext|>