<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Common handling of keyboard input and state management for text input controls

use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
use dom::bindings::js::JSRef;
use dom::keyboardevent::KeyboardEvent;
use servo_util::str::DOMString;

use std::cmp::{min, max};
use std::default::Default;

#[jstraceable]
struct TextPoint {
    /// 0-based line number
    line: uint,
    /// 0-based column number
    index: uint,
}

/// Encapsulated state for handling keyboard input in a single or multiline text input control.
#[jstraceable]
pub struct TextInput {
    /// Current text input content, split across lines without trailing '\n'
    lines: Vec<DOMString>,
    /// Current cursor input point
    edit_point: TextPoint,
    /// Selection range, beginning and end point that can span multiple lines.
    _selection: Option<(TextPoint, TextPoint)>,
    /// Is this a multiline input?
    multiline: bool,
}

/// Resulting action to be taken by the owner of a text input that is handling an event.
pub enum KeyReaction {
    TriggerDefaultAction,
    DispatchInput,
    Nothing,
}

impl Default for TextPoint {
    fn default() -> TextPoint {
        TextPoint {
            line: 0,
            index: 0,
        }
    }
}

/// Control whether this control should allow multiple lines.
#[deriving(PartialEq)]
pub enum Lines {
    Single,
    Multiple,
}

/// The direction in which to delete a character.
#[deriving(PartialEq)]
enum DeleteDir {
    Forward,
    Backward
}

impl TextInput {
    /// Instantiate a new text input control
    pub fn new(lines: Lines, initial: DOMString) -> TextInput {
        let mut i = TextInput {
            lines: vec!(),
            edit_point: Default::default(),
            _selection: None,
            multiline: lines == Multiple,
        };
        i.set_content(initial);
        i
    }

    /// Return the current line under the editing point
    fn get_current_line(&self) -> &DOMString {
        &self.lines[self.edit_point.line]
    }

    /// Insert a character at the current editing point
    fn insert_char(&mut self, ch: char) {
        //TODO: handle replacing selection with character
        let new_line = {
            let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index);
            let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
                                                                        self.current_line_length());
            let mut new_line = prefix.to_string();
            new_line.push(ch);
            new_line.push_str(suffix.as_slice());
            new_line
        };

        self.lines[self.edit_point.line] = new_line;
        self.edit_point.index += 1;
    }

    /// Remove a character at the current editing point
    fn delete_char(&mut self, dir: DeleteDir) {
        let forward = dir == Forward;

        //TODO: handle deleting selection
        let prefix_end = if forward {
            self.edit_point.index
        } else {
            if self.multiline {
                //TODO: handle backspacing from position 0 of current line
                if self.edit_point.index == 0 {
                    return;
                }
            } else if self.edit_point.index == 0 {
                return;
            }
            self.edit_point.index - 1
        };
        let suffix_start = if forward {
            let is_eol = self.edit_point.index == self.current_line_length();
            if self.multiline {
                //TODO: handle deleting from end position of current line
                if is_eol {
                    return;
                }
            } else if is_eol {
                return;
            }
            self.edit_point.index + 1
        } else {
            self.edit_point.index
        };

        let new_line = {
            let prefix = self.get_current_line().as_slice().slice_chars(0, prefix_end);
            let suffix = self.get_current_line().as_slice().slice_chars(suffix_start,
                                                                        self.current_line_length());
            let mut new_line = prefix.to_string();
            new_line.push_str(suffix);
            new_line
        };

        self.lines[self.edit_point.line] = new_line;

        if !forward {
            self.adjust_horizontal(-1);
        }
    }

    /// Return the length of the current line under the editing point.
    fn current_line_length(&self) -> uint {
        self.lines[self.edit_point.line].char_len()
    }

    /// Adjust the editing point position by a given of lines. The resulting column is
    /// as close to the original column position as possible.
    fn adjust_vertical(&mut self, adjust: int) {
        if !self.multiline {
            return;
        }

        if adjust < 0 && self.edit_point.line as int + adjust < 0 {
            self.edit_point.index = 0;
            self.edit_point.line = 0;
            return;
        } else if adjust > 0 && self.edit_point.line + adjust as uint >= self.lines.len() {
            self.edit_point.line = self.lines.len() - 1;
            self.edit_point.index = self.current_line_length();
            return;
        }

        self.edit_point.line = (self.edit_point.line as int + adjust) as uint;
        self.edit_point.index = min(self.current_line_length(), self.edit_point.index);
    }

    /// Adjust the editing point position by a given number of columns. If the adjustment
    /// requested is larger than is available in the current line, the editing point is
    /// adjusted vertically and the process repeats with the remaining adjustment requested.
    fn adjust_horizontal(&mut self, adjust: int) {
        if adjust < 0 {
            let remaining = self.edit_point.index;
            if adjust.abs() as uint > remaining && self.edit_point.line > 0 {
                self.adjust_vertical(-1);
                self.edit_point.index = self.current_line_length();
                self.adjust_horizontal(adjust + remaining as int);
            } else {
                self.edit_point.index = max(0, self.edit_point.index as int + adjust) as uint;
            }
        } else {
            let remaining = self.current_line_length() - self.edit_point.index;
            if adjust as uint > remaining && self.edit_point.line < self.lines.len() - 1 {
                self.edit_point.index = 0;
                self.adjust_vertical(1);
                self.adjust_horizontal(adjust - remaining as int);
            } else {
                self.edit_point.index = min(self.current_line_length(),
                                            self.edit_point.index + adjust as uint);
            }
        }
    }

    /// Deal with a newline input.
    fn handle_return(&mut self) -> KeyReaction {
        if !self.multiline {
            return TriggerDefaultAction;
        }

        //TODO: support replacing selection with newline
        let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index).to_string();
        let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
                                                                    self.current_line_length()).to_string();
        self.lines[self.edit_point.line] = prefix;
        self.lines.insert(self.edit_point.line + 1, suffix);
        return DispatchInput;
    }

    /// Process a given `KeyboardEvent` and return an action for the caller to execute.
    pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction {
        match event.Key().as_slice() {
            // printable characters have single-character key values
            c if c.len() == 1 => {
                self.insert_char(c.char_at(0));
                return DispatchInput;
            }
            "Space" => {
                self.insert_char(' ');
                DispatchInput
            }
            "Delete" => {
                self.delete_char(Forward);
                DispatchInput
            }
            "Backspace" => {
                self.delete_char(Backward);
                DispatchInput
            }
            "ArrowLeft" => {
                self.adjust_horizontal(-1);
                Nothing
            }
            "ArrowRight" => {
                self.adjust_horizontal(1);
                Nothing
            }
            "ArrowUp" => {
                self.adjust_vertical(-1);
                Nothing
            }
            "ArrowDown" => {
                self.adjust_vertical(1);
                Nothing
            }
            "Enter" => self.handle_return(),
            "Home" => {
                self.edit_point.index = 0;
                Nothing
            }
            "End" => {
                self.edit_point.index = self.current_line_length();
                Nothing
            }
            "PageUp" => {
                self.adjust_vertical(-28);
                Nothing
            }
            "PageDown" => {
                self.adjust_vertical(28);
                Nothing
            }
            "Tab" => TriggerDefaultAction,
            _ => Nothing,
        }
    }

    /// Get the current contents of the text input. Multiple lines are joined by \n.
    pub fn get_content(&self) -> DOMString {
        let mut content = "".to_string();
        for (i, line) in self.lines.iter().enumerate() {
            content.push_str(line.as_slice());
            if i < self.lines.len() - 1 {
                content.push('\n');
            }
        }
        content
    }

    /// Set the current contents of the text input. If this is control supports multiple lines,
    /// any \n encountered will be stripped and force a new logical line.
    pub fn set_content(&mut self, content: DOMString) {
        self.lines = if self.multiline {
            content.as_slice().split('\n').map(|s| s.to_string()).collect()
        } else {
            vec!(content)
        };
        self.edit_point.line = min(self.edit_point.line, self.lines.len() - 1);
        self.edit_point.index = min(self.edit_point.index, self.current_line_length() - 1);
    }
}
<commit_msg>Implement selection ranges and deletion of \n for TextInput.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Common handling of keyboard input and state management for text input controls

use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
use dom::bindings::js::JSRef;
use dom::keyboardevent::KeyboardEvent;
use servo_util::str::DOMString;

use std::cmp::{min, max};
use std::default::Default;

#[jstraceable]
struct TextPoint {
    /// 0-based line number
    line: uint,
    /// 0-based column number
    index: uint,
}

/// Encapsulated state for handling keyboard input in a single or multiline text input control.
#[jstraceable]
pub struct TextInput {
    /// Current text input content, split across lines without trailing '\n'
    lines: Vec<DOMString>,
    /// Current cursor input point
    edit_point: TextPoint,
    /// Beginning of selection range with edit_point as end that can span multiple lines.
    selection_begin: Option<TextPoint>,
    /// Is this a multiline input?
    multiline: bool,
}

/// Resulting action to be taken by the owner of a text input that is handling an event.
pub enum KeyReaction {
    TriggerDefaultAction,
    DispatchInput,
    Nothing,
}

impl Default for TextPoint {
    fn default() -> TextPoint {
        TextPoint {
            line: 0,
            index: 0,
        }
    }
}

/// Control whether this control should allow multiple lines.
#[deriving(PartialEq)]
pub enum Lines {
    Single,
    Multiple,
}

/// The direction in which to delete a character.
#[deriving(PartialEq)]
enum DeleteDir {
    Forward,
    Backward
}

impl TextInput {
    /// Instantiate a new text input control
    pub fn new(lines: Lines, initial: DOMString) -> TextInput {
        let mut i = TextInput {
            lines: vec!(),
            edit_point: Default::default(),
            selection_begin: None,
            multiline: lines == Multiple,
        };
        i.set_content(initial);
        i
    }

    fn replace_selection(&mut self, insert: String) {
        let begin = self.selection_begin.take().unwrap();
        let end = self.edit_point;
        let (begin, end) = if begin.line < end.line || (begin.line == end.line && begin.index < end.index) {
            (begin, end)
        } else {
            (end, begin)
        };

        let new_lines = {
            let prefix = self.lines[begin.line].slice_chars(0, begin.index);
            let suffix = self.lines[end.line].slice_chars(end.index, self.lines[end.line].char_len());
            let lines_prefix = self.lines.slice(0, begin.line);
            let lines_suffix = self.lines.slice(end.line + 1, self.lines.len());

            let mut insert_lines = if self.multiline {
                insert.as_slice().split('\n').map(|s| s.to_string()).collect()
            } else {
                vec!(insert)
            };

            let mut new_line = prefix.to_string();
            new_line.push_str(insert_lines[0].as_slice());
            insert_lines[0] = new_line;

            let last_insert_lines_index = insert_lines.len() - 1;
            self.edit_point.index = insert_lines[last_insert_lines_index].char_len();
            self.edit_point.line = begin.line + last_insert_lines_index;

            insert_lines[last_insert_lines_index].push_str(suffix);

            let mut new_lines = vec!();
            new_lines.push_all(lines_prefix);
            new_lines.push_all(insert_lines.as_slice());
            new_lines.push_all(lines_suffix);
            new_lines
        };

        self.lines = new_lines;
    }

