<commit_before>use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
use odds::vec::VecExt;

use std::rc::Rc;

use {Printer, XY};
use direction::Direction;
use vec::Vec2;
use event::{Event, EventResult, Key};
use utils::{LinesIterator, Row, prefix_length};
use view::{ScrollBase, SizeCache, View};
use theme::{ColorStyle, Effect};

/// Multi-lines text editor.
///
/// A `TextArea` by itself doesn't have a well-defined size.
/// You should wrap it in a `BoxView` to control its size.
pub struct TextArea {
    // TODO: use a smarter data structure (rope?)
    content: String,
    /// Byte offsets within `content` representing text rows
    rows: Vec<Row>,

    /// When `false`, we don't take any input.
    enabled: bool,

    /// Base for scrolling features
    scrollbase: ScrollBase,

    /// Cache to avoid re-computing layout on no-op events
    last_size: Option<XY<SizeCache>>,

    /// Byte offset of the currently selected grapheme.
    cursor: usize,
}

fn make_rows(text: &str, width: usize) -> Vec<Row> {
    LinesIterator::new(text, width)
        .show_spaces()
        .collect()
}

impl TextArea {
    /// Creates a new, empty TextArea.
    pub fn new() -> Self {
        TextArea {
            content: String::new(),
            rows: vec![Row {
                           start: 0,
                           end: 0,
                           width: 0,
                       }],
            enabled: true,
            scrollbase: ScrollBase::new().right_padding(0),
            last_size: None,
            cursor: 0,
        }
    }

    /// Retrieves the content of the view.
    pub fn get_content(&self) -> &str {
        &self.content
    }

    /// Finds the row containing the grapheme at the given offset
    fn row_at(&self, offset: usize) -> usize {
        // println_stderr!("Offset: {}", offset);
        self.rows
            .iter()
            .enumerate()
            .take_while(|&(_, row)| row.start <= offset)
            .map(|(i, _)| i)
            .last()
            .unwrap()
    }

    fn col_at(&self, offset: usize) -> usize {
        let row_id = self.row_at(offset);
        let row = self.rows[row_id];
        // Number of cells to the left of the cursor
        self.content[row.start..offset].width()
    }

    /// Finds the row containing the cursor
    fn selected_row(&self) -> usize {
        self.row_at(self.cursor)
    }

    fn page_up(&mut self) {
        for _ in 0..5 {
            self.move_up();
        }
    }

    fn page_down(&mut self) {
        for _ in 0..5 {
            self.move_down();
        }
    }

    fn move_up(&mut self) {
        let row_id = self.selected_row();
        if row_id == 0 {
            return;
        }

        // Number of cells to the left of the cursor
        let x = self.col_at(self.cursor);

        let prev_row = self.rows[row_id - 1];
        let prev_text = &self.content[prev_row.start..prev_row.end];
        let offset = prefix_length(prev_text.graphemes(true), x, "");
        self.cursor = prev_row.start + offset;
    }

    fn move_down(&mut self) {
        let row_id = self.selected_row();
        if row_id + 1 == self.rows.len() {
            return;
        }
        let x = self.col_at(self.cursor);

        let next_row = self.rows[row_id + 1];
        let next_text = &self.content[next_row.start..next_row.end];
        let offset = prefix_length(next_text.graphemes(true), x, "");
        self.cursor = next_row.start + offset;
    }

    /// Moves the cursor to the left.
    ///
    /// Wraps the previous line if required.
    fn move_left(&mut self) {
        let len = {
            // We don't want to utf8-parse the entire content.
            // So restrict to the last row.
            let mut row = self.selected_row();
            if self.rows[row].start == self.cursor {
                row -= 1;
            }

            let text = &self.content[self.rows[row].start..self.cursor];
            text.graphemes(true)
                .last()
                .unwrap()
                .len()
        };
        self.cursor -= len;
    }

    /// Moves the cursor to the right.
    ///
    /// Jumps to the next line is required.
    fn move_right(&mut self) {
        let len = self.content[self.cursor..]
            .graphemes(true)
            .next()
            .unwrap()
            .len();
        self.cursor += len;
    }

    fn is_cache_valid(&self, size: Vec2) -> bool {
        false
    }

    fn fix_ghost_row(&mut self) {
        if self.rows.is_empty() ||
           self.rows.last().unwrap().end != self.content.len() {
            // Add a fake, empty row at the end.
            self.rows.push(Row {
                start: self.content.len(),
                end: self.content.len(),
                width: 0,
            });
        }
    }

    fn compute_rows(&mut self, size: Vec2) {
        let mut available = size.x;
        self.rows = make_rows(&self.content, available);
        self.fix_ghost_row();
        if self.rows.len() > size.y {
            available -= 1;
            // Doh :(
            self.rows = make_rows(&self.content, available);
            self.fix_ghost_row();
        }

        if !self.rows.is_empty() {
            self.last_size = Some(SizeCache::build(size, size));
        }
    }

    fn backspace(&mut self) {
        if self.cursor != 0 {
            self.move_left();
            self.delete();
        }
    }

    fn delete(&mut self) {
        let len = self.content[self.cursor..]
            .graphemes(true)
            .next()
            .unwrap()
            .len();
        let start = self.cursor;
        let end = self.cursor + len;
        for _ in self.content.drain(start..end) {}

        let selected_row = self.selected_row();
        if self.cursor == self.rows[selected_row].end {
            // We're removing an (implicit) newline.
            // This means merging two rows.
        } else {
            self.rows[selected_row].end -= len;
        }

        // update all the rows downstream
        for row in &mut self.rows.iter_mut().skip(1 + selected_row) {
            row.rev_shift(len);
        }

        self.fix_damages(true);
    }

    fn insert(&mut self, ch: char) {

        // First, we inject the data, but keep the cursor unmoved
        // (So the cursor is to the left of the injected char)
        self.content.insert(self.cursor, ch);

        // Then, we shift the indexes of every row after this one.
        let shift = ch.len_utf8();

        // The current row grows, every other is just shifted.
        let selected_row = self.selected_row();
        self.rows[selected_row].end += shift;

        for row in &mut self.rows.iter_mut().skip(1 + selected_row) {
            row.shift(shift);
        }
        self.cursor += shift;

        // Finally, rows may not have the correct width anymore, so fix them.
        self.fix_damages(false);

    }

    /// Fix a damage located at the cursor.
    ///
    /// The only damages are assumed to have occured around the cursor.
    fn fix_damages(&mut self, delete: bool) {
        let size = self.last_size.unwrap().map(|s| s.value);

        // Find affected text.
        let first_row = self.selected_row();
        let start = self.rows[first_row].start;

        // We don't need to go beyond a newline.
        // If we don't find one, end of the text it is.
        // println_stderr!("Cursor: {}", self.cursor);
        let end = self.content[self.cursor..]
            .find('\n')
            .map(|i| i + self.cursor)
            .unwrap_or(self.content.len());
        // println_stderr!("Content: `{}` (len={})", self.content, self.content.len());
        // println_stderr!("start/end: {}/{}", start, end);
        let last_row = self.row_at(end);

        // Do we have access to the entire width?...
        let mut available = size.x;

        let scrollable = self.rows.len() > size.y;
        if scrollable {
            // ... not if a scrollbar is there
            available -= 1;
        }

        // First attempt, if scrollbase status didn't change.
        // println_stderr!("Rows: {:?}", self.rows);
        let mut new_rows = make_rows(&self.content[start..end], available);
        // How much did this add?
        let new_row_count = if delete {
            let delta = (1 + last_row - first_row) - new_rows.len();
            self.rows.len() - delta
        } else {
            let delta = new_rows.len() - (1 + last_row - first_row);
            self.rows.len() + delta

        };
        if !scrollable && new_row_count > size.y {
            // We just changed scrollable status.
            // This changes everything.
            // TODO: compute_rows() currently makes a scroll-less attempt.
            // Here, we know it's just no gonna happen.
            self.compute_rows(size);
            return;
        }

        // Otherwise, replace stuff.
        let affected_rows = first_row..(1 + last_row);
        let replacement_rows = new_rows.into_iter()
            .map(|row| row.shifted(start));
        self.rows.splice(affected_rows, replacement_rows);
        self.fix_ghost_row();
    }
}

impl View for TextArea {
    fn draw(&self, printer: &Printer) {
        printer.with_color(ColorStyle::Secondary, |printer| {
            let effect = if self.enabled {
                Effect::Reverse
            } else {
                Effect::Simple
            };

            let w = if self.scrollbase.scrollable() {
                printer.size.x - 1
            } else {
                printer.size.x
            };
            printer.with_effect(effect, |printer| {
                for y in 0..printer.size.y {
                    printer.print_hline((0, y), w, " ");
                }
            });

            self.scrollbase.draw(printer, |printer, i| {
                let row = &self.rows[i];
                let text = &self.content[row.start..row.end];
                printer.with_effect(effect, |printer| {
                    printer.print((0, 0), text);
                });

                if printer.focused && i == self.selected_row() {
                    let cursor_offset = self.cursor - row.start;
                    let c = if cursor_offset == text.len() {
                        "_"
                    } else {
                        text[cursor_offset..]
                            .graphemes(true)
                            .next()
                            .expect("Found no char!")
                    };
                    let offset = text[..cursor_offset].width();
                    printer.print((offset, 0), c);
                }

            });
        });
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        match event {
            Event::Char(ch) => self.insert(ch),
            Event::Key(Key::Enter) => self.insert('\n'),
            Event::Key(Key::Backspace) if self.cursor > 0 => self.backspace(),
            Event::Key(Key::Del) if self.cursor < self.content.len() => {
                self.delete()
            }

            Event::Key(Key::End) => {
                let row = self.selected_row();
                self.cursor = self.rows[row].end;
                if row + 1 < self.rows.len() &&
                   self.cursor == self.rows[row + 1].start {
                    self.move_left();
                }
            }
            Event::Ctrl(Key::Home) => self.cursor = 0,
            Event::Ctrl(Key::End) => self.cursor = self.content.len(),
            Event::Key(Key::Home) => {
                self.cursor = self.rows[self.selected_row()].start
            }
            Event::Key(Key::Up) if self.selected_row() > 0 => self.move_up(),
            Event::Key(Key::Down) if self.selected_row() + 1 <
                                     self.rows.len() => self.move_down(),
            Event::Key(Key::PageUp) => self.page_up(),
            Event::Key(Key::PageDown) => self.page_down(),
            Event::Key(Key::Left) if self.cursor > 0 => self.move_left(),
            Event::Key(Key::Right) if self.cursor < self.content.len() => {
                self.move_right()
            }
            _ => return EventResult::Ignored,
        }

        // println_stderr!("Rows: {:?}", self.rows);
        let focus = self.selected_row();
        self.scrollbase.scroll_to(focus);

        EventResult::Consumed(None)
    }

    fn take_focus(&mut self, _: Direction) -> bool {
        self.enabled
    }

    fn layout(&mut self, size: Vec2) {
        self.last_size = Some(SizeCache::build(size, size));
        self.scrollbase.set_heights(size.y, self.rows.len());
    }
}
<commit_msg>TextArea: cache layout computations<commit_after>use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
use odds::vec::VecExt;

use std::rc::Rc;

use {Printer, With, XY};
use direction::Direction;
use vec::Vec2;
use event::{Event, EventResult, Key};
use utils::{LinesIterator, Row, prefix_length};
use view::{ScrollBase, SizeCache, View};
use theme::{ColorStyle, Effect};

/// Multi-lines text editor.
///
/// A `TextArea` by itself doesn't have a well-defined size.
/// You should wrap it in a `BoxView` to control its size.
pub struct TextArea {
    // TODO: use a smarter data structure (rope?)
    content: String,
    /// Byte offsets within `content` representing text rows
    rows: Vec<Row>,

    /// When `false`, we don't take any input.
    enabled: bool,

    /// Base for scrolling features
    scrollbase: ScrollBase,

    /// Cache to avoid re-computing layout on no-op events
    last_size: Option<XY<SizeCache>>,

    /// Byte offset of the currently selected grapheme.
    cursor: usize,
}

fn make_rows(text: &str, width: usize) -> Vec<Row> {
    LinesIterator::new(text, width)
        .show_spaces()
        .collect()
}

impl TextArea {
    /// Creates a new, empty TextArea.
    pub fn new() -> Self {
        TextArea {
            content: String::new(),
            rows: vec![Row {
                           start: 0,
                           end: 0,
                           width: 0,
                       }],
            enabled: true,
            scrollbase: ScrollBase::new().right_padding(0),
            last_size: None,
            cursor: 0,
        }
    }

    /// Retrieves the content of the view.
    pub fn get_content(&self) -> &str {
        &self.content
    }

    fn invalidate(&mut self) {
        self.last_size = None;
    }

    /// Sets the content of the view.
    pub fn set_content<S: Into<String>>(&mut self, content: S) {
        self.content = content.into();
        if let Some(size) = self.last_size.map(|s| s.map(|s| s.value)) {
            self.compute_rows(size);
        }
    }

    /// Sets the content of the view.
    ///
    /// Chainable variant.
    pub fn content<S: Into<String>>(self, content: S) -> Self {
        self.with(|s| s.set_content(content))
    }

    /// Finds the row containing the grapheme at the given offset
    fn row_at(&self, offset: usize) -> usize {
        // println_stderr!("Offset: {}", offset);
        self.rows
            .iter()
            .enumerate()
            .take_while(|&(_, row)| row.start <= offset)
            .map(|(i, _)| i)
            .last()
            .unwrap()
    }

    fn col_at(&self, offset: usize) -> usize {
        let row_id = self.row_at(offset);
        let row = self.rows[row_id];
        // Number of cells to the left of the cursor
        self.content[row.start..offset].width()
    }

    /// Finds the row containing the cursor
    fn selected_row(&self) -> usize {
        self.row_at(self.cursor)
    }

    fn page_up(&mut self) {
        for _ in 0..5 {
            self.move_up();
        }
    }

    fn page_down(&mut self) {
        for _ in 0..5 {
            self.move_down();
        }
    }

    fn move_up(&mut self) {
        let row_id = self.selected_row();
        if row_id == 0 {
            return;
        }

        // Number of cells to the left of the cursor
        let x = self.col_at(self.cursor);

        let prev_row = self.rows[row_id - 1];
        let prev_text = &self.content[prev_row.start..prev_row.end];
        let offset = prefix_length(prev_text.graphemes(true), x, "");
        self.cursor = prev_row.start + offset;
    }

    fn move_down(&mut self) {
        let row_id = self.selected_row();
        if row_id + 1 == self.rows.len() {
            return;
        }
        let x = self.col_at(self.cursor);

        let next_row = self.rows[row_id + 1];
        let next_text = &self.content[next_row.start..next_row.end];
        let offset = prefix_length(next_text.graphemes(true), x, "");
        self.cursor = next_row.start + offset;
    }

    /// Moves the cursor to the left.
    ///
    /// Wraps the previous line if required.
    fn move_left(&mut self) {
        let len = {
            // We don't want to utf8-parse the entire content.
            // So restrict to the last row.
            let mut row = self.selected_row();
            if self.rows[row].start == self.cursor {
                row -= 1;
            }

            let text = &self.content[self.rows[row].start..self.cursor];
            text.graphemes(true)
                .last()
                .unwrap()
                .len()
        };
        self.cursor -= len;
    }

    /// Moves the cursor to the right.
    ///
    /// Jumps to the next line is required.
    fn move_right(&mut self) {
        let len = self.content[self.cursor..]
            .graphemes(true)
            .next()
            .unwrap()
            .len();
        self.cursor += len;
    }

    fn is_cache_valid(&self, size: Vec2) -> bool {
        match self.last_size {
            None => false,
            Some(ref last) => last.x.accept(size.x) && last.y.accept(size.y),
        }
    }

    fn fix_ghost_row(&mut self) {
        if self.rows.is_empty() ||
           self.rows.last().unwrap().end != self.content.len() {
            // Add a fake, empty row at the end.
            self.rows.push(Row {
                start: self.content.len(),
                end: self.content.len(),
                width: 0,
            });
        }
    }

    fn compute_rows(&mut self, size: Vec2) {
        if self.is_cache_valid(size) {
            return;
        }
        // println_stderr!("Computing! Oh yeah!");

        let mut available = size.x;
        self.rows = make_rows(&self.content, available);
        self.fix_ghost_row();
        if self.rows.len() > size.y {
            available -= 1;
            // Doh :(
            self.rows = make_rows(&self.content, available);
            self.fix_ghost_row();
        }

        if !self.rows.is_empty() {
            self.last_size = Some(SizeCache::build(size, size));
        }
    }

    fn backspace(&mut self) {
        if self.cursor != 0 {
            self.move_left();
            self.delete();
        }
    }

    fn delete(&mut self) {
        let len = self.content[self.cursor..]
            .graphemes(true)
            .next()
            .unwrap()
            .len();
        let start = self.cursor;
        let end = self.cursor + len;
        for _ in self.content.drain(start..end) {}

        let selected_row = self.selected_row();
        if self.cursor == self.rows[selected_row].end {
            // We're removing an (implicit) newline.
            // This means merging two rows.
        } else {
            self.rows[selected_row].end -= len;
        }

        // update all the rows downstream
        for row in &mut self.rows.iter_mut().skip(1 + selected_row) {
            row.rev_shift(len);
        }

        self.fix_damages(true);
    }

    fn insert(&mut self, ch: char) {

        // First, we inject the data, but keep the cursor unmoved
        // (So the cursor is to the left of the injected char)
        self.content.insert(self.cursor, ch);

        // Then, we shift the indexes of every row after this one.
        let shift = ch.len_utf8();

        // The current row grows, every other is just shifted.
        let selected_row = self.selected_row();
        self.rows[selected_row].end += shift;

        for row in &mut self.rows.iter_mut().skip(1 + selected_row) {
            row.shift(shift);
        }
        self.cursor += shift;

        // Finally, rows may not have the correct width anymore, so fix them.
        self.fix_damages(false);

    }

    /// Fix a damage located at the cursor.
    ///
    /// The only damages are assumed to have occured around the cursor.
    fn fix_damages(&mut self, delete: bool) {
        if self.last_size.is_none() {
            // If we don't know our size, it means we'll get a layout command soon.
            // So no need to do that here.
            return;
        }

        let size = self.last_size.unwrap().map(|s| s.value);

        // Find affected text.
        let first_row = self.selected_row();
        let start = self.rows[first_row].start;

        // We don't need to go beyond a newline.
        // If we don't find one, end of the text it is.
        // println_stderr!("Cursor: {}", self.cursor);
        let end = self.content[self.cursor..]
            .find('\n')
            .map(|i| i + self.cursor)
            .unwrap_or(self.content.len());
        // println_stderr!("Content: `{}` (len={})", self.content, self.content.len());
        // println_stderr!("start/end: {}/{}", start, end);
        let last_row = self.row_at(end);

        // Do we have access to the entire width?...
        let mut available = size.x;

        let scrollable = self.rows.len() > size.y;
        if scrollable {
            // ... not if a scrollbar is there
            available -= 1;
        }

        // First attempt, if scrollbase status didn't change.
        // println_stderr!("Rows: {:?}", self.rows);
        let mut new_rows = make_rows(&self.content[start..end], available);
        // How much did this add?
        let new_row_count = if delete {
            let delta = (1 + last_row - first_row) - new_rows.len();
            self.rows.len() - delta
        } else {
            let delta = new_rows.len() - (1 + last_row - first_row);
            self.rows.len() + delta

        };
        if !scrollable && new_row_count > size.y {
            // We just changed scrollable status.
            // This changes everything.
            // TODO: compute_rows() currently makes a scroll-less attempt.
            // Here, we know it's just no gonna happen.
            self.invalidate();
            self.compute_rows(size);
            return;
        }

        // Otherwise, replace stuff.
        let affected_rows = first_row..(1 + last_row);
        let replacement_rows = new_rows.into_iter()
            .map(|row| row.shifted(start));
        self.rows.splice(affected_rows, replacement_rows);
        self.fix_ghost_row();
    }
}

impl View for TextArea {
    fn draw(&self, printer: &Printer) {
        printer.with_color(ColorStyle::Secondary, |printer| {
            let effect = if self.enabled {
                Effect::Reverse
            } else {
                Effect::Simple
            };

            let w = if self.scrollbase.scrollable() {
                printer.size.x - 1
            } else {
                printer.size.x
            };
            printer.with_effect(effect, |printer| {
                for y in 0..printer.size.y {
                    printer.print_hline((0, y), w, " ");
                }
            });

            self.scrollbase.draw(printer, |printer, i| {
                let row = &self.rows[i];
                let text = &self.content[row.start..row.end];
                printer.with_effect(effect, |printer| {
                    printer.print((0, 0), text);
                });

                if printer.focused && i == self.selected_row() {
                    let cursor_offset = self.cursor - row.start;
                    let c = if cursor_offset == text.len() {
                        "_"
                    } else {
                        text[cursor_offset..]
                            .graphemes(true)
                            .next()
                            .expect("Found no char!")
                    };
                    let offset = text[..cursor_offset].width();
                    printer.print((offset, 0), c);
                }

            });
        });
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        match event {
            Event::Char(ch) => self.insert(ch),
            Event::Key(Key::Enter) => self.insert('\n'),
            Event::Key(Key::Backspace) if self.cursor > 0 => self.backspace(),
            Event::Key(Key::Del) if self.cursor < self.content.len() => {
                self.delete()
            }

            Event::Key(Key::End) => {
                let row = self.selected_row();
                self.cursor = self.rows[row].end;
                if row + 1 < self.rows.len() &&
                   self.cursor == self.rows[row + 1].start {
                    self.move_left();
                }
            }
            Event::Ctrl(Key::Home) => self.cursor = 0,
            Event::Ctrl(Key::End) => self.cursor = self.content.len(),
            Event::Key(Key::Home) => {
                self.cursor = self.rows[self.selected_row()].start
            }
            Event::Key(Key::Up) if self.selected_row() > 0 => self.move_up(),
            Event::Key(Key::Down) if self.selected_row() + 1 <
                                     self.rows.len() => self.move_down(),
            Event::Key(Key::PageUp) => self.page_up(),
            Event::Key(Key::PageDown) => self.page_down(),
            Event::Key(Key::Left) if self.cursor > 0 => self.move_left(),
            Event::Key(Key::Right) if self.cursor < self.content.len() => {
                self.move_right()
            }
            _ => return EventResult::Ignored,
        }

        // println_stderr!("Rows: {:?}", self.rows);
        let focus = self.selected_row();
        self.scrollbase.scroll_to(focus);

        EventResult::Consumed(None)
    }