    /// Insert a character at the current editing point
    fn insert_char(&mut self, ch: char) {
        if self.selection_begin.is_none() {
            self.selection_begin = Some(self.edit_point);
        }
        self.replace_selection(ch.to_string());
    }

    /// Remove a character at the current editing point
    fn delete_char(&mut self, dir: DeleteDir) {
        if self.selection_begin.is_none() {
            self.adjust_horizontal(if dir == Forward {1} else {-1}, true);
        }
        self.replace_selection("".to_string());
    }

    /// Return the length of the current line under the editing point.
    fn current_line_length(&self) -> uint {
        self.lines[self.edit_point.line].char_len()
    }

    /// Adjust the editing point position by a given of lines. The resulting column is
    /// as close to the original column position as possible.
    fn adjust_vertical(&mut self, adjust: int, select: bool) {
        if !self.multiline {
            return;
        }

        if select {
            if self.selection_begin.is_none() {
                self.selection_begin = Some(self.edit_point);
            }
        } else {
            self.selection_begin = None;
        }

        if adjust < 0 && self.edit_point.line as int + adjust < 0 {
            self.edit_point.index = 0;
            self.edit_point.line = 0;
            return;
        } else if adjust > 0 && self.edit_point.line + adjust as uint >= self.lines.len() {
            self.edit_point.line = self.lines.len() - 1;
            self.edit_point.index = self.current_line_length();
            return;
        }

        self.edit_point.line = (self.edit_point.line as int + adjust) as uint;
        self.edit_point.index = min(self.current_line_length(), self.edit_point.index);
    }

    /// Adjust the editing point position by a given number of columns. If the adjustment
    /// requested is larger than is available in the current line, the editing point is
    /// adjusted vertically and the process repeats with the remaining adjustment requested.
    fn adjust_horizontal(&mut self, adjust: int, select: bool) {
        if select {
            if self.selection_begin.is_none() {
                self.selection_begin = Some(self.edit_point);
            }
        } else {
            self.selection_begin = None;
        }

        if adjust < 0 {
            let remaining = self.edit_point.index;
            if adjust.abs() as uint > remaining && self.edit_point.line > 0 {
                self.adjust_vertical(-1, select);
                self.edit_point.index = self.current_line_length();
                self.adjust_horizontal(adjust + remaining as int, select);
            } else {
                self.edit_point.index = max(0, self.edit_point.index as int + adjust) as uint;
            }
        } else {
            let remaining = self.current_line_length() - self.edit_point.index;
            if adjust as uint > remaining && self.edit_point.line < self.lines.len() - 1 {
                self.edit_point.index = 0;
                self.adjust_vertical(1, select);
                self.adjust_horizontal(adjust - remaining as int, select);
            } else {
                self.edit_point.index = min(self.current_line_length(),
                                            self.edit_point.index + adjust as uint);
            }
        }
    }

    /// Deal with a newline input.
    fn handle_return(&mut self) -> KeyReaction {
        if !self.multiline {
            return TriggerDefaultAction;
        }
        self.insert_char('\n');
        return DispatchInput;
    }

    /// Process a given `KeyboardEvent` and return an action for the caller to execute.
    pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction {
        match event.Key().as_slice() {
            // printable characters have single-character key values
            c if c.len() == 1 => {
                self.insert_char(c.char_at(0));
                return DispatchInput;
            }
            "Space" => {
                self.insert_char(' ');
                DispatchInput
            }
            "Delete" => {
                self.delete_char(Forward);
                DispatchInput
            }
            "Backspace" => {
                self.delete_char(Backward);
                DispatchInput
            }
            "ArrowLeft" => {
                self.adjust_horizontal(-1, event.ShiftKey());
                Nothing
            }
            "ArrowRight" => {
                self.adjust_horizontal(1, event.ShiftKey());
                Nothing
            }
            "ArrowUp" => {
                self.adjust_vertical(-1, event.ShiftKey());
                Nothing
            }
            "ArrowDown" => {
                self.adjust_vertical(1, event.ShiftKey());
                Nothing
            }
            "Enter" => self.handle_return(),
            "Home" => {
                self.edit_point.index = 0;
                Nothing
            }
            "End" => {
                self.edit_point.index = self.current_line_length();
                Nothing
            }
            "PageUp" => {
                self.adjust_vertical(-28, event.ShiftKey());
                Nothing
            }
            "PageDown" => {
                self.adjust_vertical(28, event.ShiftKey());
                Nothing
            }
            "Tab" => TriggerDefaultAction,
            _ => Nothing,
        }
    }

    /// Get the current contents of the text input. Multiple lines are joined by \n.
    pub fn get_content(&self) -> DOMString {
        let mut content = "".to_string();
        for (i, line) in self.lines.iter().enumerate() {
            content.push_str(line.as_slice());
            if i < self.lines.len() - 1 {
                content.push('\n');
            }
        }
        content
    }

    /// Set the current contents of the text input. If this is control supports multiple lines,
    /// any \n encountered will be stripped and force a new logical line.
    pub fn set_content(&mut self, content: DOMString) {
        self.lines = if self.multiline {
            content.as_slice().split('\n').map(|s| s.to_string()).collect()
        } else {
            vec!(content)
        };
        self.edit_point.line = min(self.edit_point.line, self.lines.len() - 1);
        self.edit_point.index = min(self.edit_point.index, self.current_line_length() - 1);
    }
}
<|endoftext|>


<commit_before>use std::cmp;

pub fn lev_distance(me: &str, t: &str) -> usize {
    if me.is_empty() {
        return t.chars().count();
    }
    if t.is_empty() {
        return me.chars().count();
    }

    let mut dcol = (0..=t.len()).collect::<Vec<_>>();
    let mut t_last = 0;

    for (i, sc) in me.chars().enumerate() {
        let mut current = i;
        dcol[0] = current + 1;

        for (j, tc) in t.chars().enumerate() {
            let next = dcol[j + 1];

            if sc == tc {
                dcol[j + 1] = current;
            } else {
                dcol[j + 1] = cmp::min(current, next);
                dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1;
            }

            current = next;
            t_last = j;
        }
    }

    dcol[t_last + 1]
}

/// Find the closest element from `iter` matching `choice`. The `key` callback
/// is used to select a `&str` from the iterator to compare against `choice`.
pub fn closest<'a, T>(
    choice: &str,
    iter: impl Iterator<Item = T>,
    key: impl Fn(&T) -> &'a str,
) -> Option<T> {
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    iter.map(|e| (lev_distance(choice, key(&e)), e))
        .filter(|&(d, _)| d < 4)
        .min_by_key(|t| t.0)
        .map(|t| t.1)
}

/// Version of `closest` that returns a common "suggestion" that can be tacked
/// onto the end of an error message.
pub fn closest_msg<'a, T>(
    choice: &str,
    iter: impl Iterator<Item = T>,
    key: impl Fn(&T) -> &'a str,
) -> String {
    match closest(choice, iter, &key) {
        Some(e) => format!("\n\n\tDid you mean `{}`?", key(&e)),
        None => String::new(),
    }
}

#[test]
fn test_lev_distance() {
    use std::char::{from_u32, MAX};
    // Test bytelength agnosticity
    for c in (0u32..MAX as u32)
        .filter_map(from_u32)
        .map(|i| i.to_string())
    {
        assert_eq!(lev_distance(&c, &c), 0);
    }

    let a = "\nMäry häd ä little lämb\n\nLittle lämb\n";
    let b = "\nMary häd ä little lämb\n\nLittle lämb\n";
    let c = "Mary häd ä little lämb\n\nLittle lämb\n";
    assert_eq!(lev_distance(a, b), 1);
    assert_eq!(lev_distance(b, a), 1);
    assert_eq!(lev_distance(a, c), 2);
    assert_eq!(lev_distance(c, a), 2);
    assert_eq!(lev_distance(b, c), 1);
    assert_eq!(lev_distance(c, b), 1);
}
<commit_msg>A little more correct.<commit_after>use std::cmp;

pub fn lev_distance(me: &str, t: &str) -> usize {
    let t_len = t.chars().count();
    if me.is_empty() {
        return t_len;
    }
    if t.is_empty() {
        return me.chars().count();
    }

    let mut dcol = (0..=t_len).collect::<Vec<_>>();
    let mut t_last = 0;

    for (i, sc) in me.chars().enumerate() {
        let mut current = i;
        dcol[0] = current + 1;

        for (j, tc) in t.chars().enumerate() {
            let next = dcol[j + 1];

            if sc == tc {
                dcol[j + 1] = current;
            } else {
                dcol[j + 1] = cmp::min(current, next);
                dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1;
            }

            current = next;
            t_last = j;
        }
    }

    dcol[t_last + 1]
}

/// Find the closest element from `iter` matching `choice`. The `key` callback
/// is used to select a `&str` from the iterator to compare against `choice`.
pub fn closest<'a, T>(
    choice: &str,
    iter: impl Iterator<Item = T>,
    key: impl Fn(&T) -> &'a str,
) -> Option<T> {
    // Only consider candidates with a lev_distance of 3 or less so we don't
    // suggest out-of-the-blue options.
    iter.map(|e| (lev_distance(choice, key(&e)), e))
        .filter(|&(d, _)| d < 4)
        .min_by_key(|t| t.0)
        .map(|t| t.1)
}

/// Version of `closest` that returns a common "suggestion" that can be tacked
/// onto the end of an error message.
pub fn closest_msg<'a, T>(
    choice: &str,
    iter: impl Iterator<Item = T>,
    key: impl Fn(&T) -> &'a str,
) -> String {
    match closest(choice, iter, &key) {
        Some(e) => format!("\n\n\tDid you mean `{}`?", key(&e)),
        None => String::new(),
    }
}