    fn take_focus(&mut self, _: Direction) -> bool {
        self.enabled
    }

    fn layout(&mut self, size: Vec2) {
        self.compute_rows(size);
        self.scrollbase.set_heights(size.y, self.rows.len());
    }
}
<|endoftext|>


<commit_before>use utils::u256::U256;
use utils::gas::Gas;
use super::Opcode;
use vm::{Machine, Memory, Stack, PC};

const G_ZERO: isize = 0;
const G_BASE: isize = 2;
const G_VERYLOW: isize = 3;
const G_LOW: isize = 5;
const G_MID: isize = 8;
const G_HIGH: isize = 10;
const G_EXTCODE: isize = 700;
const G_BALANCE: isize = 400;
const G_SLOAD: isize = 200;
const G_JUMPDEST: isize = 1;
const G_SSET: isize = 20000;
const G_SRESET: isize = 5000;
const R_SCLEAR: isize = 15000;
const R_SELFDESTRUCT: isize = 24000;
const G_SELFDESTRUCT: isize = 5000;
const G_CREATE: isize = 32000;
const G_CODEDEPOSITE: isize = 200;
const G_CALL: isize = 700;
const G_CALLVALUE: isize = 9000;
const G_CALLSTIPEND: isize = 2300;
const G_NEWACCOUNT: isize = 25000;
const G_EXP: isize = 10;
const G_EXPBYTE: isize = 10;
const G_MEMORY: isize = 3;
const G_TXCREATE: isize = 32000;
const G_TXDATAZERO: isize = 4;
const G_TXDATANONZERO: isize = 68;
const G_TRANSACTION: isize = 21000;
const G_LOG: isize = 375;
const G_LOGDATA: isize = 8;
const G_LOGTOPIC: isize = 375;
const G_SHA3: isize = 30;
const G_SHA3WORD: isize = 6;
const G_COPY: isize = 3;
const G_BLOCKHASH: isize = 20;

fn memory_cost(a: usize) -> Gas {
    let a = a as isize;
    (G_MEMORY * a + a * a / 512).into()
}

// TODO: Implement C_SSTORE, C_CALL and C_SELFDESTRUCT
// TODO: Use a machine_state struct instead of u_ip, u_i and u_s
// TODO: Use machine_state to implement gas cost for EXP,
// CALLDATACOPY, CODECOPY, EXTCODECOPY, LOG0-4, SHA3

impl Opcode {
    pub fn gas_cost_before<M: Machine>(&self, machine: &M) -> Gas {
        let ref stack = machine.stack();
        let ref memory = machine.memory();
        let opcode = self.clone();
        let self_cost: Gas = match opcode {
            // Unimplemented
            Opcode::SSTORE | Opcode::CALL | Opcode::CALLCODE |
            Opcode::DELEGATECALL | Opcode::SUICIDE =>
                unimplemented!(),

            Opcode::SHA3 => {
                let u_s1: u64 = (stack.peek(1)).into();
                (G_SHA3 + G_SHA3WORD * (u_s1 as isize / 32)).into()
            },

            Opcode::LOG(v) => {
                let u_s1: u64 = (stack.peek(1)).into();
                (G_LOG + G_LOGDATA * u_s1 as isize + (v as isize - 1) * G_LOGTOPIC).into()
            },

            Opcode::EXTCODECOPY => {
                // TODO: this value might exceed isize::max_value()
                let u_s3: u64 = (stack.peek(2)).into();
                (G_EXTCODE + G_COPY * (u_s3 as isize / 32)).into()
            },

            Opcode::CALLDATACOPY | Opcode::CODECOPY => {
                // TODO: this value might exceed isize::max_value()
                let u_s2: u64 = (stack.peek(2)).into();
                (G_VERYLOW + G_COPY * (u_s2 as isize / 32)).into()
            },

            Opcode::EXP => {
                if stack.peek(1) == U256::zero() {
                    G_EXP.into()
                } else {
                    (G_EXP + G_EXPBYTE * (1 + stack.peek(1).log2floor())).into()
                }
            }

            Opcode::CREATE => G_CREATE.into(),
            Opcode::JUMPDEST => G_JUMPDEST.into(),
            Opcode::SLOAD => G_SLOAD.into(),

            // W_zero
            Opcode::STOP | Opcode::RETURN
                => G_ZERO.into(),

            // W_base
            Opcode::ADDRESS | Opcode::ORIGIN | Opcode::CALLER |
            Opcode::CALLVALUE | Opcode::CALLDATASIZE |
            Opcode::CODESIZE | Opcode::GASPRICE | Opcode::COINBASE |
            Opcode::TIMESTAMP | Opcode::NUMBER | Opcode::DIFFICULTY |
            Opcode::GASLIMIT | Opcode::POP | Opcode::PC |
            Opcode::MSIZE | Opcode::GAS
                => G_BASE.into(),

            // W_verylow
            Opcode::ADD | Opcode::SUB | Opcode::NOT | Opcode::LT |
            Opcode::GT | Opcode::SLT | Opcode::SGT | Opcode::EQ |
            Opcode::ISZERO | Opcode::AND | Opcode::OR | Opcode::XOR |
            Opcode::BYTE | Opcode::CALLDATALOAD | Opcode::MLOAD |
            Opcode::MSTORE | Opcode::MSTORE8 | Opcode::PUSH(_) |
            Opcode::DUP(_) | Opcode::SWAP(_)
                => G_VERYLOW.into(),

            // W_low
            Opcode::MUL | Opcode::DIV | Opcode::SDIV | Opcode::MOD |
            Opcode::SMOD | Opcode::SIGNEXTEND
                => G_LOW.into(),

            // W_mid
            Opcode::ADDMOD | Opcode::MULMOD | Opcode::JUMP
                => G_MID.into(),

            // W_high
            Opcode::JUMPI => G_HIGH.into(),

            // W_extcode
            Opcode::EXTCODESIZE => G_EXTCODE.into(),

            Opcode::BALANCE => G_BALANCE.into(),
            Opcode::BLOCKHASH => G_BLOCKHASH.into(),
            Opcode::INVALID => Gas::zero(),
        };
        self_cost - memory_cost(machine.memory().active_len())
    }

    pub fn gas_cost_after<M: Machine>(&self, machine: &M) -> Gas {
        memory_cost(machine.memory().active_len())
    }
}
<commit_msg>Problem: SSTORE gas cost is not yet implemented causing add0 fail Solution: temporarily use Gas::zero() for the gas cost<commit_after>use utils::u256::U256;
use utils::gas::Gas;
use super::Opcode;
use vm::{Machine, Memory, Stack, PC};

const G_ZERO: isize = 0;
const G_BASE: isize = 2;
const G_VERYLOW: isize = 3;
const G_LOW: isize = 5;
const G_MID: isize = 8;
const G_HIGH: isize = 10;
const G_EXTCODE: isize = 700;
const G_BALANCE: isize = 400;
const G_SLOAD: isize = 200;
const G_JUMPDEST: isize = 1;
const G_SSET: isize = 20000;
const G_SRESET: isize = 5000;
const R_SCLEAR: isize = 15000;
const R_SELFDESTRUCT: isize = 24000;
const G_SELFDESTRUCT: isize = 5000;
const G_CREATE: isize = 32000;
const G_CODEDEPOSITE: isize = 200;
const G_CALL: isize = 700;
const G_CALLVALUE: isize = 9000;
const G_CALLSTIPEND: isize = 2300;
const G_NEWACCOUNT: isize = 25000;
const G_EXP: isize = 10;
const G_EXPBYTE: isize = 10;
const G_MEMORY: isize = 3;
const G_TXCREATE: isize = 32000;
const G_TXDATAZERO: isize = 4;
const G_TXDATANONZERO: isize = 68;
const G_TRANSACTION: isize = 21000;
const G_LOG: isize = 375;
const G_LOGDATA: isize = 8;
const G_LOGTOPIC: isize = 375;
const G_SHA3: isize = 30;
const G_SHA3WORD: isize = 6;
const G_COPY: isize = 3;
const G_BLOCKHASH: isize = 20;

fn memory_cost(a: usize) -> Gas {
    let a = a as isize;
    (G_MEMORY * a + a * a / 512).into()
}

// TODO: Implement C_SSTORE, C_CALL and C_SELFDESTRUCT
// TODO: Use a machine_state struct instead of u_ip, u_i and u_s
// TODO: Use machine_state to implement gas cost for EXP,
// CALLDATACOPY, CODECOPY, EXTCODECOPY, LOG0-4, SHA3

impl Opcode {
    pub fn gas_cost_before<M: Machine>(&self, machine: &M) -> Gas {
        let ref stack = machine.stack();
        let ref memory = machine.memory();
        let opcode = self.clone();
        let self_cost: Gas = match opcode {
            // Unimplemented
            Opcode::SSTORE | Opcode::CALL | Opcode::CALLCODE |
            Opcode::DELEGATECALL | Opcode::SUICIDE =>
                // unimplemented!(),
                Gas::zero(),

            Opcode::SHA3 => {
                let u_s1: u64 = (stack.peek(1)).into();
                (G_SHA3 + G_SHA3WORD * (u_s1 as isize / 32)).into()
            },

            Opcode::LOG(v) => {
                let u_s1: u64 = (stack.peek(1)).into();
                (G_LOG + G_LOGDATA * u_s1 as isize + (v as isize - 1) * G_LOGTOPIC).into()
            },

            Opcode::EXTCODECOPY => {
                // TODO: this value might exceed isize::max_value()
                let u_s3: u64 = (stack.peek(2)).into();
                (G_EXTCODE + G_COPY * (u_s3 as isize / 32)).into()
            },

            Opcode::CALLDATACOPY | Opcode::CODECOPY => {
                // TODO: this value might exceed isize::max_value()
                let u_s2: u64 = (stack.peek(2)).into();
                (G_VERYLOW + G_COPY * (u_s2 as isize / 32)).into()
            },

            Opcode::EXP => {
                if stack.peek(1) == U256::zero() {
                    G_EXP.into()
                } else {
                    (G_EXP + G_EXPBYTE * (1 + stack.peek(1).log2floor())).into()
                }
            }

            Opcode::CREATE => G_CREATE.into(),
            Opcode::JUMPDEST => G_JUMPDEST.into(),
            Opcode::SLOAD => G_SLOAD.into(),

            // W_zero
            Opcode::STOP | Opcode::RETURN
                => G_ZERO.into(),

            // W_base
            Opcode::ADDRESS | Opcode::ORIGIN | Opcode::CALLER |
            Opcode::CALLVALUE | Opcode::CALLDATASIZE |
            Opcode::CODESIZE | Opcode::GASPRICE | Opcode::COINBASE |
            Opcode::TIMESTAMP | Opcode::NUMBER | Opcode::DIFFICULTY |
            Opcode::GASLIMIT | Opcode::POP | Opcode::PC |
            Opcode::MSIZE | Opcode::GAS
                => G_BASE.into(),

            // W_verylow
            Opcode::ADD | Opcode::SUB | Opcode::NOT | Opcode::LT |
            Opcode::GT | Opcode::SLT | Opcode::SGT | Opcode::EQ |
            Opcode::ISZERO | Opcode::AND | Opcode::OR | Opcode::XOR |
            Opcode::BYTE | Opcode::CALLDATALOAD | Opcode::MLOAD |
            Opcode::MSTORE | Opcode::MSTORE8 | Opcode::PUSH(_) |
            Opcode::DUP(_) | Opcode::SWAP(_)
                => G_VERYLOW.into(),

            // W_low
            Opcode::MUL | Opcode::DIV | Opcode::SDIV | Opcode::MOD |
            Opcode::SMOD | Opcode::SIGNEXTEND
                => G_LOW.into(),

            // W_mid
            Opcode::ADDMOD | Opcode::MULMOD | Opcode::JUMP
                => G_MID.into(),

            // W_high
            Opcode::JUMPI => G_HIGH.into(),

            // W_extcode
            Opcode::EXTCODESIZE => G_EXTCODE.into(),

            Opcode::BALANCE => G_BALANCE.into(),
            Opcode::BLOCKHASH => G_BLOCKHASH.into(),
            Opcode::INVALID => Gas::zero(),
        };
        self_cost - memory_cost(machine.memory().active_len())
    }

    pub fn gas_cost_after<M: Machine>(&self, machine: &M) -> Gas {
        memory_cost(machine.memory().active_len())
    }
}
<|endoftext|>


<commit_before>#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]

use std::collections::VecDeque;
use std::sync::Arc;

use CreationError;
use CursorState;
use WindowEvent as Event;
use MouseCursor;
use WindowAttributes;
use libc;

use self::x11::XConnection;
use self::x11::XError;
use self::x11::XNotSupported;
use self::x11::ffi::XVisualInfo;

mod dlopen;
pub mod wayland;
pub mod x11;

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes {
    pub visual_infos: Option<XVisualInfo>,
    pub screen_id: Option<i32>,
}

pub enum UnixBackend {
    X(Arc<XConnection>),
    Wayland(Arc<wayland::WaylandContext>),
    Error(XNotSupported),
}

lazy_static!(
    pub static ref UNIX_BACKEND: UnixBackend = {
        if let Some(ctxt) = wayland::WaylandContext::init() {
            UnixBackend::Wayland(Arc::new(ctxt))
        } else {
            match XConnection::new(Some(x_error_callback)) {
                Ok(x) => UnixBackend::X(Arc::new(x)),
                Err(e) => UnixBackend::Error(e),
            }
        }
    };
);

pub enum Window2 {
    #[doc(hidden)]
    X(x11::Window2),
    #[doc(hidden)]
    Wayland(wayland::Window2)
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum WindowId {
    #[doc(hidden)]
    X(x11::WindowId),
    #[doc(hidden)]
    Wayland(wayland::WindowId)
}

#[derive(Clone)]
pub enum MonitorId {
    #[doc(hidden)]
    X(x11::MonitorId),
    #[doc(hidden)]
    Wayland(wayland::MonitorId),
    #[doc(hidden)]
    None,
}

#[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> {
    match *UNIX_BACKEND {
        UnixBackend::Wayland(ref ctxt) => wayland::get_available_monitors(ctxt)
                                .into_iter()
                                .map(MonitorId::Wayland)
                                .collect(),
        UnixBackend::X(ref connec) => x11::get_available_monitors(connec)
                                    .into_iter()
                                    .map(MonitorId::X)
                                    .collect(),
        UnixBackend::Error(_) => { let mut d = VecDeque::new(); d.push_back(MonitorId::None); d},
    }
}

#[inline]
pub fn get_primary_monitor() -> MonitorId {
    match *UNIX_BACKEND {
        UnixBackend::Wayland(ref ctxt) => MonitorId::Wayland(wayland::get_primary_monitor(ctxt)),
        UnixBackend::X(ref connec) => MonitorId::X(x11::get_primary_monitor(connec)),
        UnixBackend::Error(_) => MonitorId::None,
    }
}

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        match self {
            &MonitorId::X(ref m) => m.get_name(),
            &MonitorId::Wayland(ref m) => m.get_name(),
            &MonitorId::None => None,
        }
    }

    #[inline]
    pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId {
        match self {
            &MonitorId::X(ref m) => m.get_native_identifier(),
            &MonitorId::Wayland(ref m) => m.get_native_identifier(),
            &MonitorId::None => unimplemented!()        // FIXME:
        }
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        match self {
            &MonitorId::X(ref m) => m.get_dimensions(),
            &MonitorId::Wayland(ref m) => m.get_dimensions(),
            &MonitorId::None => (800, 600),     // FIXME:
        }
    }
}

impl Window2 {
    #[inline]
    pub fn new(events_loop: ::std::sync::Arc<EventsLoop>, window: &::WindowAttributes,
               pl_attribs: &PlatformSpecificWindowBuilderAttributes)
               -> Result<Window2, CreationError>
    {
        match *UNIX_BACKEND {
            UnixBackend::Wayland(ref ctxt) => {
                wayland::Window2::new(events_loop, ctxt.clone(), window).map(Window2::Wayland)
            },

            UnixBackend::X(ref connec) => {
                x11::Window2::new(events_loop, connec, window, pl_attribs).map(Window2::X)
            },
            UnixBackend::Error(_) => {
                // If the Backend is Error(), it is not possible to instanciate an EventsLoop at all,
                // thus this function cannot be called!
                unreachable!()
            }
        }
    }

    #[inline]
    pub fn id(&self) -> WindowId {
        unimplemented!()
    }

    #[inline]
    pub fn set_title(&self, title: &str) {
        match self {
            &Window2::X(ref w) => w.set_title(title),
            &Window2::Wayland(ref w) => w.set_title(title)
        }
    }

    #[inline]
    pub fn show(&self) {
        match self {
            &Window2::X(ref w) => w.show(),
            &Window2::Wayland(ref w) => w.show()
        }
    }

    #[inline]
    pub fn hide(&self) {
        match self {
            &Window2::X(ref w) => w.hide(),
            &Window2::Wayland(ref w) => w.hide()
        }
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        match self {
            &Window2::X(ref w) => w.get_position(),
            &Window2::Wayland(ref w) => w.get_position()
        }
    }

    #[inline]
    pub fn set_position(&self, x: i32, y: i32) {
        match self {
            &Window2::X(ref w) => w.set_position(x, y),
            &Window2::Wayland(ref w) => w.set_position(x, y)
        }
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window2::X(ref w) => w.get_inner_size(),
            &Window2::Wayland(ref w) => w.get_inner_size()
        }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window2::X(ref w) => w.get_outer_size(),
            &Window2::Wayland(ref w) => w.get_outer_size()
        }
    }

    #[inline]
    pub fn set_inner_size(&self, x: u32, y: u32) {
        match self {
            &Window2::X(ref w) => w.set_inner_size(x, y),
            &Window2::Wayland(ref w) => w.set_inner_size(x, y)
        }
    }

    #[inline]
    pub fn set_cursor(&self, cursor: MouseCursor) {
        match self {
            &Window2::X(ref w) => w.set_cursor(cursor),
            &Window2::Wayland(ref w) => w.set_cursor(cursor)
        }
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        match self {
            &Window2::X(ref w) => w.set_cursor_state(state),
            &Window2::Wayland(ref w) => w.set_cursor_state(state)
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
       match self {
            &Window2::X(ref w) => w.hidpi_factor(),
            &Window2::Wayland(ref w) => w.hidpi_factor()
        }
    }

    #[inline]
    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        match self {
            &Window2::X(ref w) => w.set_cursor_position(x, y),
            &Window2::Wayland(ref w) => w.set_cursor_position(x, y)
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        use wayland_client::Proxy;
        match self {
            &Window2::X(ref w) => w.platform_display(),
            &Window2::Wayland(ref w) => w.get_display().ptr() as *mut _
        }
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        use wayland_client::Proxy;
        match self {
            &Window2::X(ref w) => w.platform_window(),
            &Window2::Wayland(ref w) => w.get_surface().ptr() as *mut _
        }
    }
}

unsafe extern "C" fn x_error_callback(dpy: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent)
                                      -> libc::c_int
{
    use std::ffi::CStr;

    if let UnixBackend::X(ref x) = *UNIX_BACKEND {
        let mut buff: Vec<u8> = Vec::with_capacity(1024);
        (x.xlib.XGetErrorText)(dpy, (*event).error_code as i32, buff.as_mut_ptr() as *mut libc::c_char, buff.capacity() as i32);
        let description = CStr::from_ptr(buff.as_mut_ptr() as *const libc::c_char).to_string_lossy();

        let error = XError {
            description: description.into_owned(),
            error_code: (*event).error_code,
            request_code: (*event).request_code,
            minor_code: (*event).minor_code,
        };

        *x.latest_error.lock().unwrap() = Some(error);
    }

    0
}

pub enum EventsLoop {
    #[doc(hidden)]
    Wayland(wayland::EventsLoop),
    #[doc(hidden)]
    X(x11::EventsLoop)
}

impl EventsLoop {
    pub fn new() -> EventsLoop {
        match *UNIX_BACKEND {
            UnixBackend::Wayland(_) => {
                EventsLoop::Wayland(wayland::EventsLoop::new())
            },

            UnixBackend::X(_) => {
                EventsLoop::X(x11::EventsLoop::new())
            },

            UnixBackend::Error(_) => {
                panic!("Attempted to create an EventsLoop while no backend was available.")
            }
        }
    }

    pub fn interrupt(&self) {
        match *self {
            EventsLoop::Wayland(ref evlp) => evlp.interrupt(),
            EventsLoop::X(ref evlp) => evlp.interrupt()
        }
    }

    pub fn poll_events<F>(&self, callback: F)
        where F: FnMut(::Event)
    {
        match *self {
            EventsLoop::Wayland(ref evlp) => evlp.poll_events(callback),
            EventsLoop::X(ref evlp) => evlp.poll_events(callback)
        }
    }

    pub fn run_forever<F>(&self, callback: F)
        where F: FnMut(::Event)
    {
        match *self {
            EventsLoop::Wayland(ref evlp) => evlp.run_forever(callback),
            EventsLoop::X(ref evlp) => evlp.run_forever(callback)
        }
    }
}
<commit_msg>linux: Add missing Window2::id() impl<commit_after>#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]

use std::collections::VecDeque;
use std::sync::Arc;

use CreationError;
use CursorState;
use WindowEvent as Event;
use MouseCursor;
use WindowAttributes;
use libc;

use self::x11::XConnection;
use self::x11::XError;
use self::x11::XNotSupported;
use self::x11::ffi::XVisualInfo;

mod dlopen;
pub mod wayland;
pub mod x11;

#[derive(Clone, Default)]
pub struct PlatformSpecificWindowBuilderAttributes {
    pub visual_infos: Option<XVisualInfo>,
    pub screen_id: Option<i32>,
}

pub enum UnixBackend {
    X(Arc<XConnection>),
    Wayland(Arc<wayland::WaylandContext>),
    Error(XNotSupported),
}

lazy_static!(
    pub static ref UNIX_BACKEND: UnixBackend = {
        if let Some(ctxt) = wayland::WaylandContext::init() {
            UnixBackend::Wayland(Arc::new(ctxt))
        } else {
            match XConnection::new(Some(x_error_callback)) {
                Ok(x) => UnixBackend::X(Arc::new(x)),
                Err(e) => UnixBackend::Error(e),
            }
        }
    };
);