#[test]
fn test_lev_distance() {
    use std::char::{from_u32, MAX};
    // Test bytelength agnosticity
    for c in (0u32..MAX as u32)
        .filter_map(from_u32)
        .map(|i| i.to_string())
    {
        assert_eq!(lev_distance(&c, &c), 0);
    }

    let a = "\nMäry häd ä little lämb\n\nLittle lämb\n";
    let b = "\nMary häd ä little lämb\n\nLittle lämb\n";
    let c = "Mary häd ä little lämb\n\nLittle lämb\n";
    assert_eq!(lev_distance(a, b), 1);
    assert_eq!(lev_distance(b, a), 1);
    assert_eq!(lev_distance(a, c), 2);
    assert_eq!(lev_distance(c, a), 2);
    assert_eq!(lev_distance(b, c), 1);
    assert_eq!(lev_distance(c, b), 1);
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::borrow::Cow;

static SHELL_SPECIAL: &'static str = r#" \$'"`!"#;

/// Escape characters that may have special meaning in a shell,
/// including spaces.
pub fn shell_escape(s: Cow<str>) -> Cow<str> {
    let escape_char = '\\';
    // check if string needs to be escaped
    let clean = SHELL_SPECIAL.chars().all(|sp_char| !s.contains(sp_char));
    if clean {
        return s
    }
    let mut es = String::with_capacity(s.len());
    for ch in s.chars() {
        if SHELL_SPECIAL.contains(ch) {
            es.push(escape_char);
        }
        es.push(ch)
    }
    es.into()
}

#[test]
fn test_shell_escape() {
    assert_eq!(shell_escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
    assert_eq!(shell_escape("linker=gcc -L/foo -Wl,bar".into()),
                            r#"linker=gcc\ -L/foo\ -Wl,bar"#);
    assert_eq!(shell_escape(r#"--features="default""#.into()),
                            r#"--features=\"default\""#);
    assert_eq!(shell_escape(r#"'!\$`\\\n "#.into()),
                            r#"\'\!\\\$\`\\\\\\n\ "#);
}
<commit_msg>Update for windows (WIP)<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(not(target_os = "windows"))]
pub use self::windows::shell_escape;

mod windows {
    use std::borrow::Cow;

    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        panic!()
    }
}

#[cfg(target_os = "windows")]
pub use self::other::shell_escape;

mod other {
    use std::borrow::Cow;

    static SHELL_SPECIAL: &'static str = r#" \$'"`!"#;

    #[cfg(not(target_os = "windows"))]
    /// Escape characters that may have special meaning in a shell,
    /// including spaces.
    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        let escape_char = '\\';
        // check if string needs to be escaped
        let clean = SHELL_SPECIAL.chars().all(|sp_char| !s.contains(sp_char));
        if clean {
            return s
        }
        let mut es = String::with_capacity(s.len());
        for ch in s.chars() {
            if SHELL_SPECIAL.contains(ch) {
                es.push(escape_char);
            }
            es.push(ch)
        }
        es.into()
    }

    #[test]
    fn test_shell_escape() {
        assert_eq!(shell_escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
        assert_eq!(shell_escape("linker=gcc -L/foo -Wl,bar".into()),
                                r#"linker=gcc\ -L/foo\ -Wl,bar"#);
        assert_eq!(shell_escape(r#"--features="default""#.into()),
                                r#"--features=\"default\""#);
        assert_eq!(shell_escape(r#"'!\$`\\\n "#.into()),
                                r#"\'\!\\\$\`\\\\\\n\ "#);
    }
}
<|endoftext|>


<commit_before>mod multiboot;

use ::{kmain};
use super::{kernel_end_paddr, kernel_start_paddr, KERNEL_BASE};
use super::paging::{BASE_PAGE_LENGTH, PD, PT, PML4, pd_index};
use self::multiboot::{Multiboot};

use utils::{block_count, align_up};

use core::mem;
use core::slice;
use core::ptr::{Unique};
use common::{PAddr, VAddr};

extern {
    static multiboot_sig: u32;
    static multiboot_ptr: u64;
    static mut init_pd: PD;
    static kernel_stack_guard_page: u64;
}

// Below should be used BEFORE switching to new page table structure.
const INITIAL_ALLOC_START_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xc00000);
const INITIAL_ALLOC_PML4_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xc00000);
const INITIAL_ALLOC_PDPT_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xc01000);
const INITIAL_ALLOC_PD_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xc02000);
const INITIAL_ALLOC_OBJECT_POOL_PT_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xc03000);
const INITIAL_ALLOC_KERNEL_PT_START_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xc04000);

// Below should be used AFTER switching to new page table structure.
const OBJECT_POOL_START_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xe00000);
const OBJECT_POOL_SIZE: usize = 511;
const OBJECT_POOL_PT_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xfff000);

// Variables
global_variable!(initial_pd, initial_pd_mut, _initial_pd, PD, unsafe { Some(Unique::new(&mut init_pd as *mut _)) });
global_variable!(object_pool_pt, object_pool_pt_mut, _object_pool_pt, PT, None);

global_const!(kernel_pml4_paddr, _kernel_pml4_paddr, PAddr, None);
global_const!(kernel_pd_paddr, _kernel_pd_paddr, PD, None);

// Helper functions
pub fn multiboot_paddr() -> PAddr {
    PAddr::from_u64(multiboot_ptr)
}

pub fn kernel_stack_guard_page_vaddr() -> VAddr {
    VAddr::from_u64((&kernel_stack_guard_page as *const _) as u64)
}

#[derive(Debug)]
pub struct ArchInfo {
    free_memory_length: usize,
    free_memory_regions: [Option<MemoryRegion>; 16]
}

impl ArchInfo {
    pub fn free_memory_regions(&self) -> &[Option<MemoryRegion>; 16] {
        &self.free_memory_regions
    }
}

#[derive(Debug, Copy, Clone)]
pub struct MemoryRegion {
    start_paddr: PAddr,
    length: usize
}

impl MemoryRegion {
    pub fn start_paddr(&self) -> PAddr {
        self.start_paddr
    }

    pub fn length(&self) -> usize {
        self.length
    }

    pub fn move_up(&mut self, npaddr: PAddr) {
        assert!(npaddr >= self.start_paddr);
        assert!(self.start_paddr + self.length > npaddr);
        let nlength = self.start_paddr.as_usize() + self.length - npaddr.as_usize();
        self.length = nlength;
        self.start_paddr = npaddr;
    }
}

// fn alloc_kernel_pml4(kernel_pdpt: &PDPT, &mut MemoryRegion) -> Unique<PML4> {

// }

// fn alloc_kernel_pdpt(kernel_pd: &PD, &mut MemoryRegion) -> Unique<PDPT> {

// }

// fn alloc_kernel_pd(kernel_pts: &[&PT], &mut MemoryRegion) -> Unique<PD> {

// }

// fn alloc_kernel_pts(&mut MemoryRegion) -> &[Unique<PT>] {

// }

// fn map_alloc_in_init_pd(alloc_start_vaddr: VAddr, alloc_start_paddr: PAddr, init_pd_mut: &mut PD) {

// }

fn bootstrap_archinfo() -> (ArchInfo, MemoryRegion) {
    let bootinfo = unsafe {
        multiboot::Multiboot::new(multiboot_paddr(), |addr, size| {
            let ptr = mem::transmute(super::kernel_paddr_to_vaddr(addr).as_usize());
            Some(slice::from_raw_parts(ptr, size))
        })
    }.unwrap();

    let mut archinfo = ArchInfo { free_memory_length: 0,
                                  free_memory_regions: [None; 16] };
    let mut alloc_region: Option<MemoryRegion> = None;

    for area in bootinfo.memory_regions().unwrap() {
        use self::multiboot::{MemoryType};

        if !(area.memory_type() == MemoryType::RAM) {
            continue;
        }

        let mut cur_region = MemoryRegion {
            start_paddr: area.base_address(),
            length: area.length() as usize
        };

        if cur_region.start_paddr <= kernel_start_paddr() &&
            PAddr::from_usize(cur_region.start_paddr.as_usize() + cur_region.length) >= kernel_end_paddr()
        {
            let npaddr = align_up(kernel_end_paddr(), BASE_PAGE_LENGTH);
            cur_region.move_up(npaddr);

            if alloc_region.is_none() {
                alloc_region = Some(cur_region);
            }
        } else {
            archinfo.free_memory_regions[archinfo.free_memory_length] = Some(cur_region);
        }
    }

    (archinfo, alloc_region.unwrap())
}

// This maps 2MB for allocation region
fn map_alloc_region(alloc_region: &mut MemoryRegion) {
    use super::paging::{PD_P, PD_RW, PD_PS, PDEntry};

    let map_alloc_start_vaddr = VAddr::from_u64(KERNEL_BASE + 0xc00000);
    let map_alloc_pd_index = pd_index(map_alloc_start_vaddr);
    let map_alloc_start_paddr = align_up(alloc_region.start_paddr(), BASE_PAGE_LENGTH);

    initial_pd_mut()[map_alloc_pd_index] = PDEntry::new(map_alloc_start_paddr, PD_P | PD_RW | PD_PS);

    unsafe { super::paging::flush(map_alloc_start_vaddr); }
}

/// Kernel entrypoint
#[lang="start"]
#[no_mangle]
pub fn kinit() {
    use super::paging::{PDEntry, PD_P, PD_RW, PD_PS, BASE_PAGE_LENGTH};

    let kernel_page_size = block_count(kernel_end_paddr().as_usize() - kernel_start_paddr().as_usize(), BASE_PAGE_LENGTH);
    let alloc_size =
        1 + // One PML4
        1 + // One PDPT
        1 + // One PD
        block_count(kernel_page_size, 512) + // Kernel page mapping PT
        1
    // The object pool PT, with its last item pointing to itself at address
    // KERNEL_BASE + 0xfff000
        ;

    assert!(alloc_size <= 512);

    let (mut archinfo, mut alloc_region) = bootstrap_archinfo();

    log!("archinfo: {:?}", archinfo);
    log!("alloc_region: {:?}", alloc_region);

    // Before allocation, we need to make sure PAddr + alloc_size is mapped. This is done in the init_pd.

    assert!(alloc_size * BASE_PAGE_LENGTH < alloc_region.length());
    map_alloc_region(&mut alloc_region);

    kmain();
}
<commit_msg>Use const for finding alloc_start_addr<commit_after>mod multiboot;

use ::{kmain};
use super::{kernel_end_paddr, kernel_start_paddr, KERNEL_BASE};
use super::paging::{BASE_PAGE_LENGTH, PD, PT, PML4, pd_index};
use self::multiboot::{Multiboot};

use utils::{block_count, align_up};

use core::mem;
use core::slice;
use core::ptr::{Unique};
use common::{PAddr, VAddr};

extern {
    static multiboot_sig: u32;
    static multiboot_ptr: u64;
    static mut init_pd: PD;
    static kernel_stack_guard_page: u64;
}

// Below should be used BEFORE switching to new page table structure.
const INITIAL_ALLOC_START_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xc00000);
const INITIAL_ALLOC_PML4_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xc00000);
const INITIAL_ALLOC_PDPT_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xc01000);
const INITIAL_ALLOC_PD_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xc02000);
const INITIAL_ALLOC_OBJECT_POOL_PT_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xc03000);
const INITIAL_ALLOC_KERNEL_PT_START_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xc04000);