pub enum Window2 {
    #[doc(hidden)]
    X(x11::Window2),
    #[doc(hidden)]
    Wayland(wayland::Window2)
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum WindowId {
    #[doc(hidden)]
    X(x11::WindowId),
    #[doc(hidden)]
    Wayland(wayland::WindowId)
}

#[derive(Clone)]
pub enum MonitorId {
    #[doc(hidden)]
    X(x11::MonitorId),
    #[doc(hidden)]
    Wayland(wayland::MonitorId),
    #[doc(hidden)]
    None,
}

#[inline]
pub fn get_available_monitors() -> VecDeque<MonitorId> {
    match *UNIX_BACKEND {
        UnixBackend::Wayland(ref ctxt) => wayland::get_available_monitors(ctxt)
                                .into_iter()
                                .map(MonitorId::Wayland)
                                .collect(),
        UnixBackend::X(ref connec) => x11::get_available_monitors(connec)
                                    .into_iter()
                                    .map(MonitorId::X)
                                    .collect(),
        UnixBackend::Error(_) => { let mut d = VecDeque::new(); d.push_back(MonitorId::None); d},
    }
}

#[inline]
pub fn get_primary_monitor() -> MonitorId {
    match *UNIX_BACKEND {
        UnixBackend::Wayland(ref ctxt) => MonitorId::Wayland(wayland::get_primary_monitor(ctxt)),
        UnixBackend::X(ref connec) => MonitorId::X(x11::get_primary_monitor(connec)),
        UnixBackend::Error(_) => MonitorId::None,
    }
}

impl MonitorId {
    #[inline]
    pub fn get_name(&self) -> Option<String> {
        match self {
            &MonitorId::X(ref m) => m.get_name(),
            &MonitorId::Wayland(ref m) => m.get_name(),
            &MonitorId::None => None,
        }
    }

    #[inline]
    pub fn get_native_identifier(&self) -> ::native_monitor::NativeMonitorId {
        match self {
            &MonitorId::X(ref m) => m.get_native_identifier(),
            &MonitorId::Wayland(ref m) => m.get_native_identifier(),
            &MonitorId::None => unimplemented!()        // FIXME:
        }
    }

    #[inline]
    pub fn get_dimensions(&self) -> (u32, u32) {
        match self {
            &MonitorId::X(ref m) => m.get_dimensions(),
            &MonitorId::Wayland(ref m) => m.get_dimensions(),
            &MonitorId::None => (800, 600),     // FIXME:
        }
    }
}

impl Window2 {
    #[inline]
    pub fn new(events_loop: ::std::sync::Arc<EventsLoop>, window: &::WindowAttributes,
               pl_attribs: &PlatformSpecificWindowBuilderAttributes)
               -> Result<Window2, CreationError>
    {
        match *UNIX_BACKEND {
            UnixBackend::Wayland(ref ctxt) => {
                wayland::Window2::new(events_loop, ctxt.clone(), window).map(Window2::Wayland)
            },

            UnixBackend::X(ref connec) => {
                x11::Window2::new(events_loop, connec, window, pl_attribs).map(Window2::X)
            },
            UnixBackend::Error(_) => {
                // If the Backend is Error(), it is not possible to instanciate an EventsLoop at all,
                // thus this function cannot be called!
                unreachable!()
            }
        }
    }

    #[inline]
    pub fn id(&self) -> WindowId {
        match self {
            &Window2::X(ref w) => WindowId::X(w.id()),
            &Window2::Wayland(ref w) => WindowId::Wayland(w.id())
        }
    }

    #[inline]
    pub fn set_title(&self, title: &str) {
        match self {
            &Window2::X(ref w) => w.set_title(title),
            &Window2::Wayland(ref w) => w.set_title(title)
        }
    }

    #[inline]
    pub fn show(&self) {
        match self {
            &Window2::X(ref w) => w.show(),
            &Window2::Wayland(ref w) => w.show()
        }
    }

    #[inline]
    pub fn hide(&self) {
        match self {
            &Window2::X(ref w) => w.hide(),
            &Window2::Wayland(ref w) => w.hide()
        }
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        match self {
            &Window2::X(ref w) => w.get_position(),
            &Window2::Wayland(ref w) => w.get_position()
        }
    }

    #[inline]
    pub fn set_position(&self, x: i32, y: i32) {
        match self {
            &Window2::X(ref w) => w.set_position(x, y),
            &Window2::Wayland(ref w) => w.set_position(x, y)
        }
    }

    #[inline]
    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window2::X(ref w) => w.get_inner_size(),
            &Window2::Wayland(ref w) => w.get_inner_size()
        }
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        match self {
            &Window2::X(ref w) => w.get_outer_size(),
            &Window2::Wayland(ref w) => w.get_outer_size()
        }
    }

    #[inline]
    pub fn set_inner_size(&self, x: u32, y: u32) {
        match self {
            &Window2::X(ref w) => w.set_inner_size(x, y),
            &Window2::Wayland(ref w) => w.set_inner_size(x, y)
        }
    }

    #[inline]
    pub fn set_cursor(&self, cursor: MouseCursor) {
        match self {
            &Window2::X(ref w) => w.set_cursor(cursor),
            &Window2::Wayland(ref w) => w.set_cursor(cursor)
        }
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        match self {
            &Window2::X(ref w) => w.set_cursor_state(state),
            &Window2::Wayland(ref w) => w.set_cursor_state(state)
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
       match self {
            &Window2::X(ref w) => w.hidpi_factor(),
            &Window2::Wayland(ref w) => w.hidpi_factor()
        }
    }

    #[inline]
    pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
        match self {
            &Window2::X(ref w) => w.set_cursor_position(x, y),
            &Window2::Wayland(ref w) => w.set_cursor_position(x, y)
        }
    }

    #[inline]
    pub fn platform_display(&self) -> *mut libc::c_void {
        use wayland_client::Proxy;
        match self {
            &Window2::X(ref w) => w.platform_display(),
            &Window2::Wayland(ref w) => w.get_display().ptr() as *mut _
        }
    }

    #[inline]
    pub fn platform_window(&self) -> *mut libc::c_void {
        use wayland_client::Proxy;
        match self {
            &Window2::X(ref w) => w.platform_window(),
            &Window2::Wayland(ref w) => w.get_surface().ptr() as *mut _
        }
    }
}

unsafe extern "C" fn x_error_callback(dpy: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent)
                                      -> libc::c_int
{
    use std::ffi::CStr;

    if let UnixBackend::X(ref x) = *UNIX_BACKEND {
        let mut buff: Vec<u8> = Vec::with_capacity(1024);
        (x.xlib.XGetErrorText)(dpy, (*event).error_code as i32, buff.as_mut_ptr() as *mut libc::c_char, buff.capacity() as i32);
        let description = CStr::from_ptr(buff.as_mut_ptr() as *const libc::c_char).to_string_lossy();

        let error = XError {
            description: description.into_owned(),
            error_code: (*event).error_code,
            request_code: (*event).request_code,
            minor_code: (*event).minor_code,
        };

        *x.latest_error.lock().unwrap() = Some(error);
    }

    0
}

pub enum EventsLoop {
    #[doc(hidden)]
    Wayland(wayland::EventsLoop),
    #[doc(hidden)]
    X(x11::EventsLoop)
}

impl EventsLoop {
    pub fn new() -> EventsLoop {
        match *UNIX_BACKEND {
            UnixBackend::Wayland(_) => {
                EventsLoop::Wayland(wayland::EventsLoop::new())
            },

            UnixBackend::X(_) => {
                EventsLoop::X(x11::EventsLoop::new())
            },

            UnixBackend::Error(_) => {
                panic!("Attempted to create an EventsLoop while no backend was available.")
            }
        }
    }

    pub fn interrupt(&self) {
        match *self {
            EventsLoop::Wayland(ref evlp) => evlp.interrupt(),
            EventsLoop::X(ref evlp) => evlp.interrupt()
        }
    }

    pub fn poll_events<F>(&self, callback: F)
        where F: FnMut(::Event)
    {
        match *self {
            EventsLoop::Wayland(ref evlp) => evlp.poll_events(callback),
            EventsLoop::X(ref evlp) => evlp.poll_events(callback)
        }
    }

    pub fn run_forever<F>(&self, callback: F)
        where F: FnMut(::Event)
    {
        match *self {
            EventsLoop::Wayland(ref evlp) => evlp.run_forever(callback),
            EventsLoop::X(ref evlp) => evlp.run_forever(callback)
        }
    }
}
<|endoftext|>


<commit_before>use webcore::value::Reference;
use webcore::try_from::TryInto;
use webapi::dom_exception::SecurityError;

/// The `Location` interface represents the location (URL) of the object it
/// is linked to. Changes done on it are reflected on the object it relates
/// to. Both the [Document](struct.Document.html) and [Window](struct.Window.html)
/// interface have such a linked `Location`, accessible via [Document::location](struct.Document.html#method.location)
/// and [Window::location](struct.Window.html#method.location) respectively.
///
/// Note that all `Location` methods can return a `SecurityError` if the `Location` object's
/// relevant `Document`'s origin is not same origin-domain with the entry settings object's origin.
/// See: https://html.spec.whatwg.org/#dom-location-href
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location)
// https://html.spec.whatwg.org/#location
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Location")]
pub struct Location( Reference );

impl Location {
    /// The entire URL.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/href)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-href
    pub fn href( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.href; ).unwrap()
    }

    /// Returns a `String` containing the Unicode serialization of the origin of the represented
    /// URL, that is:
    ///
    /// - For URL using the http or https, the scheme followed by `'://'`, followed by the domain,
    ///   followed by `':'`, followed by the port (the default port, 80 and 443 respectively, if
    ///   explicitely specified);
    /// - For URL using `file: scheme`, the value is browser dependant.
    /// - For URL using the blob: scheme, the origin of the URL following blob:. E.g
    ///   "blob:https://mozilla.org" will have "https://mozilla.org".
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/origin)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-origin
    pub fn origin( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.origin; ).unwrap()
    }

    /// Returns a `String` representing the protocol scheme of the URL, including the final ':'.
    ///
    /// Example: `http:`
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/protocol)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-protocol
    pub fn protocol( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.protocol; ).unwrap()
    }

    /// Returns a `String` containing the host (i.e. hostname) and then, if the port of the
    /// URL is nonempty, a ':', and the port of the URL.
    ///
    /// Example: `hitchhikers.com:4242`
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/host)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-host
    pub fn host( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.host; ).unwrap()
    }

    /// Returns a `String` which is the domain of the URL
    ///
    /// Example: `mozilla.com`
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/hostname)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-hostname
    pub fn hostname( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.hostname; ).unwrap()
    }

    /// Returns a `String` containing the port number or `""` if there is no port.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/port)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-port
    pub fn port( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.port; ).unwrap()
    }

    /// Returns a `String` containing an initial '/' followed by the path of the URL.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/pathname)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-pathname
    pub fn pathname( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.pathname; ).unwrap()
    }

    /// Returns a `String` which is a search string, also called a query string, that is a `String`
    /// containing a '?' followed by the parameters of the URL.
    ///
    /// These can then be further parsed via another library.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/search)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-search
    pub fn search( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.search; ).unwrap()
    }

    /// Returns a `String` containing a '#' followed by the fragment
    /// identifier of the URL. The fragment is not percent-decoded.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/hash)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-hash
    pub fn hash( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.hash; ).unwrap()
    }
}
<commit_msg>Remove unnecessary import<commit_after>use webcore::value::Reference;
use webapi::dom_exception::SecurityError;

/// The `Location` interface represents the location (URL) of the object it
/// is linked to. Changes done on it are reflected on the object it relates
/// to. Both the [Document](struct.Document.html) and [Window](struct.Window.html)
/// interface have such a linked `Location`, accessible via [Document::location](struct.Document.html#method.location)
/// and [Window::location](struct.Window.html#method.location) respectively.
///
/// Note that all `Location` methods can return a `SecurityError` if the `Location` object's
/// relevant `Document`'s origin is not same origin-domain with the entry settings object's origin.
/// See: https://html.spec.whatwg.org/#dom-location-href
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location)
// https://html.spec.whatwg.org/#location
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Location")]
pub struct Location( Reference );

impl Location {
    /// The entire URL.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/href)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-href
    pub fn href( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.href; ).unwrap()
    }

    /// Returns a `String` containing the Unicode serialization of the origin of the represented
    /// URL, that is:
    ///
    /// - For URL using the http or https, the scheme followed by `'://'`, followed by the domain,
    ///   followed by `':'`, followed by the port (the default port, 80 and 443 respectively, if
    ///   explicitely specified);
    /// - For URL using `file: scheme`, the value is browser dependant.
    /// - For URL using the blob: scheme, the origin of the URL following blob:. E.g
    ///   "blob:https://mozilla.org" will have "https://mozilla.org".
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/origin)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-origin
    pub fn origin( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.origin; ).unwrap()
    }

    /// Returns a `String` representing the protocol scheme of the URL, including the final ':'.
    ///
    /// Example: `http:`
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/protocol)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-protocol
    pub fn protocol( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.protocol; ).unwrap()
    }

    /// Returns a `String` containing the host (i.e. hostname) and then, if the port of the
    /// URL is nonempty, a ':', and the port of the URL.
    ///
    /// Example: `hitchhikers.com:4242`
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/host)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-host
    pub fn host( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.host; ).unwrap()
    }

    /// Returns a `String` which is the domain of the URL
    ///
    /// Example: `mozilla.com`
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/hostname)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-hostname
    pub fn hostname( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.hostname; ).unwrap()
    }

    /// Returns a `String` containing the port number or `""` if there is no port.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/port)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-port
    pub fn port( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.port; ).unwrap()
    }

    /// Returns a `String` containing an initial '/' followed by the path of the URL.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/pathname)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-pathname
    pub fn pathname( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.pathname; ).unwrap()
    }

    /// Returns a `String` which is a search string, also called a query string, that is a `String`
    /// containing a '?' followed by the parameters of the URL.
    ///
    /// These can then be further parsed via another library.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/search)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-search
    pub fn search( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.search; ).unwrap()
    }

    /// Returns a `String` containing a '#' followed by the fragment
    /// identifier of the URL. The fragment is not percent-decoded.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Location/hash)
    // https://html.spec.whatwg.org/#the-location-interface:dom-location-hash
    pub fn hash( &self ) -> Result< String, SecurityError > {
        js_try!( return @{self}.hash; ).unwrap()
    }
}
<|endoftext|>


<commit_before>use std::f64;
use std::fs::File;
use std::io::Read;
use std::result;
use std::str::FromStr;
use std::time::Duration;

use failure::{format_err, Error, ResultExt};
use tokio_timer::Timer;

use crate::text::{Attributes, Color, Text};
use crate::{Cnx, Result};

#[derive(Clone, Debug, Eq, PartialEq)]
enum Status {
    Full,
    Charging,
    Discharging,
    Unknown,
}

impl FromStr for Status {
    type Err = Error;

    fn from_str(s: &str) -> result::Result<Self, Self::Err> {
        match s {
            "Full" => Ok(Status::Full),
            "Charging" => Ok(Status::Charging),
            "Discharging" => Ok(Status::Discharging),
            "Unknown" => Ok(Status::Unknown),
            _ => Err(format_err!("Unknown Status: {}", s)),
        }
    }
}

/// Shows battery charge percentage and (dis)charge time.
///
/// This widget shows the battery's current charge percentage and the amount of
/// remaining (dis)charge time, depending on whether the battery is charging or
/// discharging. The format of the output is `(PP% HH:MM)`.
///
/// When the battery has less than 10% charge remaining, the widget's text will
/// change to the specified `warning_color`.
///
/// Battery charge information is read from [`/sys/class/power_supply/BAT0/`].
///
/// [`/sys/class/power_supply/BAT0/`]: https://www.kernel.org/doc/Documentation/power/power_supply_class.txt
pub struct Battery {
    timer: Timer,
    update_interval: Duration,
    battery: String,
    attr: Attributes,
    warning_color: Color,
}

impl Battery {
    ///  Creates a new Battery widget.
    ///
    ///  Creates a new `Battery` widget, whose text will be displayed with the
    ///  given [`Attributes`]. The caller can provide use the `warning_color`
    ///  argument, to control the [`Color`] of the text once the battery has
    ///  less than 10% charge remaining.
    ///
    ///  The [`Cnx`] instance is borrowed during construction in order to get
    ///  access to handles of its event loop. However, it is not borrowed for
    ///  the lifetime of the widget. See the [`cnx_add_widget!()`] for more
    ///  discussion about the lifetime of the borrow.
    ///
    /// [`Attributes`]: ../text/struct.Attributes.html
    /// [`Color`]: ../text/struct.Color.html
    /// [`Cnx`]: ../struct.Cnx.html
    /// [`cnx_add_widget!()`]: ../macro.cnx_add_widget.html
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use]
    /// # extern crate cnx;
    /// #
    /// # use cnx::*;
    /// # use cnx::text::*;
    /// # use cnx::widgets::*;
    /// #
    /// # fn run() -> ::cnx::Result<()> {
    /// let attr = Attributes {
    ///     font: Font::new("SourceCodePro 21"),
    ///     fg_color: Color::white(),
    ///     bg_color: None,
    ///     padding: Padding::new(8.0, 8.0, 0.0, 0.0),
    /// };
    ///
    /// let mut cnx = Cnx::new(Position::Top)?;
    /// cnx_add_widget!(cnx, Battery::new(&cnx, attr.clone(), Color::red()));
    /// # Ok(())
    /// # }
    /// # fn main() { run().unwrap(); }
    /// ```
    pub fn new(cnx: &Cnx, attr: Attributes, warning_color: Color) -> Battery {
        Battery {
            timer: cnx.timer(),
            update_interval: Duration::from_secs(60),
            battery: "BAT0".to_owned(),
            attr,
            warning_color,
        }
    }

    fn load_value_inner<T>(&self, file: &str) -> Result<T>
    where
        T: FromStr,
        <T as FromStr>::Err: Into<Error>,
    {
        let path = format!("/sys/class/power_supply/{}/{}", self.battery, file);
        let mut file = File::open(path)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        let s = FromStr::from_str(contents.trim())
            .map_err(|e: <T as FromStr>::Err| e.into())
            .context("Failed to parse value")?;
        Ok(s)
    }

    fn load_value<T>(&self, file: &str) -> Result<T>
    where
        T: FromStr,
        <T as FromStr>::Err: Into<Error>,
    {
        let value = self
            .load_value_inner(file)
            .with_context(|_| format!("Could not load value from battery status file: {}", file))?;
        Ok(value)
    }

    fn tick(&self) -> Result<Vec<Text>> {
        let full: f64 = self.load_value("charge_full")?;
        let now: f64 = self.load_value("charge_now")?;
        let percentage = (now / full) * 100.0;

        // If we're discharging, show time to empty.
        // If we're charging, show time to full.
        let power: f64 = self.load_value("current_avg")?;
        let status: Status = self.load_value("status")?;
        let time = match status {
            Status::Discharging => now / power,
            Status::Charging => (full - now) / power,
            _ => 0.0,
        };
        let hours = time as u64;
        let minutes = (time * 60.0) as u64 % 60;

        let text = format!(
            "({percentage:.0}% - {hours}:{minutes:02})",
            percentage = percentage,
            hours = hours,
            minutes = minutes
        );

        // If we're discharging and have <=10% left, then render with a
        // special warning color.
        let mut attr = self.attr.clone();
        if status == Status::Discharging && percentage <= 10.0 {
            attr.fg_color = self.warning_color.clone()
        }

        Ok(vec![Text {
            attr,
            text,
            stretch: false,
        }])
    }
}

timer_widget!(Battery, timer, update_interval, tick);
<commit_msg>No such file "current_avg" in sysfs-class-power<commit_after>use std::f64;
use std::fs::File;
use std::io::Read;
use std::result;
use std::str::FromStr;
use std::time::Duration;

use failure::{format_err, Error, ResultExt};
use tokio_timer::Timer;

use crate::text::{Attributes, Color, Text};
use crate::{Cnx, Result};

#[derive(Clone, Debug, Eq, PartialEq)]
enum Status {
    Full,
    Charging,
    Discharging,
    Unknown,
}

impl FromStr for Status {
    type Err = Error;

    fn from_str(s: &str) -> result::Result<Self, Self::Err> {
        match s {
            "Full" => Ok(Status::Full),
            "Charging" => Ok(Status::Charging),
            "Discharging" => Ok(Status::Discharging),
            "Unknown" => Ok(Status::Unknown),
            _ => Err(format_err!("Unknown Status: {}", s)),
        }
    }
}

/// Shows battery charge percentage and (dis)charge time.
///
/// This widget shows the battery's current charge percentage and the amount of
/// remaining (dis)charge time, depending on whether the battery is charging or
/// discharging. The format of the output is `(PP% HH:MM)`.
///
/// When the battery has less than 10% charge remaining, the widget's text will
/// change to the specified `warning_color`.
///
/// Battery charge information is read from [`/sys/class/power_supply/BAT0/`].
///
/// [`/sys/class/power_supply/BAT0/`]: https://www.kernel.org/doc/Documentation/power/power_supply_class.txt
pub struct Battery {
    timer: Timer,
    update_interval: Duration,
    battery: String,
    attr: Attributes,
    warning_color: Color,
}

impl Battery {
    ///  Creates a new Battery widget.
    ///
    ///  Creates a new `Battery` widget, whose text will be displayed with the
    ///  given [`Attributes`]. The caller can provide use the `warning_color`
    ///  argument, to control the [`Color`] of the text once the battery has
    ///  less than 10% charge remaining.
    ///
    ///  The [`Cnx`] instance is borrowed during construction in order to get
    ///  access to handles of its event loop. However, it is not borrowed for
    ///  the lifetime of the widget. See the [`cnx_add_widget!()`] for more
    ///  discussion about the lifetime of the borrow.
    ///
    /// [`Attributes`]: ../text/struct.Attributes.html
    /// [`Color`]: ../text/struct.Color.html
    /// [`Cnx`]: ../struct.Cnx.html
    /// [`cnx_add_widget!()`]: ../macro.cnx_add_widget.html
    ///
    /// # Examples
    ///
    /// ```
    /// # #[macro_use]
    /// # extern crate cnx;
    /// #
    /// # use cnx::*;
    /// # use cnx::text::*;
    /// # use cnx::widgets::*;
    /// #
    /// # fn run() -> ::cnx::Result<()> {
    /// let attr = Attributes {
    ///     font: Font::new("SourceCodePro 21"),
    ///     fg_color: Color::white(),
    ///     bg_color: None,
    ///     padding: Padding::new(8.0, 8.0, 0.0, 0.0),
    /// };
    ///
    /// let mut cnx = Cnx::new(Position::Top)?;
    /// cnx_add_widget!(cnx, Battery::new(&cnx, attr.clone(), Color::red()));
    /// # Ok(())
    /// # }
    /// # fn main() { run().unwrap(); }
    /// ```
    pub fn new(cnx: &Cnx, attr: Attributes, warning_color: Color) -> Battery {
        Battery {
            timer: cnx.timer(),
            update_interval: Duration::from_secs(60),
            battery: "BAT0".to_owned(),
            attr,
            warning_color,
        }
    }