// Below should be used AFTER switching to new page table structure.
const OBJECT_POOL_START_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xe00000);
const OBJECT_POOL_SIZE: usize = 511;
const OBJECT_POOL_PT_VADDR: VAddr = VAddr::from_u64(KERNEL_BASE + 0xfff000);

// Variables
global_variable!(initial_pd, initial_pd_mut, _initial_pd, PD, unsafe { Some(Unique::new(&mut init_pd as *mut _)) });
global_variable!(object_pool_pt, object_pool_pt_mut, _object_pool_pt, PT, None);

global_const!(kernel_pml4_paddr, _kernel_pml4_paddr, PAddr, None);
global_const!(kernel_pd_paddr, _kernel_pd_paddr, PD, None);

// Helper functions
pub fn multiboot_paddr() -> PAddr {
    PAddr::from_u64(multiboot_ptr)
}

pub fn kernel_stack_guard_page_vaddr() -> VAddr {
    VAddr::from_u64((&kernel_stack_guard_page as *const _) as u64)
}

#[derive(Debug)]
pub struct ArchInfo {
    free_memory_length: usize,
    free_memory_regions: [Option<MemoryRegion>; 16]
}

impl ArchInfo {
    pub fn free_memory_regions(&self) -> &[Option<MemoryRegion>; 16] {
        &self.free_memory_regions
    }
}

#[derive(Debug, Copy, Clone)]
pub struct MemoryRegion {
    start_paddr: PAddr,
    length: usize
}

impl MemoryRegion {
    pub fn start_paddr(&self) -> PAddr {
        self.start_paddr
    }

    pub fn length(&self) -> usize {
        self.length
    }

    pub fn move_up(&mut self, npaddr: PAddr) {
        assert!(npaddr >= self.start_paddr);
        assert!(self.start_paddr + self.length > npaddr);
        let nlength = self.start_paddr.as_usize() + self.length - npaddr.as_usize();
        self.length = nlength;
        self.start_paddr = npaddr;
    }
}

// fn alloc_kernel_pml4(kernel_pdpt: &PDPT, &mut MemoryRegion) -> Unique<PML4> {

// }

// fn alloc_kernel_pdpt(kernel_pd: &PD, &mut MemoryRegion) -> Unique<PDPT> {

// }

// fn alloc_kernel_pd(kernel_pts: &[&PT], &mut MemoryRegion) -> Unique<PD> {

// }

// fn alloc_kernel_pts(&mut MemoryRegion) -> &[Unique<PT>] {

// }

// fn map_alloc_in_init_pd(alloc_start_vaddr: VAddr, alloc_start_paddr: PAddr, init_pd_mut: &mut PD) {

// }

fn bootstrap_archinfo() -> (ArchInfo, MemoryRegion) {
    let bootinfo = unsafe {
        multiboot::Multiboot::new(multiboot_paddr(), |addr, size| {
            let ptr = mem::transmute(super::kernel_paddr_to_vaddr(addr).as_usize());
            Some(slice::from_raw_parts(ptr, size))
        })
    }.unwrap();

    let mut archinfo = ArchInfo { free_memory_length: 0,
                                  free_memory_regions: [None; 16] };
    let mut alloc_region: Option<MemoryRegion> = None;

    for area in bootinfo.memory_regions().unwrap() {
        use self::multiboot::{MemoryType};

        if !(area.memory_type() == MemoryType::RAM) {
            continue;
        }

        let mut cur_region = MemoryRegion {
            start_paddr: area.base_address(),
            length: area.length() as usize
        };

        if cur_region.start_paddr <= kernel_start_paddr() &&
            PAddr::from_usize(cur_region.start_paddr.as_usize() + cur_region.length) >= kernel_end_paddr()
        {
            let npaddr = align_up(kernel_end_paddr(), BASE_PAGE_LENGTH);
            cur_region.move_up(npaddr);

            if alloc_region.is_none() {
                alloc_region = Some(cur_region);
            }
        } else {
            archinfo.free_memory_regions[archinfo.free_memory_length] = Some(cur_region);
        }
    }

    (archinfo, alloc_region.unwrap())
}

// This maps 2MB for allocation region
fn map_alloc_region(alloc_region: &mut MemoryRegion) {
    use super::paging::{PD_P, PD_RW, PD_PS, PDEntry};

    let map_alloc_start_vaddr = INITIAL_ALLOC_START_VADDR;
    let map_alloc_pd_index = pd_index(map_alloc_start_vaddr);
    let map_alloc_start_paddr = align_up(alloc_region.start_paddr(), BASE_PAGE_LENGTH);

    initial_pd_mut()[map_alloc_pd_index] = PDEntry::new(map_alloc_start_paddr, PD_P | PD_RW | PD_PS);

    unsafe { super::paging::flush(map_alloc_start_vaddr); }
}

/// Kernel entrypoint
#[lang="start"]
#[no_mangle]
pub fn kinit() {
    use super::paging::{PDEntry, PD_P, PD_RW, PD_PS, BASE_PAGE_LENGTH};

    let kernel_page_size = block_count(kernel_end_paddr().as_usize() - kernel_start_paddr().as_usize(), BASE_PAGE_LENGTH);
    let alloc_size =
        1 + // One PML4
        1 + // One PDPT
        1 + // One PD
        block_count(kernel_page_size, 512) + // Kernel page mapping PT
        1
    // The object pool PT, with its last item pointing to itself at address
    // KERNEL_BASE + 0xfff000
        ;

    assert!(alloc_size <= 512);

    let (mut archinfo, mut alloc_region) = bootstrap_archinfo();

    log!("archinfo: {:?}", archinfo);
    log!("alloc_region: {:?}", alloc_region);

    // Before allocation, we need to make sure PAddr + alloc_size is mapped. This is done in the init_pd.

    assert!(alloc_size * BASE_PAGE_LENGTH < alloc_region.length());
    map_alloc_region(&mut alloc_region);

    kmain();
}
<|endoftext|>


<commit_before>//! Contains the `Row` trait

use crate::{
    backend::{self, Backend},
    deserialize,
};
use deserialize::FromSql;
use std::ops::Range;

/// Representing a way to index into database rows
///
/// * Crates using existing backends should use existing implementations of
///   this traits. Diesel provides `RowIndex<usize>` and `RowIndex<&str>` for
///   all bulit-in backends
///
/// * Crates implementing custom backends need to provide `RowIndex<usize>` and
///   `RowIndex<&str>` impls for their [`Row`] type.
///
pub trait RowIndex<I> {
    /// Get the numeric index inside the current row for the provided index value
    fn idx(&self, idx: I) -> Option<usize>;
}

/// A helper trait to indicate the life time bound for a field returned
/// by [`Row::get`]
pub trait RowGatWorkaround<'a, DB: Backend> {
    /// Field type returned by a `Row` implementation
    ///
    /// * Crates using existing backend should not concern themself with the
    ///   concrete type of this associated type.
    ///
    /// * Crates implementing custom backends should provide their own type
    ///   meeting the required trait bounds
    type Field: Field<'a, DB>;
}

/// Represents a single database row.
///
/// This trait is used as an argument to [`FromSqlRow`].
///
/// [`FromSqlRow`]: crate::deserialize::FromSqlRow
pub trait Row<'a, DB: Backend>:
    RowIndex<usize> + for<'b> RowIndex<&'b str> + for<'b> RowGatWorkaround<'b, DB> + Sized
{
    /// Return type of `PartialRow`
    ///
    /// For all implementations, beside of the `Row` implementation on `PartialRow` itself
    /// this should be `Self`.
    #[doc(hidden)]
    type InnerPartialRow: Row<'a, DB>;

    /// Get the number of fields in the current row
    fn field_count(&self) -> usize;

    /// Get the field with the provided index from the row.
    ///
    /// Returns `None` if there is no matching field for the given index
    fn get<'b, I>(&'b self, idx: I) -> Option<<Self as RowGatWorkaround<'b, DB>>::Field>
    where
        'a: 'b,
        Self: RowIndex<I>;

    /// Get a deserialized value with the provided index from the row.
    ///
    /// Returns `None` if there is no matching field for the given index
    /// Returns `Some(Err(…)` if there is an error during deserialization
    /// Returns `Some(T)` if deserialization is successful
    fn get_value<ST, T, I>(&self, idx: I) -> Option<crate::deserialize::Result<T>>
    where
        Self: RowIndex<I>,
        T: FromSql<ST, DB>,
    {
        let field = self.get(idx)?;
        Some(<T as FromSql<ST, DB>>::from_nullable_sql(field.value()))
    }

    /// Returns a wrapping row that allows only to access fields, where the index is part of
    /// the provided range.
    #[doc(hidden)]
    fn partial_row(&self, range: Range<usize>) -> PartialRow<Self::InnerPartialRow>;
}

/// Represents a single field in a database row.
///
/// This trait allows retrieving information on the name of the colum and on the value of the
/// field.
pub trait Field<'a, DB: Backend> {
    /// The name of the current field
    ///
    /// Returns `None` if it's an unnamed field
    fn field_name(&self) -> Option<&str>;

    /// Get the value representing the current field in the raw representation
    /// as it is transmitted by the database
    fn value(&self) -> Option<backend::RawValue<DB>>;

    /// Checks whether this field is null or not.
    fn is_null(&self) -> bool {
        self.value().is_none()
    }
}

/// A row type that wraps an inner row
///
/// This type only allows to access fields of the inner row, whose index is
/// part of `range`.
///
/// Indexing via `usize` starts with 0 for this row type. The index is then shifted
/// by `self.range.start` to match the corresponding field in the underlying row.
#[derive(Debug)]
#[doc(hidden)]
pub struct PartialRow<'a, R> {
    inner: &'a R,
    range: Range<usize>,
}

impl<'a, R> PartialRow<'a, R> {
    #[doc(hidden)]
    pub fn new<'b, DB>(inner: &'a R, range: Range<usize>) -> Self
    where
        R: Row<'b, DB>,
        DB: Backend,
    {
        let range_lower = std::cmp::min(range.start, inner.field_count());
        let range_upper = std::cmp::min(range.end, inner.field_count());
        Self {
            inner,
            range: range_lower..range_upper,
        }
    }
}

impl<'a, 'b, DB, R> RowGatWorkaround<'a, DB> for PartialRow<'b, R>
where
    DB: Backend,
    R: RowGatWorkaround<'a, DB>,
{
    type Field = R::Field;
}

impl<'a, 'b, DB, R> Row<'a, DB> for PartialRow<'b, R>
where
    DB: Backend,
    R: Row<'a, DB>,
{
    type InnerPartialRow = R;

    fn field_count(&self) -> usize {
        self.range.len()
    }

    fn get<'c, I>(&'c self, idx: I) -> Option<<Self as RowGatWorkaround<'c, DB>>::Field>
    where
        'a: 'c,
        Self: RowIndex<I>,
    {
        let idx = self.idx(idx)?;
        self.inner.get(idx)
    }

    fn partial_row(&self, range: Range<usize>) -> PartialRow<R> {
        let range_upper_bound = std::cmp::min(self.range.end, self.range.start + range.end);
        let range = (self.range.start + range.start)..range_upper_bound;
        PartialRow {
            inner: self.inner,
            range,
        }
    }
}

impl<'a, 'b, R> RowIndex<&'a str> for PartialRow<'b, R>
where
    R: RowIndex<&'a str>,
{
    fn idx(&self, idx: &'a str) -> Option<usize> {
        let idx = self.inner.idx(idx)?;
        if self.range.contains(&idx) {
            Some(idx)
        } else {
            None
        }
    }
}

impl<'a, R> RowIndex<usize> for PartialRow<'a, R>
where
    R: RowIndex<usize>,
{
    fn idx(&self, idx: usize) -> Option<usize> {
        let idx = self.inner.idx(idx + self.range.start)?;
        if self.range.contains(&idx) {
            Some(idx)
        } else {
            None
        }
    }
}

/// Represents a row of a SQL query, where the values are accessed by name
/// rather than by index.
///
/// This trait is used by implementations of
/// [`QueryableByName`](crate::deserialize::QueryableByName)
pub trait NamedRow<'a, DB: Backend>: Row<'a, DB> {
    /// Retrieve and deserialize a single value from the query
    ///
    /// Note that `ST` *must* be the exact type of the value with that name in
    /// the query. The compiler will not be able to verify that you have
    /// provided the correct type. If there is a mismatch, you may receive an
    /// incorrect value, or a runtime error.
    ///
    /// If two or more fields in the query have the given name, the result of
    /// this function is undefined.
    fn get<ST, T>(&self, column_name: &str) -> deserialize::Result<T>
    where
        T: FromSql<ST, DB>;
}

impl<'a, R, DB> NamedRow<'a, DB> for R
where
    R: Row<'a, DB>,
    DB: Backend,
{
    fn get<ST, T>(&self, column_name: &str) -> deserialize::Result<T>
    where
        T: FromSql<ST, DB>,
    {
        let field = Row::get(self, column_name)
            .ok_or_else(|| format!("Column `{}` was not present in query", column_name))?;

        T::from_nullable_sql(field.value())
    }
}
<commit_msg>Apply review commend regarding to `Row::get_value`<commit_after>//! Contains the `Row` trait

use crate::{
    backend::{self, Backend},
    deserialize,
};
use deserialize::FromSql;
use std::ops::Range;

/// Representing a way to index into database rows
///
/// * Crates using existing backends should use existing implementations of
///   this traits. Diesel provides `RowIndex<usize>` and `RowIndex<&str>` for
///   all bulit-in backends
///
/// * Crates implementing custom backends need to provide `RowIndex<usize>` and
///   `RowIndex<&str>` impls for their [`Row`] type.
///
pub trait RowIndex<I> {
    /// Get the numeric index inside the current row for the provided index value
    fn idx(&self, idx: I) -> Option<usize>;
}

/// A helper trait to indicate the life time bound for a field returned
/// by [`Row::get`]
pub trait RowGatWorkaround<'a, DB: Backend> {
    /// Field type returned by a `Row` implementation
    ///
    /// * Crates using existing backend should not concern themself with the
    ///   concrete type of this associated type.
    ///
    /// * Crates implementing custom backends should provide their own type
    ///   meeting the required trait bounds
    type Field: Field<'a, DB>;
}

/// Represents a single database row.
///
/// This trait is used as an argument to [`FromSqlRow`].
///
/// [`FromSqlRow`]: crate::deserialize::FromSqlRow
pub trait Row<'a, DB: Backend>:
    RowIndex<usize> + for<'b> RowIndex<&'b str> + for<'b> RowGatWorkaround<'b, DB> + Sized
{
    /// Return type of `PartialRow`
    ///
    /// For all implementations, beside of the `Row` implementation on `PartialRow` itself
    /// this should be `Self`.
    #[doc(hidden)]
    type InnerPartialRow: Row<'a, DB>;

    /// Get the number of fields in the current row
    fn field_count(&self) -> usize;

    /// Get the field with the provided index from the row.
    ///
    /// Returns `None` if there is no matching field for the given index
    fn get<'b, I>(&'b self, idx: I) -> Option<<Self as RowGatWorkaround<'b, DB>>::Field>
    where
        'a: 'b,
        Self: RowIndex<I>;

    /// Get a deserialized value with the provided index from the row.
    ///
    /// * Returns `Ok(T)` if deserialization is successful
    /// * Returns `Err(Error::DeserializationError)` if there is an error during deserialization
    /// * Returns `Err(Error::NotFound)` if the row does not contain a value at this position
    /// use [`result.optional()`](crate::result::OptionalExtension) to convert the result to
    /// `QueryResult<Option<T>>` for explicit access to the `None` values
    fn get_value<ST, T, I>(&self, idx: I) -> crate::result::QueryResult<T>
    where
        Self: RowIndex<I>,
        T: FromSql<ST, DB>,
    {
        let field = self.get(idx).ok_or(crate::result::Error::NotFound)?;
        <T as FromSql<ST, DB>>::from_nullable_sql(field.value())
            .map_err(crate::result::Error::DeserializationError)
    }

    /// Returns a wrapping row that allows only to access fields, where the index is part of
    /// the provided range.
    #[doc(hidden)]
    fn partial_row(&self, range: Range<usize>) -> PartialRow<Self::InnerPartialRow>;
}

/// Represents a single field in a database row.
///
/// This trait allows retrieving information on the name of the colum and on the value of the
/// field.
pub trait Field<'a, DB: Backend> {
    /// The name of the current field
    ///
    /// Returns `None` if it's an unnamed field
    fn field_name(&self) -> Option<&str>;

    /// Get the value representing the current field in the raw representation
    /// as it is transmitted by the database
    fn value(&self) -> Option<backend::RawValue<DB>>;

    /// Checks whether this field is null or not.
    fn is_null(&self) -> bool {
        self.value().is_none()
    }
}

/// A row type that wraps an inner row
///
/// This type only allows to access fields of the inner row, whose index is
/// part of `range`.
///
/// Indexing via `usize` starts with 0 for this row type. The index is then shifted
/// by `self.range.start` to match the corresponding field in the underlying row.
#[derive(Debug)]
#[doc(hidden)]
pub struct PartialRow<'a, R> {
    inner: &'a R,
    range: Range<usize>,
}

impl<'a, R> PartialRow<'a, R> {
    #[doc(hidden)]
    pub fn new<'b, DB>(inner: &'a R, range: Range<usize>) -> Self
    where
        R: Row<'b, DB>,
        DB: Backend,
    {
        let range_lower = std::cmp::min(range.start, inner.field_count());
        let range_upper = std::cmp::min(range.end, inner.field_count());
        Self {
            inner,
            range: range_lower..range_upper,
        }
    }
}

impl<'a, 'b, DB, R> RowGatWorkaround<'a, DB> for PartialRow<'b, R>
where
    DB: Backend,
    R: RowGatWorkaround<'a, DB>,
{
    type Field = R::Field;
}

impl<'a, 'b, DB, R> Row<'a, DB> for PartialRow<'b, R>
where
    DB: Backend,
    R: Row<'a, DB>,
{
    type InnerPartialRow = R;

    fn field_count(&self) -> usize {
        self.range.len()
    }

    fn get<'c, I>(&'c self, idx: I) -> Option<<Self as RowGatWorkaround<'c, DB>>::Field>
    where
        'a: 'c,
        Self: RowIndex<I>,
    {
        let idx = self.idx(idx)?;
        self.inner.get(idx)
    }

    fn partial_row(&self, range: Range<usize>) -> PartialRow<R> {
        let range_upper_bound = std::cmp::min(self.range.end, self.range.start + range.end);
        let range = (self.range.start + range.start)..range_upper_bound;
        PartialRow {
            inner: self.inner,
            range,
        }
    }
}

impl<'a, 'b, R> RowIndex<&'a str> for PartialRow<'b, R>
where
    R: RowIndex<&'a str>,
{
    fn idx(&self, idx: &'a str) -> Option<usize> {
        let idx = self.inner.idx(idx)?;
        if self.range.contains(&idx) {
            Some(idx)
        } else {
            None
        }
    }
}

impl<'a, R> RowIndex<usize> for PartialRow<'a, R>
where
    R: RowIndex<usize>,
{
    fn idx(&self, idx: usize) -> Option<usize> {
        let idx = self.inner.idx(idx + self.range.start)?;
        if self.range.contains(&idx) {
            Some(idx)
        } else {
            None
        }
    }
}

/// Represents a row of a SQL query, where the values are accessed by name
/// rather than by index.
///
/// This trait is used by implementations of
/// [`QueryableByName`](crate::deserialize::QueryableByName)
pub trait NamedRow<'a, DB: Backend>: Row<'a, DB> {
    /// Retrieve and deserialize a single value from the query
    ///
    /// Note that `ST` *must* be the exact type of the value with that name in
    /// the query. The compiler will not be able to verify that you have
    /// provided the correct type. If there is a mismatch, you may receive an
    /// incorrect value, or a runtime error.
    ///
    /// If two or more fields in the query have the given name, the result of
    /// this function is undefined.
    fn get<ST, T>(&self, column_name: &str) -> deserialize::Result<T>
    where
        T: FromSql<ST, DB>;
}

impl<'a, R, DB> NamedRow<'a, DB> for R
where
    R: Row<'a, DB>,
    DB: Backend,
{
    fn get<ST, T>(&self, column_name: &str) -> deserialize::Result<T>
    where
        T: FromSql<ST, DB>,
    {
        let field = Row::get(self, column_name)
            .ok_or_else(|| format!("Column `{}` was not present in query", column_name))?;

        T::from_nullable_sql(field.value())
    }
}
<|endoftext|>