    fn load_value_inner<T>(&self, file: &str) -> Result<T>
    where
        T: FromStr,
        <T as FromStr>::Err: Into<Error>,
    {
        let path = format!("/sys/class/power_supply/{}/{}", self.battery, file);
        let mut file = File::open(path)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        let s = FromStr::from_str(contents.trim())
            .map_err(|e: <T as FromStr>::Err| e.into())
            .context("Failed to parse value")?;
        Ok(s)
    }

    fn load_value<T>(&self, file: &str) -> Result<T>
    where
        T: FromStr,
        <T as FromStr>::Err: Into<Error>,
    {
        let value = self
            .load_value_inner(file)
            .with_context(|_| format!("Could not load value from battery status file: {}", file))?;
        Ok(value)
    }

    fn tick(&self) -> Result<Vec<Text>> {
        let full: f64 = self.load_value("charge_full")?;
        let now: f64 = self.load_value("charge_now")?;
        let percentage = (now / full) * 100.0;

        // If we're discharging, show time to empty.
        // If we're charging, show time to full.
        let power: f64 = self
            .load_value("current_avg")
            .or_else(|_| self.load_value("current_now"))?;
        let status: Status = self.load_value("status")?;
        let time = match status {
            Status::Discharging => now / power,
            Status::Charging => (full - now) / power,
            _ => 0.0,
        };
        let hours = time as u64;
        let minutes = (time * 60.0) as u64 % 60;

        let text = format!(
            "({percentage:.0}% - {hours}:{minutes:02})",
            percentage = percentage,
            hours = hours,
            minutes = minutes
        );

        // If we're discharging and have <=10% left, then render with a
        // special warning color.
        let mut attr = self.attr.clone();
        if status == Status::Discharging && percentage <= 10.0 {
            attr.fg_color = self.warning_color.clone()
        }

        Ok(vec![Text {
            attr,
            text,
            stretch: false,
        }])
    }
}

timer_widget!(Battery, timer, update_interval, tick);
<|endoftext|>


<commit_before>//! Instruction Set Architectures.
//!
//! The `isa` module provides a `TargetIsa` trait which provides the behavior specialization needed
//! by the ISA-independent code generator. The sub-modules of this module provide definitions for
//! the instruction sets that Cretonne can target. Each sub-module has it's own implementation of
//! `TargetIsa`.
//!
//! # Constructing a `TargetIsa` instance
//!
//! The target ISA is built from the following information:
//!
//! - The name of the target ISA as a string. Cretonne is a cross-compiler, so the ISA to target
//!   can be selected dynamically. Individual ISAs can be left out when Cretonne is compiled, so a
//!   string is used to identify the proper sub-module.
//! - Values for settings that apply to all ISAs. This is represented by a `settings::Flags`
//!   instance.
//! - Values for ISA-specific settings.
//!
//! The `isa::lookup()` function is the main entry point which returns an `isa::Builder`
//! appropriate for the requested ISA:
//!
//! ```
//! use cretonne::settings::{self, Configurable};
//! use cretonne::isa;
//!
//! let shared_builder = settings::builder();
//! let shared_flags = settings::Flags::new(&shared_builder);
//!
//! match isa::lookup("riscv") {
//!     Err(_) => {
//!         // The RISC-V target ISA is not available.
//!     }
//!     Ok(mut isa_builder) => {
//!         isa_builder.set("supports_m", "on");
//!         let isa = isa_builder.finish(shared_flags);
//!     }
//! }
//! ```
//!
//! The configured target ISA trait object is a `Box<TargetIsa>` which can be used for multiple
//! concurrent function compilations.

pub use isa::constraints::{RecipeConstraints, OperandConstraint, ConstraintKind, BranchRange};
pub use isa::encoding::{Encoding, EncInfo};
pub use isa::registers::{RegInfo, RegUnit, RegClass, RegClassIndex, regs_overlap};
pub use isa::stack::{StackBase, StackBaseMask, StackRef};

use binemit;
use flowgraph;
use settings;
use ir;
use regalloc;
use result;
use isa::enc_tables::Encodings;

#[cfg(build_riscv)]
pub mod riscv;

#[cfg(build_intel)]
pub mod intel;

#[cfg(build_arm32)]
pub mod arm32;

#[cfg(build_arm64)]
pub mod arm64;

pub mod registers;
mod encoding;
mod enc_tables;
mod constraints;
mod stack;

/// Returns a builder that can create a corresponding `TargetIsa`
/// or `Err(LookupError::Unsupported)` if not enabled.
macro_rules! isa_builder {
    ($module:ident, $name:ident) => {
        {
            #[cfg($name)]
            fn $name() -> Result<Builder, LookupError> {
                Ok($module::isa_builder())
            };
            #[cfg(not($name))]
            fn $name() -> Result<Builder, LookupError> {
                Err(LookupError::Unsupported)
            }
            $name()
        }
    };
}

/// Look for a supported ISA with the given `name`.
/// Return a builder that can create a corresponding `TargetIsa`.
pub fn lookup(name: &str) -> Result<Builder, LookupError> {
    match name {
        "riscv" => isa_builder!(riscv, build_riscv),
        "intel" => isa_builder!(intel, build_intel),
        "arm32" => isa_builder!(arm32, build_arm32),
        "arm64" => isa_builder!(arm64, build_arm64),
        _ => Err(LookupError::Unknown),
    }
}

/// Describes reason for target lookup failure
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum LookupError {
    /// Unknown Target
    Unknown,

    /// Target known but not built and thus not supported
    Unsupported,
}

/// Builder for a `TargetIsa`.
/// Modify the ISA-specific settings before creating the `TargetIsa` trait object with `finish`.
pub struct Builder {
    setup: settings::Builder,
    constructor: fn(settings::Flags, &settings::Builder) -> Box<TargetIsa>,
}

impl Builder {
    /// Combine the ISA-specific settings with the provided ISA-independent settings and allocate a
    /// fully configured `TargetIsa` trait object.
    pub fn finish(self, shared_flags: settings::Flags) -> Box<TargetIsa> {
        (self.constructor)(shared_flags, &self.setup)
    }
}

impl settings::Configurable for Builder {
    fn set(&mut self, name: &str, value: &str) -> settings::Result<()> {
        self.setup.set(name, value)
    }

    fn enable(&mut self, name: &str) -> settings::Result<()> {
        self.setup.enable(name)
    }
}

/// After determining that an instruction doesn't have an encoding, how should we proceed to
/// legalize it?
///
/// The `Encodings` iterator returns a legalization function to call.
pub type Legalize = fn(ir::Inst,
                       &mut ir::Function,
                       &mut flowgraph::ControlFlowGraph)
                       -> bool;

/// Methods that are specialized to a target ISA.
pub trait TargetIsa {
    /// Get the name of this ISA.
    fn name(&self) -> &'static str;

    /// Get the ISA-independent flags that were used to make this trait object.
    fn flags(&self) -> &settings::Flags;

    /// Get a data structure describing the registers in this ISA.
    fn register_info(&self) -> RegInfo;

    /// Returns an iterartor over legal encodings for the instruction.
    fn legal_encodings<'a>(
        &'a self,
        dfg: &'a ir::DataFlowGraph,
        inst: &'a ir::InstructionData,
        ctrl_typevar: ir::Type,
    ) -> Encodings<'a>;

    /// Encode an instruction after determining it is legal.
    ///
    /// If `inst` can legally be encoded in this ISA, produce the corresponding `Encoding` object.
    /// Otherwise, return `Legalize` action.
    ///
    /// This is also the main entry point for determining if an instruction is legal.
    fn encode(
        &self,
        dfg: &ir::DataFlowGraph,
        inst: &ir::InstructionData,
        ctrl_typevar: ir::Type,
    ) -> Result<Encoding, Legalize> {
        let mut iter = self.legal_encodings(dfg, inst, ctrl_typevar);
        iter.next().ok_or_else(|| iter.legalize().into())
    }

    /// Get a data structure describing the instruction encodings in this ISA.
    fn encoding_info(&self) -> EncInfo;

    /// Legalize a function signature.
    ///
    /// This is used to legalize both the signature of the function being compiled and any called
    /// functions. The signature should be modified by adding `ArgumentLoc` annotations to all
    /// arguments and return values.
    ///
    /// Arguments with types that are not supported by the ABI can be expanded into multiple
    /// arguments:
    ///
    /// - Integer types that are too large to fit in a register can be broken into multiple
    ///   arguments of a smaller integer type.
    /// - Floating point types can be bit-cast to an integer type of the same size, and possible
    ///   broken into smaller integer types.
    /// - Vector types can be bit-cast and broken down into smaller vectors or scalars.
    ///
    /// The legalizer will adapt argument and return values as necessary at all ABI boundaries.
    ///
    /// When this function is called to legalize the signature of the function currently begin
    /// compiler, `current` is true. The legalized signature can then also contain special purpose
    /// arguments and return values such as:
    ///
    /// - A `link` argument representing the link registers on RISC architectures that don't push
    ///   the return address on the stack.
    /// - A `link` return value which will receive the value that was passed to the `link`
    ///   argument.
    /// - An `sret` argument can be added if one wasn't present already. This is necessary if the
    ///   signature returns more values than registers are available for returning values.
    /// - An `sret` return value can be added if the ABI requires a function to return its `sret`
    ///   argument in a register.
    ///
    /// Arguments and return values for the caller's frame pointer and other callee-saved registers
    /// should not be added by this function. These arguments are not added until after register
    /// allocation.
    fn legalize_signature(&self, sig: &mut ir::Signature, current: bool);

    /// Get the register class that should be used to represent an ABI argument or return value of
    /// type `ty`. This should be the top-level register class that contains the argument
    /// registers.
    ///
    /// This function can assume that it will only be asked to provide register classes for types
    /// that `legalize_signature()` produces in `ArgumentLoc::Reg` entries.
    fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass;

    /// Get the set of allocatable registers that can be used when compiling `func`.
    ///
    /// This set excludes reserved registers like the stack pointer and other special-purpose
    /// registers.
    fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet;

    /// Compute the stack layout and insert prologue and epilogue code into `func`.
    ///
    /// Return an error if the stack frame is too large.
    fn prologue_epilogue(&self, func: &mut ir::Function) -> result::CtonResult {
        // This default implementation is unlikely to be good enough.
        use stack_layout::layout_stack;
        use ir::stackslot::{StackSize, StackOffset};

        let word_size = if self.flags().is_64bit() { 8 } else { 4 };

        // Account for the SpiderMonkey standard prologue pushes.
        if func.signature.call_conv == ir::CallConv::SpiderWASM {
            let bytes = self.flags().spiderwasm_prologue_words() as StackSize * word_size;
            let mut ss = ir::StackSlotData::new(ir::StackSlotKind::IncomingArg, bytes);
            ss.offset = -(bytes as StackOffset);
            func.stack_slots.push(ss);
        }

        layout_stack(&mut func.stack_slots, word_size)?;
        Ok(())
    }

    /// Emit binary machine code for a single instruction into the `sink` trait object.
    ///
    /// Note that this will call `put*` methods on the trait object via its vtable which is not the
    /// fastest way of emitting code.
    fn emit_inst(
        &self,
        func: &ir::Function,
        inst: ir::Inst,
        divert: &mut regalloc::RegDiversions,
        sink: &mut binemit::CodeSink,
    );

    /// Emit a whole function into memory.
    ///
    /// This is more performant than calling `emit_inst` for each instruction.
    fn emit_function(&self, func: &ir::Function, sink: &mut binemit::MemoryCodeSink);

    /// Get a static array of names associated with relocations in this ISA.
    ///
    /// This array can be indexed by the contents of `binemit::Reloc` objects passed to a
    /// `CodeSink`.
    fn reloc_names(&self) -> &'static [&'static str];
}
<commit_msg>Remove a redundant `.into()`.<commit_after>//! Instruction Set Architectures.
//!
//! The `isa` module provides a `TargetIsa` trait which provides the behavior specialization needed
//! by the ISA-independent code generator. The sub-modules of this module provide definitions for
//! the instruction sets that Cretonne can target. Each sub-module has it's own implementation of
//! `TargetIsa`.
//!
//! # Constructing a `TargetIsa` instance
//!
//! The target ISA is built from the following information:
//!
//! - The name of the target ISA as a string. Cretonne is a cross-compiler, so the ISA to target
//!   can be selected dynamically. Individual ISAs can be left out when Cretonne is compiled, so a
//!   string is used to identify the proper sub-module.
//! - Values for settings that apply to all ISAs. This is represented by a `settings::Flags`
//!   instance.
//! - Values for ISA-specific settings.
//!
//! The `isa::lookup()` function is the main entry point which returns an `isa::Builder`
//! appropriate for the requested ISA:
//!
//! ```
//! use cretonne::settings::{self, Configurable};
//! use cretonne::isa;
//!
//! let shared_builder = settings::builder();
//! let shared_flags = settings::Flags::new(&shared_builder);
//!
//! match isa::lookup("riscv") {
//!     Err(_) => {
//!         // The RISC-V target ISA is not available.
//!     }
//!     Ok(mut isa_builder) => {
//!         isa_builder.set("supports_m", "on");
//!         let isa = isa_builder.finish(shared_flags);
//!     }
//! }
//! ```
//!
//! The configured target ISA trait object is a `Box<TargetIsa>` which can be used for multiple
//! concurrent function compilations.

pub use isa::constraints::{RecipeConstraints, OperandConstraint, ConstraintKind, BranchRange};
pub use isa::encoding::{Encoding, EncInfo};
pub use isa::registers::{RegInfo, RegUnit, RegClass, RegClassIndex, regs_overlap};
pub use isa::stack::{StackBase, StackBaseMask, StackRef};

use binemit;
use flowgraph;
use settings;
use ir;
use regalloc;
use result;
use isa::enc_tables::Encodings;

#[cfg(build_riscv)]
pub mod riscv;

#[cfg(build_intel)]
pub mod intel;

#[cfg(build_arm32)]
pub mod arm32;

#[cfg(build_arm64)]
pub mod arm64;

pub mod registers;
mod encoding;
mod enc_tables;
mod constraints;
mod stack;

/// Returns a builder that can create a corresponding `TargetIsa`
/// or `Err(LookupError::Unsupported)` if not enabled.
macro_rules! isa_builder {
    ($module:ident, $name:ident) => {
        {
            #[cfg($name)]
            fn $name() -> Result<Builder, LookupError> {
                Ok($module::isa_builder())
            };
            #[cfg(not($name))]
            fn $name() -> Result<Builder, LookupError> {
                Err(LookupError::Unsupported)
            }
            $name()
        }
    };
}

/// Look for a supported ISA with the given `name`.
/// Return a builder that can create a corresponding `TargetIsa`.
pub fn lookup(name: &str) -> Result<Builder, LookupError> {
    match name {
        "riscv" => isa_builder!(riscv, build_riscv),
        "intel" => isa_builder!(intel, build_intel),
        "arm32" => isa_builder!(arm32, build_arm32),
        "arm64" => isa_builder!(arm64, build_arm64),
        _ => Err(LookupError::Unknown),
    }
}

/// Describes reason for target lookup failure
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum LookupError {
    /// Unknown Target
    Unknown,

    /// Target known but not built and thus not supported
    Unsupported,
}

/// Builder for a `TargetIsa`.
/// Modify the ISA-specific settings before creating the `TargetIsa` trait object with `finish`.
pub struct Builder {
    setup: settings::Builder,
    constructor: fn(settings::Flags, &settings::Builder) -> Box<TargetIsa>,
}

impl Builder {
    /// Combine the ISA-specific settings with the provided ISA-independent settings and allocate a
    /// fully configured `TargetIsa` trait object.
    pub fn finish(self, shared_flags: settings::Flags) -> Box<TargetIsa> {
        (self.constructor)(shared_flags, &self.setup)
    }
}

impl settings::Configurable for Builder {
    fn set(&mut self, name: &str, value: &str) -> settings::Result<()> {
        self.setup.set(name, value)
    }

    fn enable(&mut self, name: &str) -> settings::Result<()> {
        self.setup.enable(name)
    }
}

/// After determining that an instruction doesn't have an encoding, how should we proceed to
/// legalize it?
///
/// The `Encodings` iterator returns a legalization function to call.
pub type Legalize = fn(ir::Inst,
                       &mut ir::Function,
                       &mut flowgraph::ControlFlowGraph)
                       -> bool;

/// Methods that are specialized to a target ISA.
pub trait TargetIsa {
    /// Get the name of this ISA.
    fn name(&self) -> &'static str;

    /// Get the ISA-independent flags that were used to make this trait object.
    fn flags(&self) -> &settings::Flags;

    /// Get a data structure describing the registers in this ISA.
    fn register_info(&self) -> RegInfo;

    /// Returns an iterartor over legal encodings for the instruction.
    fn legal_encodings<'a>(
        &'a self,
        dfg: &'a ir::DataFlowGraph,
        inst: &'a ir::InstructionData,
        ctrl_typevar: ir::Type,
    ) -> Encodings<'a>;

    /// Encode an instruction after determining it is legal.
    ///
    /// If `inst` can legally be encoded in this ISA, produce the corresponding `Encoding` object.
    /// Otherwise, return `Legalize` action.
    ///
    /// This is also the main entry point for determining if an instruction is legal.
    fn encode(
        &self,
        dfg: &ir::DataFlowGraph,
        inst: &ir::InstructionData,
        ctrl_typevar: ir::Type,
    ) -> Result<Encoding, Legalize> {
        let mut iter = self.legal_encodings(dfg, inst, ctrl_typevar);
        iter.next().ok_or_else(|| iter.legalize())
    }

    /// Get a data structure describing the instruction encodings in this ISA.
    fn encoding_info(&self) -> EncInfo;

    /// Legalize a function signature.
    ///
    /// This is used to legalize both the signature of the function being compiled and any called
    /// functions. The signature should be modified by adding `ArgumentLoc` annotations to all
    /// arguments and return values.
    ///
    /// Arguments with types that are not supported by the ABI can be expanded into multiple
    /// arguments:
    ///
    /// - Integer types that are too large to fit in a register can be broken into multiple
    ///   arguments of a smaller integer type.
    /// - Floating point types can be bit-cast to an integer type of the same size, and possible
    ///   broken into smaller integer types.
    /// - Vector types can be bit-cast and broken down into smaller vectors or scalars.
    ///
    /// The legalizer will adapt argument and return values as necessary at all ABI boundaries.
    ///
    /// When this function is called to legalize the signature of the function currently begin
    /// compiler, `current` is true. The legalized signature can then also contain special purpose
    /// arguments and return values such as:
    ///
    /// - A `link` argument representing the link registers on RISC architectures that don't push
    ///   the return address on the stack.
    /// - A `link` return value which will receive the value that was passed to the `link`
    ///   argument.
    /// - An `sret` argument can be added if one wasn't present already. This is necessary if the
    ///   signature returns more values than registers are available for returning values.
    /// - An `sret` return value can be added if the ABI requires a function to return its `sret`
    ///   argument in a register.
    ///
    /// Arguments and return values for the caller's frame pointer and other callee-saved registers
    /// should not be added by this function. These arguments are not added until after register
    /// allocation.
    fn legalize_signature(&self, sig: &mut ir::Signature, current: bool);

    /// Get the register class that should be used to represent an ABI argument or return value of
    /// type `ty`. This should be the top-level register class that contains the argument
    /// registers.
    ///
    /// This function can assume that it will only be asked to provide register classes for types
    /// that `legalize_signature()` produces in `ArgumentLoc::Reg` entries.
    fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass;

    /// Get the set of allocatable registers that can be used when compiling `func`.
    ///
    /// This set excludes reserved registers like the stack pointer and other special-purpose
    /// registers.
    fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet;

    /// Compute the stack layout and insert prologue and epilogue code into `func`.
    ///
    /// Return an error if the stack frame is too large.
    fn prologue_epilogue(&self, func: &mut ir::Function) -> result::CtonResult {
        // This default implementation is unlikely to be good enough.
        use stack_layout::layout_stack;
        use ir::stackslot::{StackSize, StackOffset};

        let word_size = if self.flags().is_64bit() { 8 } else { 4 };

        // Account for the SpiderMonkey standard prologue pushes.
        if func.signature.call_conv == ir::CallConv::SpiderWASM {
            let bytes = self.flags().spiderwasm_prologue_words() as StackSize * word_size;
            let mut ss = ir::StackSlotData::new(ir::StackSlotKind::IncomingArg, bytes);
            ss.offset = -(bytes as StackOffset);
            func.stack_slots.push(ss);
        }

        layout_stack(&mut func.stack_slots, word_size)?;
        Ok(())
    }

    /// Emit binary machine code for a single instruction into the `sink` trait object.
    ///
    /// Note that this will call `put*` methods on the trait object via its vtable which is not the
    /// fastest way of emitting code.
    fn emit_inst(
        &self,
        func: &ir::Function,
        inst: ir::Inst,
        divert: &mut regalloc::RegDiversions,
        sink: &mut binemit::CodeSink,
    );

    /// Emit a whole function into memory.
    ///
    /// This is more performant than calling `emit_inst` for each instruction.
    fn emit_function(&self, func: &ir::Function, sink: &mut binemit::MemoryCodeSink);

    /// Get a static array of names associated with relocations in this ISA.
    ///
    /// This array can be indexed by the contents of `binemit::Reloc` objects passed to a
    /// `CodeSink`.
    fn reloc_names(&self) -> &'static [&'static str];
}
<|endoftext|>