<commit_before>//! # IconView Sample
//!
//! This sample demonstrates how to create a toplevel `window`, set its title, size and
//! position, how to add a `IconView` to this `window` and how to set `model` of the `IconView`
//! A Gtk.IconView is a widget that displays a collection of icons in a grid view.
//! It supports features such as drag and drop, multiple selections and item reordering.
//! Similarly to Gtk.TreeView, Gtk.IconView uses a Gtk.ListStore for its model.
//! Instead of using cell renderers, Gtk.IconView requires that one of the columns in its
//! Gtk.ListStore contains GdkPixbuf.Pixbuf objects.
//! The example is using icons from the current icon theme. To view all icons and their names please install
//! gtk3-icon-browser: https://developer.gnome.org/gtk3/stable/gtk3-icon-browser.html

extern crate gio;
extern crate gtk;

use gio::prelude::*;
use gtk::prelude::*;

use std::env::args;
use std::process;

// Concinience Enum for IconView column types
enum IconViewColumnType {
    TextColumn = 0,
    PixbufColumn = 1
}

fn create_list_store_model() -> gtk::ListStore {
    // Initialize array of icon names, these can be found using gtk3-icon-browser app
    let icons: [&'static str; 3] = ["edit-cut", "edit-paste", "edit-copy"];

    // Initialize an array of column types for ListStore object. Here we say that the first item must always be of Type String
    // and the second item is of Type Pixbuf.
    let col_types: [glib::Type; 2] = [glib::Type::String, gdk_pixbuf::Pixbuf::static_type()];
    let icon_view_model = gtk::ListStore::new(&col_types);

    // IconTheme provides a facility for looking up icons by name and size.
    // Get default icon theme
    let icon_theme: Option<gtk::IconTheme> = gtk::IconTheme::get_default();
    if let Some(it) = icon_theme {
        for x in &icons {
            // Looks up an icon in an icon theme, scales it to the given size and renders it into a pixbuf.
            let result = it.load_icon(x, 64, gtk::IconLookupFlags::empty());
            match result {
                Ok(r) => {
                    // Notice how we specified the first column to be Text and second to be Pixbuf just like in col_types var
                    // The values also follow the same order, &[&String::from("Label"), &r]. First item is text, second is pixbuf
                    icon_view_model.insert_with_values(None, &[IconViewColumnType::TextColumn as u32, IconViewColumnType::PixbufColumn as u32], &[&String::from("Label"), &r]);
                },
                Err(err) => {
                    println!("Error: {}", err);
                    process::exit(1);
                }
            }
        }

    }

    return icon_view_model;
}

fn build_ui(application: &gtk::Application) {
    let window = gtk::ApplicationWindow::new(application);

    window.set_title("IconView Example");
    window.set_border_width(10);
    window.set_position(gtk::WindowPosition::Center);
    window.set_default_size(350, 70);

    let icon_view = gtk::IconView::new();
    icon_view.set_item_padding(0);
    icon_view.set_columns(3);
    icon_view.set_column_spacing(0);
    // User can select only one item at a time
    icon_view.set_selection_mode(gtk::SelectionMode::Single);

    // Create a model for our IconView
    let icon_view_model = create_list_store_model();
    // Set IconView model
    icon_view.set_model(Some(&icon_view_model));

    // And finally set text column and pixbuf column using enum
    icon_view.set_text_column(IconViewColumnType::TextColumn as i32);
    icon_view.set_pixbuf_column(IconViewColumnType::PixbufColumn as i32);

    window.add(&icon_view);
    window.show_all();
}

fn main() {
    let application =
        gtk::Application::new(Some("com.github.gtk-rs.examples.iconview_example"), Default::default())
            .expect("Initialization failed...");

    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run(&args().collect::<Vec<_>>());
}
<commit_msg>cargo fmt<commit_after>//! # IconView Sample
//!
//! This sample demonstrates how to create a toplevel `window`, set its title, size and
//! position, how to add a `IconView` to this `window` and how to set `model` of the `IconView`
//! A Gtk.IconView is a widget that displays a collection of icons in a grid view.
//! It supports features such as drag and drop, multiple selections and item reordering.
//! Similarly to Gtk.TreeView, Gtk.IconView uses a Gtk.ListStore for its model.
//! Instead of using cell renderers, Gtk.IconView requires that one of the columns in its
//! Gtk.ListStore contains GdkPixbuf.Pixbuf objects.
//! The example is using icons from the current icon theme. To view all icons and their names please install
//! gtk3-icon-browser: https://developer.gnome.org/gtk3/stable/gtk3-icon-browser.html

extern crate gio;
extern crate gtk;

use gio::prelude::*;
use gtk::prelude::*;

use std::env::args;
use std::process;

// Concinience Enum for IconView column types
enum IconViewColumnType {
    TextColumn = 0,
    PixbufColumn = 1,
}

fn create_list_store_model() -> gtk::ListStore {
    // Initialize array of icon names, these can be found using gtk3-icon-browser app
    let icons: [&'static str; 3] = ["edit-cut", "edit-paste", "edit-copy"];

    // Initialize an array of column types for ListStore object. Here we say that the first item must always be of Type String
    // and the second item is of Type Pixbuf.
    let col_types: [glib::Type; 2] = [glib::Type::String, gdk_pixbuf::Pixbuf::static_type()];
    let icon_view_model = gtk::ListStore::new(&col_types);

    // IconTheme provides a facility for looking up icons by name and size.
    // Get default icon theme
    let icon_theme: Option<gtk::IconTheme> = gtk::IconTheme::get_default();
    if let Some(it) = icon_theme {
        for x in &icons {
            // Looks up an icon in an icon theme, scales it to the given size and renders it into a pixbuf.
            let result = it.load_icon(x, 64, gtk::IconLookupFlags::empty());
            match result {
                Ok(r) => {
                    // Notice how we specified the first column to be Text and second to be Pixbuf just like in col_types var
                    // The values also follow the same order, &[&String::from("Label"), &r]. First item is text, second is pixbuf
                    icon_view_model.insert_with_values(
                        None,
                        &[
                            IconViewColumnType::TextColumn as u32,
                            IconViewColumnType::PixbufColumn as u32,
                        ],
                        &[&String::from("Label"), &r],
                    );
                }
                Err(err) => {
                    println!("Error: {}", err);
                    process::exit(1);
                }
            }
        }
    }

    return icon_view_model;
}

fn build_ui(application: &gtk::Application) {
    let window = gtk::ApplicationWindow::new(application);

    window.set_title("IconView Example");
    window.set_border_width(10);
    window.set_position(gtk::WindowPosition::Center);
    window.set_default_size(350, 70);

    let icon_view = gtk::IconView::new();
    icon_view.set_item_padding(0);
    icon_view.set_columns(3);
    icon_view.set_column_spacing(0);
    // User can select only one item at a time
    icon_view.set_selection_mode(gtk::SelectionMode::Single);

    // Create a model for our IconView
    let icon_view_model = create_list_store_model();
    // Set IconView model
    icon_view.set_model(Some(&icon_view_model));

    // And finally set text column and pixbuf column using enum
    icon_view.set_text_column(IconViewColumnType::TextColumn as i32);
    icon_view.set_pixbuf_column(IconViewColumnType::PixbufColumn as i32);

    window.add(&icon_view);
    window.show_all();
}

fn main() {
    let application = gtk::Application::new(
        Some("com.github.gtk-rs.examples.iconview_example"),
        Default::default(),
    )
    .expect("Initialization failed...");

    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run(&args().collect::<Vec<_>>());
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;

extern crate regex;
use regex::Regex;

fn count_diff(text: &String) -> usize {
    let hex_re = Regex::new(r"\\x[a-f0-9]{2}").unwrap();
    let no_hex = hex_re.replace_all(&text, " ");
    let esc_re = Regex::new(r"\\.").unwrap();
    let no_esc = esc_re.replace_all(&no_hex, " ");
    no_esc.len()
}

fn main() {
    let stdin = io::stdin();
    let input = stdin.lock().lines();
    let lens = input.map(|res| {
        let s = res.unwrap();
        (s.len(), count_diff(&s) - 2)
    });
    let totals = lens.fold((0, 0), |acc, e| (acc.0 + e.0, acc.1 + e.1));
    println!("({}, {})", totals.0, totals.1);
    println!("{}", totals.0 - totals.1);
}
<commit_msg>day 8 part 2<commit_after>use std::io;
use std::io::prelude::*;

extern crate regex;
use regex::Regex;

fn count_diff(text: &String) -> usize {
    let hex_re = Regex::new(r"\\x[a-f0-9]{2}").unwrap();
    let no_hex = hex_re.replace_all(&text, " ");
    let esc_re = Regex::new(r"\\.").unwrap();
    let no_esc = esc_re.replace_all(&no_hex, " ");
    no_esc.len()
}

fn count_escaped(text: &String) -> usize {
    text.chars()
        .fold(
            0 as usize,
            |acc, c| acc + match c {
                '"' | '\\' => 2,
                _          => 1,
            }
        )
}

fn main() {
    let stdin = io::stdin();
    let input = stdin.lock().lines();
    let lens = input.map(|res| {
        let s = res.unwrap();
        (s.len(), count_diff(&s) - 2, count_escaped(&s) + 2)
    });
    let totals = lens.fold(
        (0, 0, 0),
        |acc, e| (acc.0 + e.0, acc.1 + e.1, acc.2 + e.2)
    );
    println!("({}, {} {})", totals.0, totals.1, totals.2);
    println!("{}", totals.0 - totals.1);
    println!("{}", totals.2 - totals.0);
}
<|endoftext|>


<commit_before>//! Performs constant folding on literals

use compiler::Warning;
use compiler::visit::*;
use compiler::ast::*;
use compiler::span::Spanned;
use op::*;

use std::num::{Int, Float};

struct Folder {
    warns: Vec<Warning>,
}

fn unary_err(op: UnOp, lit: &Literal) -> String {
    format!("attempt to apply unary {} to type \"{}\"", op, lit.get_type_str())
}

fn bin_err(lhs: &Literal, op: BinOp, rhs: &Literal) -> String {
    format!("attempt to apply binary {} to {} and {}", op, lhs.get_type_str(), rhs.get_type_str())
}

/// Tries to fold a unary operator applied to a literal.
///
/// Returns `Ok(Literal)` on success and `Err(String)` with an appropriate error message if the
/// type of the literal mismatched the operator's expected type or domain. This causes a warning to
/// be emitted.
fn fold_unop(op: UnOp, lit: &Literal) -> Result<Literal, String> {
    match op {
        UnOp::Negate => match *lit { // -
            TInt(i) => Ok(TInt(-i)),
            TFloat(f) => Ok(TFloat(-f)),
            TStr(_) | TBool(_) | TNil => Err(unary_err(op, lit)),
        },
        UnOp::LNot => match *lit { // ! / not
            TInt(_) | TFloat(_) | TStr(_) => Ok(TBool(false)),  // all these evaluate to true
            TBool(b) => Ok(TBool(!b)),
            TNil => Err(unary_err(op, lit)),
        },
        UnOp::BNot => match *lit { // ~
            TInt(i) => Ok(TInt(!i)),
            TFloat(_) | TStr(_) | TBool(_) | TNil => Err(unary_err(op, lit)),
        },
        UnOp::Len => match *lit { // #
            TInt(_) | TFloat(_) | TBool(_) | TNil => Err(unary_err(op, lit)),

            // # of graphemes is the way to go
            TStr(ref s) => Ok(TInt(s.as_slice().graphemes(true).count() as i64)),
        },
    }
}

/// `fold_unop` for binary operators
fn fold_binop(lhs: &Literal, op: BinOp, rhs: &Literal) -> Result<Literal, String> {
    match op {
        BinOp::Add => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TInt(i + j)),
            (&TInt(i), &TFloat(j)) => Ok(TFloat(i as f64 + j)),
            (&TFloat(i), &TInt(j)) => Ok(TFloat(i + j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TFloat(i + j)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Sub => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TInt(i - j)),
            (&TInt(i), &TFloat(j)) => Ok(TFloat(i as f64 - j)),
            (&TFloat(i), &TInt(j)) => Ok(TFloat(i - j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TFloat(i - j)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Mul => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TInt(i * j)),
            (&TInt(i), &TFloat(j)) => Ok(TFloat(i as f64 * j)),
            (&TFloat(i), &TInt(j)) => Ok(TFloat(i * j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TFloat(i * j)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Div => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TInt(i / j)),
            (&TInt(i), &TFloat(j)) => Ok(TFloat(i as f64 / j)),
            (&TFloat(i), &TInt(j)) => Ok(TFloat(i / j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TFloat(i / j)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Mod => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TInt(i % j)),
            (&TInt(i), &TFloat(j)) => Ok(TFloat(i as f64 % j)),
            (&TFloat(i), &TInt(j)) => Ok(TFloat(i % j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TFloat(i % j)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Pow => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => {
                if j > u32::max_value() as i64 {
                    Err(format!("exponent {} is out of range", j))
                } else {
                    Ok(TInt(i.pow(j as u32)))
                }
            },
            (&TInt(i), &TFloat(j)) => {
                Ok(TFloat((i as f64).powf(j)))
            },
            (&TFloat(i), &TInt(j)) => {
                if j > i32::max_value() as i64 {
                    Err(format!("exponent {} is out of range", j))
                } else {
                    Ok(TFloat(i.powi(j as i32)))
                }
            },
            (&TFloat(i), &TFloat(j)) => {
                Ok(TFloat(i.powf(j)))
            },
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Concat => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TStr(format!("{}{}", i, j))),
            (&TInt(i), &TFloat(j)) => Ok(TStr(format!("{}{}", i, j))),
            (&TFloat(i), &TInt(j)) => Ok(TStr(format!("{}{}", i, j))),
            (&TFloat(i), &TFloat(j)) => Ok(TStr(format!("{}{}", i, j))),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Eq | BinOp::NEq | BinOp::NEqLua => {
            let res = match (lhs, rhs) {
                (&TInt(i), &TInt(j)) => i == j,
                (&TInt(i), &TFloat(j)) => i as f64 == j,
                (&TFloat(i), &TInt(j)) => i == j as f64,
                (&TFloat(i), &TFloat(j)) => i == j,
                (&TBool(i), &TBool(j)) => i == j,
                (&TStr(ref a), &TStr(ref b)) => a == b,
                (&TNil, &TNil) => true,
                _ => false,
            };
            if op == BinOp::Eq { Ok(TBool(res)) } else { Ok(TBool(!res)) }
        },
        BinOp::LEq => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TBool(i <= j)),
            (&TInt(i), &TFloat(j)) => Ok(TBool(i as f64 <= j)),
            (&TFloat(i), &TInt(j)) => Ok(TBool(i <= j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TBool(i <= j)),
            (&TStr(ref a), &TStr(ref b)) => Ok(TBool(a <= b)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::GEq => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TBool(i >= j)),
            (&TInt(i), &TFloat(j)) => Ok(TBool(i as f64 >= j)),
            (&TFloat(i), &TInt(j)) => Ok(TBool(i >= j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TBool(i >= j)),
            (&TStr(ref a), &TStr(ref b)) => Ok(TBool(a >= b)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Less => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TBool(i < j)),
            (&TInt(i), &TFloat(j)) => Ok(TBool((i as f64) < j)),
            (&TFloat(i), &TInt(j)) => Ok(TBool(i < j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TBool(i < j)),
            (&TStr(ref a), &TStr(ref b)) => Ok(TBool(a < b)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Greater => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TBool(i > j)),
            (&TInt(i), &TFloat(j)) => Ok(TBool(i as f64 > j)),
            (&TFloat(i), &TInt(j)) => Ok(TBool(i > j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TBool(i > j)),
            (&TStr(ref a), &TStr(ref b)) => Ok(TBool(a > b)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        _ => Err(bin_err(lhs, op, rhs)),
    }
}

impl Visitor for Folder {
    fn visit_expr(&mut self, mut e: Expr) -> Expr {
        e.value = match e.value {
            EBinOp(mut lhs, op, mut rhs) => {
                // TODO fold these too
                lhs = Box::new(self.visit_expr(*lhs));
                rhs = Box::new(self.visit_expr(*rhs));

                let lspan = lhs.span;
                let rspan = rhs.span;
                if let ELit(lit_lhs) = lhs.value {
                    if let ELit(lit_rhs) = rhs.value {
                        match fold_binop(&lit_lhs, op, &lit_rhs) {
                            Ok(newlit) => ELit(newlit),
                            Err(msg) => {
                                self.warns.push(Warning::new(e.span, msg));
                                EBinOp(Box::new(Spanned::new(lspan, ELit(lit_lhs))), op, Box::new(Spanned::new(rspan, ELit(lit_rhs))))
                            }
                        }
                    } else {
                        EBinOp(Box::new(Spanned::new(lspan, ELit(lit_lhs))), op, rhs)
                    }
                } else {
                    EBinOp(lhs, op, rhs)
                }
            },
            EUnOp(op, mut arg) => {
                arg = Box::new(self.visit_expr(*arg));

                let span = arg.span;
                if let ELit(lit) = arg.value {
                    match fold_unop(op, &lit) {
                        Ok(newlit) => ELit(newlit),
                        Err(msg) => {
                            self.warns.push(Warning::new(e.span, msg));
                            EUnOp(op, Box::new(Spanned::new(span, ELit(lit))))
                        }
                    }
                } else {
                    EUnOp(op, arg)
                }
            },
            _ => { return walk_expr(e, self) },
        };

        e
    }
}

pub fn run(mut main: Function) -> (Function, Vec<Warning>) {
    let mut v = Folder {
        warns: vec![],
    };

    main = walk_func(main, &mut v);
    (main, v.warns)
}

#[cfg(test)]
mod tests {
    use super::*;
    use compiler::*;

    /// Parses and folds `raw`, then parses `folded`. Asserts that the ASTs are equal.
    fn test(raw: &str, folded: &str) {
        let mut conf = CompileConfig::empty();
        conf.add_transform(run, LintMode::Warn);

        let main = parse_and_resolve(raw).unwrap();
        let (main, _warns) = apply_transforms(main, &conf).unwrap();
        let expected = parse_and_resolve(folded).unwrap();

        assert_eq!(main, expected);
    }

    #[test]
    fn basic() {
        test("return -0, -4.5, #\"TEST\"", "return 0, -4.5, 4");
        test("return 1-1+3*(1-1)/1^1+1", "return 1");
    }
}
<commit_msg>More work on constant folder<commit_after>//! Performs constant folding on literals

use compiler::Warning;
use compiler::visit::*;
use compiler::ast::*;
use compiler::span::Spanned;
use op::*;

use std::num::{Int, Float};

struct Folder {
    warns: Vec<Warning>,
}

fn unary_err(op: UnOp, lit: &Literal) -> String {
    format!("attempt to apply unary {} to type \"{}\"", op, lit.get_type_str())
}

fn bin_err(lhs: &Literal, op: BinOp, rhs: &Literal) -> String {
    format!("attempt to apply binary {} to {} and {}", op, lhs.get_type_str(), rhs.get_type_str())
}

/// Folds a literal used as a truth value (eg. as an if condition or in a logical operator).
fn fold_truth(lit: &Literal) -> bool {
    match *lit {
        TInt(_) | TFloat(_) | TStr(_) | TBool(true) => true,
        TBool(false) | TNil => false,
    }
}

/// Tries to fold a unary operator applied to a literal.
///
/// Returns `Ok(Literal)` on success and `Err(String)` with an appropriate error message if the
/// type of the literal mismatched the operator's expected type or domain. This causes a warning to
/// be emitted.
fn fold_unop(op: UnOp, lit: &Literal) -> Result<Literal, String> {
    match op {
        UnOp::Negate => match *lit { // -
            TInt(i) => Ok(TInt(-i)),
            TFloat(f) => Ok(TFloat(-f)),
            TStr(_) | TBool(_) | TNil => Err(unary_err(op, lit)),
        },
        UnOp::LNot => match *lit { // ! / not
            TInt(_) | TFloat(_) | TStr(_) => Ok(TBool(false)),  // all these evaluate to true
            TBool(b) => Ok(TBool(!b)),
            TNil => Err(unary_err(op, lit)),
        },
        UnOp::BNot => match *lit { // ~
            TInt(i) => Ok(TInt(!i)),
            TFloat(_) | TStr(_) | TBool(_) | TNil => Err(unary_err(op, lit)),
        },
        UnOp::Len => match *lit { // #
            TInt(_) | TFloat(_) | TBool(_) | TNil => Err(unary_err(op, lit)),

            // # of graphemes is the way to go
            TStr(ref s) => Ok(TInt(s.as_slice().graphemes(true).count() as i64)),
        },
    }
}

/// `fold_unop` for binary operators
fn fold_binop(lhs: &Literal, op: BinOp, rhs: &Literal) -> Result<Literal, String> {
    match op {
        BinOp::Add => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TInt(i + j)),
            (&TInt(i), &TFloat(j)) => Ok(TFloat(i as f64 + j)),
            (&TFloat(i), &TInt(j)) => Ok(TFloat(i + j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TFloat(i + j)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Sub => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TInt(i - j)),
            (&TInt(i), &TFloat(j)) => Ok(TFloat(i as f64 - j)),
            (&TFloat(i), &TInt(j)) => Ok(TFloat(i - j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TFloat(i - j)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Mul => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TInt(i * j)),
            (&TInt(i), &TFloat(j)) => Ok(TFloat(i as f64 * j)),
            (&TFloat(i), &TInt(j)) => Ok(TFloat(i * j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TFloat(i * j)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Div => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TInt(i / j)),
            (&TInt(i), &TFloat(j)) => Ok(TFloat(i as f64 / j)),
            (&TFloat(i), &TInt(j)) => Ok(TFloat(i / j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TFloat(i / j)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Mod => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TInt(i % j)),
            (&TInt(i), &TFloat(j)) => Ok(TFloat(i as f64 % j)),
            (&TFloat(i), &TInt(j)) => Ok(TFloat(i % j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TFloat(i % j)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Pow => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => {
                if j > u32::max_value() as i64 {
                    Err(format!("exponent {} is out of range", j))
                } else {
                    Ok(TInt(i.pow(j as u32)))
                }
            },
            (&TInt(i), &TFloat(j)) => {
                Ok(TFloat((i as f64).powf(j)))
            },
            (&TFloat(i), &TInt(j)) => {
                if j > i32::max_value() as i64 {
                    Err(format!("exponent {} is out of range", j))
                } else {
                    Ok(TFloat(i.powi(j as i32)))
                }
            },
            (&TFloat(i), &TFloat(j)) => {
                Ok(TFloat(i.powf(j)))
            },
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Concat => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TStr(format!("{}{}", i, j))),
            (&TInt(i), &TFloat(j)) => Ok(TStr(format!("{}{}", i, j))),
            (&TFloat(i), &TInt(j)) => Ok(TStr(format!("{}{}", i, j))),
            (&TFloat(i), &TFloat(j)) => Ok(TStr(format!("{}{}", i, j))),
            (&TStr(ref s), &TInt(i)) => Ok(TStr(format!("{}{}", s, i))),
            (&TInt(i), &TStr(ref s)) => Ok(TStr(format!("{}{}", i, s))),
            (&TStr(ref s), &TFloat(f)) => Ok(TStr(format!("{}{}", s, f))),
            (&TFloat(f), &TStr(ref s)) => Ok(TStr(format!("{}{}", f, s))),
            (&TStr(ref a), &TStr(ref b)) => Ok(TStr(format!("{}{}", a, b))),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Eq | BinOp::NEq | BinOp::NEqLua => {
            let res = match (lhs, rhs) {
                (&TInt(i), &TInt(j)) => i == j,
                (&TInt(i), &TFloat(j)) => i as f64 == j,
                (&TFloat(i), &TInt(j)) => i == j as f64,
                (&TFloat(i), &TFloat(j)) => i == j,
                (&TBool(i), &TBool(j)) => i == j,
                (&TStr(ref a), &TStr(ref b)) => a == b,
                (&TNil, &TNil) => true,
                _ => false,
            };
            if op == BinOp::Eq { Ok(TBool(res)) } else { Ok(TBool(!res)) }
        },
        BinOp::LEq => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TBool(i <= j)),
            (&TInt(i), &TFloat(j)) => Ok(TBool(i as f64 <= j)),
            (&TFloat(i), &TInt(j)) => Ok(TBool(i <= j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TBool(i <= j)),
            (&TStr(ref a), &TStr(ref b)) => Ok(TBool(a <= b)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::GEq => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TBool(i >= j)),
            (&TInt(i), &TFloat(j)) => Ok(TBool(i as f64 >= j)),
            (&TFloat(i), &TInt(j)) => Ok(TBool(i >= j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TBool(i >= j)),
            (&TStr(ref a), &TStr(ref b)) => Ok(TBool(a >= b)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Less => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TBool(i < j)),
            (&TInt(i), &TFloat(j)) => Ok(TBool((i as f64) < j)),
            (&TFloat(i), &TInt(j)) => Ok(TBool(i < j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TBool(i < j)),
            (&TStr(ref a), &TStr(ref b)) => Ok(TBool(a < b)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::Greater => match (lhs, rhs) {
            (&TInt(i), &TInt(j)) => Ok(TBool(i > j)),
            (&TInt(i), &TFloat(j)) => Ok(TBool(i as f64 > j)),
            (&TFloat(i), &TInt(j)) => Ok(TBool(i > j as f64)),
            (&TFloat(i), &TFloat(j)) => Ok(TBool(i > j)),
            (&TStr(ref a), &TStr(ref b)) => Ok(TBool(a > b)),
            _ => Err(bin_err(lhs, op, rhs)),
        },
        BinOp::LAnd | BinOp::LAndLua => {
            if fold_truth(lhs) {
                Ok(rhs.clone())
            } else {
                Ok(lhs.clone())
            }
        },
        BinOp::LOr | BinOp::LOrLua => {
            if fold_truth(lhs) {
                Ok(lhs.clone())
            } else {
                Ok(rhs.clone())
            }
        },
        _ => Err(bin_err(lhs, op, rhs)),
    }
}

impl Visitor for Folder {
    fn visit_expr(&mut self, mut e: Expr) -> Expr {
        e.value = match e.value {
            EBinOp(mut lhs, op, mut rhs) => {
                // TODO fold these too
                lhs = Box::new(self.visit_expr(*lhs));
                rhs = Box::new(self.visit_expr(*rhs));

                let lspan = lhs.span;
                let rspan = rhs.span;
                if let ELit(lit_lhs) = lhs.value {
                    if let ELit(lit_rhs) = rhs.value {
                        match fold_binop(&lit_lhs, op, &lit_rhs) {
                            Ok(newlit) => ELit(newlit),
                            Err(msg) => {
                                self.warns.push(Warning::new(e.span, msg));
                                EBinOp(Box::new(Spanned::new(lspan, ELit(lit_lhs))), op, Box::new(Spanned::new(rspan, ELit(lit_rhs))))
                            }
                        }
                    } else {
                        EBinOp(Box::new(Spanned::new(lspan, ELit(lit_lhs))), op, rhs)
                    }
                } else {
                    EBinOp(lhs, op, rhs)
                }
            },
            EUnOp(op, mut arg) => {
                arg = Box::new(self.visit_expr(*arg));

                let span = arg.span;
                if let ELit(lit) = arg.value {
                    match fold_unop(op, &lit) {
                        Ok(newlit) => ELit(newlit),
                        Err(msg) => {
                            self.warns.push(Warning::new(e.span, msg));
                            EUnOp(op, Box::new(Spanned::new(span, ELit(lit))))
                        }
                    }
                } else {
                    EUnOp(op, arg)
                }
            },
            _ => { return walk_expr(e, self) },
        };

        e
    }
}

pub fn run(mut main: Function) -> (Function, Vec<Warning>) {
    let mut v = Folder {
        warns: vec![],
    };

    main = walk_func(main, &mut v);
    (main, v.warns)
}

#[cfg(test)]
mod tests {
    use super::*;
    use compiler::*;

    /// Parses and folds `raw`, then parses `folded`. Asserts that the ASTs are equal.
    fn test(raw: &str, folded: &str) {
        let mut conf = CompileConfig::empty();
        conf.add_transform(run, LintMode::Warn);

        let main = parse_and_resolve(raw).unwrap();
        let (main, _warns) = apply_transforms(main, &conf).unwrap();
        let expected = parse_and_resolve(folded).unwrap();

        assert_eq!(main, expected);
    }

    #[test]
    fn basic() {
        test("return -0, -4.5, #\"TEST\"", "return 0, -4.5, 4");
        test("return 1-1+3*(1-1)/1^1+1", "return 1");
    }
}
<|endoftext|>


<commit_before>fn is_permutation(string_a: &str, string_b: &str, prefix: String) -> bool {
    let len = string_a.len();

    if string_b == string_a || string_b == prefix {
        return true;
    }

    if len == 0 {
        println!("prefix len 0 {}", prefix);
    } else {
        for i in 0..len {
            let char_at = string_a.chars().nth(i).unwrap();

            let rem = string_a[0..i].to_string() + &string_a[i + 1..len];

            let result = is_permutation(&rem, string_b, prefix.to_string() + &char_at.to_string());
            if result == true {
                return result;
            }
        }
    }

    return false;
}

#[test]
fn a_is_permutation_of_a() {
    assert!(is_permutation("a", "a", "".to_string()));
}

#[test]
fn ab_is_permutation_of_ba() {
    assert!(is_permutation("ab", "ba", "".to_string()));
}

#[test]
fn abcd_is_permutation_of_bacd() {
    assert!(is_permutation("abcd", "bacd", "".to_string()));
}

#[test]
fn abcdefg_is_permutation_of_gfedcba() {
    assert!(is_permutation("abcdefg", "gfedcba", "".to_string()));
}

#[test]
fn aabb_is_permutation_of_baba() {
    assert!(is_permutation("aabb", "baba", "".to_string()));
}
<commit_msg>Add helpful comment on why .chars().nth() is there<commit_after>fn is_permutation(string_a: &str, string_b: &str, prefix: String) -> bool {
    let len = string_a.len();

    if string_b == string_a || string_b == prefix {
        return true;
    }

    if len == 0 {
        println!("prefix len 0 {}", prefix);
    } else {
        for i in 0..len {
            // Even tough .chars builds a list from the string,
            // .nth on it idiomatic Rust. As of 04/13, char_at
            // https://doc.rust-lang.org/std/string/struct.String.html#method.char_at
            // is unstable
            let char_at = string_a.chars().nth(i).unwrap();

            let rem = string_a[0..i].to_string() + &string_a[i + 1..len];

            let result = is_permutation(&rem, string_b, prefix.to_string() + &char_at.to_string());
            if result == true {
                return result;
            }
        }
    }

    return false;
}

#[test]
fn a_is_permutation_of_a() {
    assert!(is_permutation("a", "a", "".to_string()));
}

#[test]
fn ab_is_permutation_of_ba() {
    assert!(is_permutation("ab", "ba", "".to_string()));
}

#[test]
fn abcd_is_permutation_of_bacd() {
    assert!(is_permutation("abcd", "bacd", "".to_string()));
}

#[test]
fn abcdefg_is_permutation_of_gfedcba() {
    assert!(is_permutation("abcdefg", "gfedcba", "".to_string()));
}

#[test]
fn aabb_is_permutation_of_baba() {
    assert!(is_permutation("aabb", "baba", "".to_string()));
}
<|endoftext|>