<commit_before>use std;

#[derive(Debug,Clone,PartialEq)]
pub enum Token {
  // Structure
  EOF,
  Enter,
  Exit,
  Space,
  Newline,
  Comment(String),

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  StrLit(String),
  Name(String),

  // Keywords
  Break,
  Continue,
  Else,
  For,
  Func,
  If,
  In,
  Return,
  While,

  // Symbols
  Arr, // ->
  Ass, // =
  Col, // :
  Com, // ,
  Dot, // .
  Meta,// ::
  Semi,// ;

  // Braces
  Cul, // {
  Cur, // }
  Pal, // (
  Par, // )
  Sql, // [
  Sqr, // ]

  // Operators
  Add, // +
  And, // &
  Car, // ^
  Div, // /
  Dol, // $
  Mul, // *
  Neg, // ~
  Not, // !
  Or,  // |
  Pct, // %
  Sub, // -

  // Comparisons
  Eql, // ==
  Ge,  // >=
  Gt,  // >
  Le,  // <=
  Lt,  // <
  Ne,  // !=
}

use self::Token::*;

fn lex_number(it: &mut std::iter::Peekable<std::str::Chars>) -> Token {
  let mut digits = String::new();
  while let Some(&c) = it.peek() {
    match c {
      '0'...'9' | '.' => {
        it.next();
        digits.push(c);
      }
      _ => {break}
    }
  }

  match digits.contains(".") {
    true => Float(digits.parse::<f64>().unwrap()),
    false => Int(digits.parse::<i64>().unwrap())
  }
}

fn lex_name(it: &mut std::iter::Peekable<std::str::Chars>) -> Token {
  let mut name = String::new();
  name.push(it.next().unwrap());

  while let Some(&c) = it.peek() {
    match c {
      'a'...'z' | 'A'...'Z' | '0'...'9' | '_' => {
        it.next();
        name.push(c);
      }
      _ => {break}
    }
  }

  match name.as_str() {
    "true" => Bool(true),
    "false" => Bool(false),
    "break" => Break,
    "continue" => Continue,
    "else" => Else,
    "for" => For,
    "func" => Func,
    "if" => If,
    "in" => In,
    "return" => Return,
    "while" => While,
    _ => Name(name)
  }
}

fn lex_comment(it: &mut std::iter::Peekable<std::str::Chars>) -> Token {
  let mut comment = String::new();
  it.next();

  while let Some(&c) = it.peek() {
    match c {
      '\n' => {break}
      _ => {
        it.next();
        comment.push(c);
      }
    }
  }

  println!("Comment: {:?}", comment);
  Comment(comment)
}

fn lex_indent(it: &mut std::iter::Peekable<std::str::Chars>) -> u64 {
  let mut indent: u64 = 0;
  it.next();

  while let Some(&c) = it.peek() {
    match c {
      ' ' => {
        it.next();
        indent += 1;
      }
      _ => {break}
    }
  }

  indent
}

fn lex_pair(next: char, solo: Token, pair: Token, it: &mut std::iter::Peekable<std::str::Chars>) -> Token {
  it.next();

  if let Some(&c) = it.peek() {
    if c == next {
      it.next();
      return pair;
    }
  }

  // is this right? if peek() returns a None, we just return `solo`?
  // seems right. None should be the EOF, meaning `solo` is the last token
  solo
}

pub fn lex(input: &str) -> Vec<Token> {
  let mut tokens: Vec<Token> = Vec::new();
  let mut it = input.chars().peekable();

  while let Some(&c) = it.peek() {
    let x = match c {
      '#' => lex_comment(&mut it),
      'a'...'z' | 'A'...'Z' | '_' => lex_name(&mut it),
      '0'...'9' => lex_number(&mut it),
      '\n' => {
        lex_indent(&mut it);
        Newline
      }

      // Compound
      '-' => lex_pair('>', Sub, Arr, &mut it),
      '<' => lex_pair('=', Lt, Le, &mut it),
      '>' => lex_pair('=', Gt, Ge, &mut it),
      '=' => lex_pair('=', Ass, Eql, &mut it),
      '!' => lex_pair('=', Not, Ne, &mut it),
      ':' => lex_pair(':', Col, Meta, &mut it),

      // Symbols
      // -> Arr
      // = Ass
      // : Col
      ',' => {it.next(); Com}
      '.' => {it.next(); Dot}
      // :: Meta
      ';' => {it.next(); Semi}

      // Braces
      '(' => {it.next(); Pal}
      ')' => {it.next(); Par}
      '[' => {it.next(); Sql}
      ']' => {it.next(); Sqr}
      '{' => {it.next(); Cul}
      '}' => {it.next(); Cur}

      // Operators
      '+' => {it.next(); Add}
      '&' => {it.next(); And}
      '^' => {it.next(); Car}
      '/' => {it.next(); Div}
      '$' => {it.next(); Dol}
      '*' => {it.next(); Mul}
      '~' => {it.next(); Neg}
      // ! Not
      '|' => {it.next(); Or}
      '%' => {it.next(); Pct}
      // - Sub

      _ => {it.next(); Space}
    };

    // don't emit tokens for spaces or comments
    match x {
      Space => (),
      Comment(_) => (),
      _ => tokens.push(x),
    }
  }

  tokens.push(Newline);
  tokens.push(EOF);

  tokens
}
<commit_msg>lexer: Add Enumeration to the iter for code locs<commit_after>use std;

#[derive(Debug, Clone, PartialEq)]
pub enum Token {
  // Structure
  EOF,
  Enter,
  Exit,
  Space,
  Newline,
  Comment(String),

  // Literals
  Null,
  Bool(bool),
  Float(f64),
  Int(i64),
  StrLit(String),
  Name(String),

  // Keywords
  Break,
  Continue,
  Else,
  For,
  Func,
  If,
  In,
  Return,
  While,

  // Symbols
  Arr, // ->
  Ass, // =
  Col, // :
  Com, // ,
  Dot, // .
  Meta,// ::
  Semi,// ;

  // Braces
  Cul, // {
  Cur, // }
  Pal, // (
  Par, // )
  Sql, // [
  Sqr, // ]

  // Operators
  Add, // +
  And, // &
  Car, // ^
  Div, // /
  Dol, // $
  Mul, // *
  Neg, // ~
  Not, // !
  Or,  // |
  Pct, // %
  Sub, // -

  // Comparisons
  Eql, // ==
  Ge,  // >=
  Gt,  // >
  Le,  // <=
  Lt,  // <
  Ne,  // !=
}

use self::Token::*;

type LexIter<'a> = std::iter::Peekable<std::iter::Enumerate<std::str::Chars<'a>>>;

fn lex_number(it: &mut LexIter) -> Token {
  let mut digits = String::new();
  while let Some(&(i, c)) = it.peek() {
    match c {
      '0'...'9' | '.' => {
        it.next();
        digits.push(c);
      }
      _ => {break}
    }
  }

  match digits.contains(".") {
    true => Float(digits.parse::<f64>().unwrap()),
    false => Int(digits.parse::<i64>().unwrap())
  }
}

fn lex_name(it: &mut LexIter) -> Token {
  let mut name = String::new();
  name.push(it.next().unwrap().1);

  while let Some(&(i, c)) = it.peek() {
    match c {
      'a'...'z' | 'A'...'Z' | '0'...'9' | '_' => {
        it.next();
        name.push(c);
      }
      _ => {break}
    }
  }

  match name.as_str() {
    "true" => Bool(true),
    "false" => Bool(false),
    "break" => Break,
    "continue" => Continue,
    "else" => Else,
    "for" => For,
    "func" => Func,
    "if" => If,
    "in" => In,
    "return" => Return,
    "while" => While,
    _ => Name(name)
  }
}

fn lex_comment(it: &mut LexIter) -> Token {
  let mut comment = String::new();
  it.next();

  while let Some(&(i, c)) = it.peek() {
    match c {
      '\n' => {break}
      _ => {
        it.next();
        comment.push(c);
      }
    }
  }

  println!("Comment: {:?}", comment);
  Comment(comment)
}

fn lex_indent(it: &mut LexIter) -> u64 {
  let mut indent: u64 = 0;
  it.next();

  while let Some(&(i, c)) = it.peek() {
    match c {
      ' ' => {
        it.next();
        indent += 1;
      }
      _ => {break}
    }
  }

  indent
}

fn lex_pair(next: char, solo: Token, pair: Token, it: &mut LexIter) -> Token {
  it.next();

  if let Some(&(i, c)) = it.peek() {
    if c == next {
      it.next();
      return pair;
    }
  }

  // is this right? if peek() returns a None, we just return `solo`?
  // seems right. None should be the EOF, meaning `solo` is the last token
  solo
}

pub fn lex(input: &str) -> Vec<Token> {
  let mut tokens: Vec<Token> = Vec::new();
  let mut it: LexIter = input.chars().enumerate().peekable();

  while let Some(&(i, c)) = it.peek() {
    let start_i = i;
    let x = match c {
      '#' => lex_comment(&mut it),
      'a'...'z' | 'A'...'Z' | '_' => lex_name(&mut it),
      '0'...'9' => lex_number(&mut it),
      '\n' => {
        lex_indent(&mut it);
        Newline
      }

      // Compound
      '-' => lex_pair('>', Sub, Arr, &mut it),
      '<' => lex_pair('=', Lt, Le, &mut it),
      '>' => lex_pair('=', Gt, Ge, &mut it),
      '=' => lex_pair('=', Ass, Eql, &mut it),
      '!' => lex_pair('=', Not, Ne, &mut it),
      ':' => lex_pair(':', Col, Meta, &mut it),

      // Symbols
      // -> Arr
      // = Ass
      // : Col
      ',' => {it.next(); Com}
      '.' => {it.next(); Dot}
      // :: Meta
      ';' => {it.next(); Semi}

      // Braces
      '(' => {it.next(); Pal}
      ')' => {it.next(); Par}
      '[' => {it.next(); Sql}
      ']' => {it.next(); Sqr}
      '{' => {it.next(); Cul}
      '}' => {it.next(); Cur}

      // Operators
      '+' => {it.next(); Add}
      '&' => {it.next(); And}
      '^' => {it.next(); Car}
      '/' => {it.next(); Div}
      '$' => {it.next(); Dol}
      '*' => {it.next(); Mul}
      '~' => {it.next(); Neg}
      // ! Not
      '|' => {it.next(); Or}
      '%' => {it.next(); Pct}
      // - Sub

      _ => {it.next(); Space}
    };

    // don't emit tokens for spaces or comments
    match x {
      Space => (),
      Comment(_) => (),
      _ => tokens.push(x),
    }

    let mut end_i = 0;
    if let Some(&(j, _)) = it.peek() {
      end_i = j;
      println!("tokenized from {:?} to {:?}", start_i, end_i);
    }
    else {
      println!("tokenized from {:?} to end", start_i);
    }
  }

  tokens.push(Newline);
  tokens.push(EOF);

  tokens
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Letter_frequency

extern crate collections;

use std::io::fs::File;
use std::io::BufferedReader;
use std::os;

#[cfg(not(test))]
fn main() {
    let filename = match os::args().len() {
        1 => fail!("You must enter a filename to read line by line"),
        _ => os::args()[1]
    };

    let file = File::open(&Path::new(filename));
    let mut reader = BufferedReader::new(file);

    let mut s : collections::HashMap<char,uint> = collections::HashMap::new();

    for c in reader.chars() {
        let letter = c.unwrap();
        let counter = match s.contains_key(&letter) {
            true => s.get(&letter) + 1,
            false => 1,
        };
        s.insert(letter, counter);
    }

    println!("{}", s);
}
<commit_msg>Added tests for letter frequency<commit_after>// Implements http://rosettacode.org/wiki/Letter_frequency

extern crate collections;

#[cfg(not(test))]
use std::io::fs::File;
#[cfg(not(test))]
use std::io::BufferedReader;
use collections::HashMap;

fn count_chars<T: Iterator<char>>(mut chars: T) -> HashMap<char, uint> {
    let mut map: collections::HashMap<char, uint> = collections::HashMap::new();
    for letter in chars {
        map.insert_or_update_with(letter, 1, |_, count| *count += 1);
    }
    map
}

#[cfg(not(test))]
fn main() {
    let file = File::open(&Path::new("resources/unixdict.txt"));
    let mut reader = BufferedReader::new(file);

    println!("{}", count_chars(reader.chars().map(|c| c.unwrap())));
}

#[test]
fn test_empty() {
    let map = count_chars("".chars());
    assert!(map.len() == 0);
}

#[test]
fn test_basic() {
    let map = count_chars("aaaabbbbc".chars());

    assert!(map.len() == 3);
    assert!(*map.get(&'a') == 4);
    assert!(*map.get(&'b') == 4);
    assert!(*map.get(&'c') == 1);
}
<|endoftext|>


<commit_before>extern crate libc;

use {KeyboardControllable, Key, MouseControllable, MouseButton};

use self::libc::{c_ulong, c_int, c_char, c_void};
use std::borrow::Cow;
use std::ffi::CString;
use std::ptr;

const CURRENT_WINDOW: c_int = 0;
type Window  = c_int;
type Xdo     = *const c_void;

#[link(name = "xdo")]
extern "C" {
    fn xdo_free(xdo: Xdo);
    fn xdo_new(display: *const c_char) -> Xdo;

    fn xdo_click_window(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_down(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_up(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_move_mouse(xdo: Xdo, x: c_int, y: c_int, screen: c_int) -> c_int;
    fn xdo_move_mouse_relative(xdo: Xdo, x: c_int, y: c_int) -> c_int;

    fn xdo_enter_text_window(xdo: Xdo, window: Window, string: *const c_char, delay: c_ulong);
    fn xdo_send_keysequence_window(xdo: Xdo, window: Window, string: *const c_char, delay: c_ulong);
    fn xdo_send_keysequence_window_down(xdo: Xdo, window: Window, string: *const c_char, delay: c_ulong);
    fn xdo_send_keysequence_window_up(xdo: Xdo, window: Window, string: *const c_char, delay: c_ulong);
}

fn mousebutton(button: MouseButton) -> i32 {
    match button {
        MouseButton::Left => 1,
        MouseButton::Middle => 2,
        MouseButton::Right => 3,
        MouseButton::ScrollUp => 4,
        MouseButton::ScrollDown => 5,
        MouseButton::ScrollLeft => 6,
        MouseButton::ScrollRight => 7
    }
}

/// The main struct for handling the event emitting
pub struct Enigo {
    xdo: Xdo
}
impl Enigo {
    /// Create a new Enigo instance
    pub fn new() -> Enigo {
        Enigo {
            xdo: unsafe { xdo_new(ptr::null()) }
        }
    }
}
impl Drop for Enigo {
    fn drop(&mut self) {
        unsafe {
            xdo_free(self.xdo);
        }
    }
}
impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse(self.xdo, x, y, 0);
        }
    }
    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse_relative(self.xdo, x, y);
        }
    }
    fn mouse_down(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_down(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_up(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_up(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_click(&mut self, button: MouseButton) {
        unsafe {
            xdo_click_window(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_scroll_x(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollLeft;
        } else {
            button = MouseButton::ScrollRight;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
    fn mouse_scroll_y(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollUp;
        } else {
            button = MouseButton::ScrollDown;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
}
fn keysequence<'a>(key: Key) -> Cow<'a, str> {
    if let Key::Layout(c) = key {
        return Cow::from(c.to_string());
    }
    Cow::from(match key {
        Key::Alt => "Alt",
        Key::Backspace => "Backspace",
        Key::CapsLock => "CapsLock",
        Key::Command => "Command",
        Key::Control => "Control",
        Key::DownArrow => "DownArrow",
        Key::Escape => "Escape",
        Key::F1 => "F1",
        Key::F2 => "F2",
        Key::F3 => "F3",
        Key::F4 => "F4",
        Key::F5 => "F5",
        Key::F6 => "F6",
        Key::F7 => "F7",
        Key::F8 => "F8",
        Key::F9 => "F9",
        Key::F10 => "F10",
        Key::F11 => "F11",
        Key::F12 => "F12",
        Key::Home => "Home",
        Key::Layout(_) => unreachable!(),
        Key::LeftArrow => "Left",
        Key::Option => "Option",
        Key::PageDown => "PageDown",
        Key::PageUp => "PageUp",
        Key::Raw(_) => unimplemented!(),
        Key::Return => "Return",
        Key::RightArrow => "Right",
        Key::Shift => "Shift",
        Key::Space => "Space",
        Key::Super => "Super",
        Key::Tab => "Tab",
        Key::UpArrow => "Up",
        Key::Windows => "Windows"
    })
}
impl KeyboardControllable for Enigo {
    fn key_sequence(&mut self, sequence: &str) {
        let string = CString::new(sequence).unwrap();
        unsafe {
            xdo_enter_text_window(self.xdo, CURRENT_WINDOW, string.as_ptr(), 12000);
        }
    }
    fn key_down(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_down(self.xdo, CURRENT_WINDOW, string.as_ptr(), 12000);
        }
    }
    fn key_up(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_up(self.xdo, CURRENT_WINDOW, string.as_ptr(), 12000);
        }
    }
    fn key_click(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window(self.xdo, CURRENT_WINDOW, string.as_ptr(), 12000);
        }
    }
}
<commit_msg>Get rid of sleep<commit_after>extern crate libc;

use {KeyboardControllable, Key, MouseControllable, MouseButton};

use self::libc::{c_ulong, c_int, c_char, c_void};
use std::borrow::Cow;
use std::ffi::CString;
use std::ptr;

const CURRENT_WINDOW: c_int = 0;
type Window  = c_int;
type Xdo     = *const c_void;

#[link(name = "xdo")]
extern "C" {
    fn xdo_free(xdo: Xdo);
    fn xdo_new(display: *const c_char) -> Xdo;

    fn xdo_click_window(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_down(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_up(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_move_mouse(xdo: Xdo, x: c_int, y: c_int, screen: c_int) -> c_int;
    fn xdo_move_mouse_relative(xdo: Xdo, x: c_int, y: c_int) -> c_int;

    fn xdo_enter_text_window(xdo: Xdo, window: Window, string: *const c_char, delay: c_ulong);
    fn xdo_send_keysequence_window(xdo: Xdo, window: Window, string: *const c_char, delay: c_ulong);
    fn xdo_send_keysequence_window_down(xdo: Xdo, window: Window, string: *const c_char, delay: c_ulong);
    fn xdo_send_keysequence_window_up(xdo: Xdo, window: Window, string: *const c_char, delay: c_ulong);
}

fn mousebutton(button: MouseButton) -> i32 {
    match button {
        MouseButton::Left => 1,
        MouseButton::Middle => 2,
        MouseButton::Right => 3,
        MouseButton::ScrollUp => 4,
        MouseButton::ScrollDown => 5,
        MouseButton::ScrollLeft => 6,
        MouseButton::ScrollRight => 7
    }
}

/// The main struct for handling the event emitting
pub struct Enigo {
    xdo: Xdo
}
impl Enigo {
    /// Create a new Enigo instance
    pub fn new() -> Enigo {
        Enigo {
            xdo: unsafe { xdo_new(ptr::null()) }
        }
    }
}
impl Drop for Enigo {
    fn drop(&mut self) {
        unsafe {
            xdo_free(self.xdo);
        }
    }
}
impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse(self.xdo, x, y, 0);
        }
    }
    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse_relative(self.xdo, x, y);
        }
    }
    fn mouse_down(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_down(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_up(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_up(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_click(&mut self, button: MouseButton) {
        unsafe {
            xdo_click_window(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_scroll_x(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollLeft;
        } else {
            button = MouseButton::ScrollRight;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
    fn mouse_scroll_y(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollUp;
        } else {
            button = MouseButton::ScrollDown;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
}
fn keysequence<'a>(key: Key) -> Cow<'a, str> {
    if let Key::Layout(c) = key {
        return Cow::from(c.to_string());
    }
    Cow::from(match key {
        Key::Alt => "Alt",
        Key::Backspace => "Backspace",
        Key::CapsLock => "CapsLock",
        Key::Command => "Command",
        Key::Control => "Control",
        Key::DownArrow => "DownArrow",
        Key::Escape => "Escape",
        Key::F1 => "F1",
        Key::F2 => "F2",
        Key::F3 => "F3",
        Key::F4 => "F4",
        Key::F5 => "F5",
        Key::F6 => "F6",
        Key::F7 => "F7",
        Key::F8 => "F8",
        Key::F9 => "F9",
        Key::F10 => "F10",
        Key::F11 => "F11",
        Key::F12 => "F12",
        Key::Home => "Home",
        Key::Layout(_) => unreachable!(),
        Key::LeftArrow => "Left",
        Key::Option => "Option",
        Key::PageDown => "PageDown",
        Key::PageUp => "PageUp",
        Key::Raw(_) => unimplemented!(),
        Key::Return => "Return",
        Key::RightArrow => "Right",
        Key::Shift => "Shift",
        Key::Space => "Space",
        Key::Super => "Super",
        Key::Tab => "Tab",
        Key::UpArrow => "Up",
        Key::Windows => "Windows"
    })
}
impl KeyboardControllable for Enigo {
    fn key_sequence(&mut self, sequence: &str) {
        let string = CString::new(sequence).unwrap();
        unsafe {
            xdo_enter_text_window(self.xdo, CURRENT_WINDOW, string.as_ptr(), 0);
        }
    }
    fn key_down(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_down(self.xdo, CURRENT_WINDOW, string.as_ptr(), 0);
        }
    }
    fn key_up(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_up(self.xdo, CURRENT_WINDOW, string.as_ptr(), 0);
        }
    }
    fn key_click(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window(self.xdo, CURRENT_WINDOW, string.as_ptr(), 0);
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(not(target_os = "linux"))]
use std::io::ErrorKind;
use std::io::{self, Error};

/// An active AX.25 network interface, e.g. "ax0"
pub struct NetDev {
    pub name: String,
    pub ifindex: i32,
}

/// An open socket for sending and receiving AX.25 frames
pub struct Ax25RawSocket {
    #[cfg(target_os = "linux")]
    fd: i32,
}

impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_new()
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(ErrorKind::NotFound, "only supported on linux"))
        }
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_close(self)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(ErrorKind::NotFound, "only supported on linux"))
        }
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_list_ax25_interfaces(self)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Ok(Vec::new())
        }
    }

    /// Send a frame to a particular interface, specified by its index
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_send_frame(self, frame, ifindex)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(
                ErrorKind::NotConnected,
                "only supported on linux",
            ))
        }
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_receive_frame(self)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(
                ErrorKind::NotConnected,
                "only supported on linux",
            ))
        }
    }
}

/// Keeps all the linux interface-specific code in one place
#[cfg(target_os = "linux")]
mod sys {
    use super::*;
    use libc::{
        c_char, c_int, c_ulong, c_void, close, recvfrom, sendto, sockaddr_ll, socket, socklen_t,
        AF_AX25, AF_PACKET, SOCK_RAW,
    };
    use std::fs::File;
    use std::io::{BufRead, BufReader};
    use std::mem;

    const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
    const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
    const SIOCGIFINDEX: c_ulong = 0x8933;

    pub fn socket_new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket { fd }),
        }
    }

    pub fn socket_close(socket: &mut Ax25RawSocket) -> io::Result<()> {
        match unsafe { close(socket.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    pub fn socket_list_ax25_interfaces(socket: &Ax25RawSocket) -> io::Result<Vec<NetDev>> {
        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2) {
            if let Ok(line) = l {
                let device_name = line.trim().split(':').next().unwrap();
                if let Some(net_dev) = get_ax25_netdev(&device_name, socket.fd) {
                    devices.push(net_dev);
                }
            }
        }
        Ok(devices)
    }

    pub fn socket_send_frame(socket: &Ax25RawSocket, frame: &[u8], ifindex: i32) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8],
        };

        match unsafe {
            let sa_ptr = &sa as *const libc::sockaddr_ll as *const libc::sockaddr;
            sendto(
                socket.fd,
                prefixed_frame.as_ptr() as *const c_void,
                prefixed_frame.len(),
                0,
                sa_ptr,
                mem::size_of_val(&sa) as socklen_t,
            )
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    pub fn socket_receive_frame(socket: &Ax25RawSocket) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        // Not sure we need the address but it might come in handy someday
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let len: usize;
        unsafe {
            let sa_ptr = &mut addr_struct as *mut libc::sockaddr_ll as *mut libc::sockaddr;
            let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
            len = match recvfrom(
                socket.fd,
                buf.as_mut_ptr() as *mut c_void,
                buf.len(),
                0,
                sa_ptr,
                &mut sa_in_sz,
            ) {
                -1 => return Err(Error::last_os_error()),
                len => len as usize,
            };
        }
        let valid_buf = &buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf.iter().skip_while(|&c| *c == 0).cloned().collect();
        Ok(filtered)
    }

    fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
        let mut req = ifreq::default();
        let if_name = name.to_owned();
        for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
            *d = *s as c_char;
        }

        if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
            return None;
        }
        if req.data.address_family() as i32 != AF_AX25 {
            return None;
        }
        let hw_addr = match req.data.ax25_address() {
            Some(addr) => addr,
            None => return None,
        };

        if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
            return None;
        }
        let ifindex = req.data.ifindex();

        Some(NetDev {
            name: hw_addr,
            ifindex,
        })
    }

    extern "C" {
        fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
    }

    #[repr(C)]
    struct ifreq {
        ifr_name: [c_char; 16],
        data: ifreq_union,
    }

    impl Default for ifreq {
        fn default() -> ifreq {
            ifreq {
                ifr_name: [0; 16],
                data: ifreq_union::default(),
            }
        }
    }

    #[repr(C)]
    struct ifreq_union {
        data: [u8; 24],
    }

    impl Default for ifreq_union {
        fn default() -> ifreq_union {
            ifreq_union { data: [0; 24] }
        }
    }

    impl ifreq_union {
        fn ifindex(&self) -> c_int {
            c_int::from_be(
                ((self.data[0] as c_int) << 24)
                    + ((self.data[1] as c_int) << 16)
                    + ((self.data[2] as c_int) << 8)
                    + (self.data[3] as c_int),
            )
        }

        fn address_family(&self) -> u16 {
            u16::from_be(((self.data[0] as u16) << 8) + (self.data[1] as u16))
        }

        fn ax25_address(&self) -> Option<String> {
            let mut addr_utf8: Vec<u8> = self.data[2..8]
                .iter()
                .rev()
                .map(|&c| c >> 1)
                .skip_while(|&c| c == 0)
                .collect::<Vec<u8>>();
            addr_utf8.reverse();
            let ssid = (self.data[8] >> 1) & 0x0f;
            if let Ok(addr) = String::from_utf8(addr_utf8) {
                return Some(format!("{}-{}", addr, ssid));
            }
            None
        }
    }
}
<commit_msg>Suppress unused variables warning for non-linux platforms<commit_after>#[cfg(not(target_os = "linux"))]
use std::io::ErrorKind;
use std::io::{self, Error};

/// An active AX.25 network interface, e.g. "ax0"
pub struct NetDev {
    pub name: String,
    pub ifindex: i32,
}

/// An open socket for sending and receiving AX.25 frames
pub struct Ax25RawSocket {
    #[cfg(target_os = "linux")]
    fd: i32,
}

impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_new()
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(ErrorKind::NotFound, "only supported on linux"))
        }
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_close(self)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(ErrorKind::NotFound, "only supported on linux"))
        }
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_list_ax25_interfaces(self)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Ok(Vec::new())
        }
    }

    /// Send a frame to a particular interface, specified by its index
    #[allow(unused_variables)]
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_send_frame(self, frame, ifindex)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(
                ErrorKind::NotConnected,
                "only supported on linux",
            ))
        }
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        #[cfg(target_os = "linux")]
        {
            sys::socket_receive_frame(self)
        }
        #[cfg(not(target_os = "linux"))]
        {
            Err(Error::new(
                ErrorKind::NotConnected,
                "only supported on linux",
            ))
        }
    }
}

/// Keeps all the linux interface-specific code in one place
#[cfg(target_os = "linux")]
mod sys {
    use super::*;
    use libc::{
        c_char, c_int, c_ulong, c_void, close, recvfrom, sendto, sockaddr_ll, socket, socklen_t,
        AF_AX25, AF_PACKET, SOCK_RAW,
    };
    use std::fs::File;
    use std::io::{BufRead, BufReader};
    use std::mem;

    const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
    const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
    const SIOCGIFINDEX: c_ulong = 0x8933;

    pub fn socket_new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket { fd }),
        }
    }

    pub fn socket_close(socket: &mut Ax25RawSocket) -> io::Result<()> {
        match unsafe { close(socket.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    pub fn socket_list_ax25_interfaces(socket: &Ax25RawSocket) -> io::Result<Vec<NetDev>> {
        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2) {
            if let Ok(line) = l {
                let device_name = line.trim().split(':').next().unwrap();
                if let Some(net_dev) = get_ax25_netdev(&device_name, socket.fd) {
                    devices.push(net_dev);
                }
            }
        }
        Ok(devices)
    }

    pub fn socket_send_frame(socket: &Ax25RawSocket, frame: &[u8], ifindex: i32) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8],
        };

        match unsafe {
            let sa_ptr = &sa as *const libc::sockaddr_ll as *const libc::sockaddr;
            sendto(
                socket.fd,
                prefixed_frame.as_ptr() as *const c_void,
                prefixed_frame.len(),
                0,
                sa_ptr,
                mem::size_of_val(&sa) as socklen_t,
            )
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    pub fn socket_receive_frame(socket: &Ax25RawSocket) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        // Not sure we need the address but it might come in handy someday
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let len: usize;
        unsafe {
            let sa_ptr = &mut addr_struct as *mut libc::sockaddr_ll as *mut libc::sockaddr;
            let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
            len = match recvfrom(
                socket.fd,
                buf.as_mut_ptr() as *mut c_void,
                buf.len(),
                0,
                sa_ptr,
                &mut sa_in_sz,
            ) {
                -1 => return Err(Error::last_os_error()),
                len => len as usize,
            };
        }
        let valid_buf = &buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf.iter().skip_while(|&c| *c == 0).cloned().collect();
        Ok(filtered)
    }

    fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
        let mut req = ifreq::default();
        let if_name = name.to_owned();
        for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
            *d = *s as c_char;
        }

        if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
            return None;
        }
        if req.data.address_family() as i32 != AF_AX25 {
            return None;
        }
        let hw_addr = match req.data.ax25_address() {
            Some(addr) => addr,
            None => return None,
        };

        if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
            return None;
        }
        let ifindex = req.data.ifindex();

        Some(NetDev {
            name: hw_addr,
            ifindex,
        })
    }

    extern "C" {
        fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
    }

    #[repr(C)]
    struct ifreq {
        ifr_name: [c_char; 16],
        data: ifreq_union,
    }

    impl Default for ifreq {
        fn default() -> ifreq {
            ifreq {
                ifr_name: [0; 16],
                data: ifreq_union::default(),
            }
        }
    }

    #[repr(C)]
    struct ifreq_union {
        data: [u8; 24],
    }

    impl Default for ifreq_union {
        fn default() -> ifreq_union {
            ifreq_union { data: [0; 24] }
        }
    }

    impl ifreq_union {
        fn ifindex(&self) -> c_int {
            c_int::from_be(
                ((self.data[0] as c_int) << 24)
                    + ((self.data[1] as c_int) << 16)
                    + ((self.data[2] as c_int) << 8)
                    + (self.data[3] as c_int),
            )
        }

        fn address_family(&self) -> u16 {
            u16::from_be(((self.data[0] as u16) << 8) + (self.data[1] as u16))
        }

        fn ax25_address(&self) -> Option<String> {
            let mut addr_utf8: Vec<u8> = self.data[2..8]
                .iter()
                .rev()
                .map(|&c| c >> 1)
                .skip_while(|&c| c == 0)
                .collect::<Vec<u8>>();
            addr_utf8.reverse();
            let ssid = (self.data[8] >> 1) & 0x0f;
            if let Ok(addr) = String::from_utf8(addr_utf8) {
                return Some(format!("{}-{}", addr, ssid));
            }
            None
        }
    }
}
<|endoftext|>


<commit_before>// Last updated for Tock 1.4.
// See https://github.com/tock/tock/blob/master/doc/syscalls/memop.md
use crate::syscalls;
use core::slice;

/// Set the memory break
/// # Safety
/// Setting the break is marked as unsafe as it should only be called by the entry point to setup
/// the allocator. Updating the break afterwards can lead to allocated memory becoming unaccessible.
///
/// Alternate allocator implementations may still find this useful in the future.
pub unsafe fn set_brk(ptr: *const u8) -> bool {
    syscalls::raw::memop(0, ptr as usize) == 0
}

/// Increment the memory break
pub fn increment_brk(increment: usize) -> Option<*const u8> {
    let result = unsafe { syscalls::raw::memop(1, increment) };
    if result >= 0 {
        Some(result as *const u8)
    } else {
        None
    }
}

pub fn get_brk() -> *const u8 {
    unsafe { syscalls::raw::memop(1, 0) as *const u8 }
}

pub fn get_mem_start() -> *const u8 {
    unsafe { syscalls::raw::memop(2, 0) as *const u8 }
}

pub fn get_mem_end() -> *const u8 {
    unsafe { syscalls::raw::memop(3, 0) as *const u8 }
}

pub fn get_flash_start() -> *const u8 {
    unsafe { syscalls::raw::memop(4, 0) as *const u8 }
}

pub fn get_flash_end() -> *const u8 {
    unsafe { syscalls::raw::memop(5, 0) as *const u8 }
}

pub fn get_grant_start() -> *const u8 {
    unsafe { syscalls::raw::memop(6, 0) as *const u8 }
}

pub fn get_flash_regions_count() -> usize {
    unsafe { syscalls::raw::memop(7, 0) as usize }
}

pub fn get_flash_region_start(i: usize) -> Option<*const u8> {
    if i < get_flash_regions_count() {
        Some(unsafe { syscalls::raw::memop(8, i) as *const u8 })
    } else {
        None
    }
}

pub fn get_flash_region_end(i: usize) -> Option<*const u8> {
    if i < get_flash_regions_count() {
        Some(unsafe { syscalls::raw::memop(9, i) as *const u8 })
    } else {
        None
    }
}

/// It is safe to return a 'static immutable slice, as the Tock kernel doesn't change the layout of
/// flash regions during the application's lifetime.
pub fn get_flash_region(i: usize) -> Option<&'static [u8]> {
    if i < get_flash_regions_count() {
        let start_addr = unsafe { syscalls::raw::memop(8, i) } as usize;
        let start_ptr = start_addr as *const u8;
        let end_addr = unsafe { syscalls::raw::memop(9, i) } as usize;
        // This assumes that the kernel sends consistent results, i.e. start <= end.
        let len = end_addr - start_addr + 1;
        Some(unsafe { slice::from_raw_parts(start_ptr, len) })
    } else {
        None
    }
}

/// Set the top of the stack
/// # Safety
/// Setting the stack_top and heap_start addresses are marked as unsafe as they should only be called
/// by the entry point to setup the allocator. Updating these values afterwards can lead to incorrect
/// debug output from the kernel.
///
/// Alternate allocator implementations may still find this useful in the future.
pub unsafe fn set_stack_top(ptr: *const u8) {
    let _ = syscalls::raw::memop(10, ptr as usize);
}

/// Set the top of the heap
/// # Safety
/// Setting the stack_top and heap_start addresses are marked as unsafe as they should only be called
/// by the entry point to setup the allocator. Updating these values afterwards can lead to incorrect
/// debug output from the kernel.
pub unsafe fn set_heap_start(ptr: *const u8) {
    let _ = syscalls::raw::memop(11, ptr as usize);
}
<commit_msg>Fix off by one error<commit_after>// Last updated for Tock 1.4.
// See https://github.com/tock/tock/blob/master/doc/syscalls/memop.md
use crate::syscalls;
use core::slice;

/// Set the memory break
/// # Safety
/// Setting the break is marked as unsafe as it should only be called by the entry point to setup
/// the allocator. Updating the break afterwards can lead to allocated memory becoming unaccessible.
///
/// Alternate allocator implementations may still find this useful in the future.
pub unsafe fn set_brk(ptr: *const u8) -> bool {
    syscalls::raw::memop(0, ptr as usize) == 0
}

/// Increment the memory break
pub fn increment_brk(increment: usize) -> Option<*const u8> {
    let result = unsafe { syscalls::raw::memop(1, increment) };
    if result >= 0 {
        Some(result as *const u8)
    } else {
        None
    }
}

pub fn get_brk() -> *const u8 {
    unsafe { syscalls::raw::memop(1, 0) as *const u8 }
}

pub fn get_mem_start() -> *const u8 {
    unsafe { syscalls::raw::memop(2, 0) as *const u8 }
}

pub fn get_mem_end() -> *const u8 {
    unsafe { syscalls::raw::memop(3, 0) as *const u8 }
}

pub fn get_flash_start() -> *const u8 {
    unsafe { syscalls::raw::memop(4, 0) as *const u8 }
}

pub fn get_flash_end() -> *const u8 {
    unsafe { syscalls::raw::memop(5, 0) as *const u8 }
}

pub fn get_grant_start() -> *const u8 {
    unsafe { syscalls::raw::memop(6, 0) as *const u8 }
}

pub fn get_flash_regions_count() -> usize {
    unsafe { syscalls::raw::memop(7, 0) as usize }
}

pub fn get_flash_region_start(i: usize) -> Option<*const u8> {
    if i < get_flash_regions_count() {
        Some(unsafe { syscalls::raw::memop(8, i) as *const u8 })
    } else {
        None
    }
}

pub fn get_flash_region_end(i: usize) -> Option<*const u8> {
    if i < get_flash_regions_count() {
        Some(unsafe { syscalls::raw::memop(9, i) as *const u8 })
    } else {
        None
    }
}

/// It is safe to return a 'static immutable slice, as the Tock kernel doesn't change the layout of
/// flash regions during the application's lifetime.
pub fn get_flash_region(i: usize) -> Option<&'static [u8]> {
    if i < get_flash_regions_count() {
        let start_addr = unsafe { syscalls::raw::memop(8, i) } as usize;
        let start_ptr = start_addr as *const u8;
        let end_addr = unsafe { syscalls::raw::memop(9, i) } as usize;
        // This assumes that the kernel sends consistent results, i.e. start <= end.
        let len = end_addr - start_addr;
        Some(unsafe { slice::from_raw_parts(start_ptr, len) })
    } else {
        None
    }
}

/// Set the top of the stack
/// # Safety
/// Setting the stack_top and heap_start addresses are marked as unsafe as they should only be called
/// by the entry point to setup the allocator. Updating these values afterwards can lead to incorrect
/// debug output from the kernel.
///
/// Alternate allocator implementations may still find this useful in the future.
pub unsafe fn set_stack_top(ptr: *const u8) {
    let _ = syscalls::raw::memop(10, ptr as usize);
}

/// Set the top of the heap
/// # Safety
/// Setting the stack_top and heap_start addresses are marked as unsafe as they should only be called
/// by the entry point to setup the allocator. Updating these values afterwards can lead to incorrect
/// debug output from the kernel.
pub unsafe fn set_heap_start(ptr: *const u8) {
    let _ = syscalls::raw::memop(11, ptr as usize);
}
<|endoftext|>


<commit_before>#![crate_name = "uu_mv"]

// This file is part of the uutils coreutils package.
//
// (c) Orvar Segerström <orvarsegerstrom@gmail.com>
// (c) Sokovikov Evgeniy  <skv-headless@yandex.ru>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
//

extern crate getopts;

#[macro_use]
extern crate uucore;

use std::fs;
use std::env;
use std::io::{BufRead, BufReader, Result, stdin, Write};
use std::path::{Path, PathBuf};

static NAME: &'static str = "mv";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub struct Behaviour {
    overwrite: OverwriteMode,
    backup: BackupMode,
    suffix: String,
    update: bool,
    target_dir: Option<String>,
    no_target_dir: bool,
    verbose: bool,
}

#[derive(Clone, Eq, PartialEq)]
pub enum OverwriteMode {
    NoClobber,
    Interactive,
    Force,
}

#[derive(Clone, Copy, Eq, PartialEq)]
pub enum BackupMode {
    NoBackup,
    SimpleBackup,
    NumberedBackup,
    ExistingBackup,
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optflagopt("",
                    "backup",
                    "make a backup of each existing destination file",
                    "CONTROL");
    opts.optflag("b", "", "like --backup but does not accept an argument");
    opts.optflag("f", "force", "do not prompt before overwriting");
    opts.optflag("i", "interactive", "prompt before override");
    opts.optflag("n", "no-clobber", "do not overwrite an existing file");
    opts.optflag("",
                 "strip-trailing-slashes",
                 "remove any trailing slashes from each SOURCE\n \
                                                 argument");
    opts.optopt("S", "suffix", "override the usual backup suffix", "SUFFIX");
    opts.optopt("t",
                "target-directory",
                "move all SOURCE arguments into DIRECTORY",
                "DIRECTORY");
    opts.optflag("T", "no-target-directory", "treat DEST as a normal file");
    opts.optflag("u",
                 "update",
                 "move only when the SOURCE file is newer\n \
                                than the destination file or when the\n \
                                destination file is missing");
    opts.optflag("v", "verbose", "explain what is being done");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            show_error!("Invalid options\n{}", f);
            return 1;
        }
    };
    let usage = opts.usage("Move SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.");

    // This does not exactly match the GNU implementation:
    // The GNU mv defaults to Force, but if more than one of the
    // overwrite options are supplied, only the last takes effect.
    // To default to no-clobber in that situation seems safer:
    //
    let overwrite_mode = if matches.opt_present("no-clobber") {
        OverwriteMode::NoClobber
    } else if matches.opt_present("interactive") {
        OverwriteMode::Interactive
    } else {
        OverwriteMode::Force
    };

    let backup_mode = if matches.opt_present("b") {
        BackupMode::SimpleBackup
    } else if matches.opt_present("backup") {
        match matches.opt_str("backup") {
            None => BackupMode::SimpleBackup,
            Some(mode) => {
                match &mode[..] {
                    "simple" | "never" => BackupMode::SimpleBackup,
                    "numbered" | "t" => BackupMode::NumberedBackup,
                    "existing" | "nil" => BackupMode::ExistingBackup,
                    "none" | "off" => BackupMode::NoBackup,
                    x => {
                        show_error!("invalid argument ‘{}’ for ‘backup type’\n\
                                Try '{} --help' for more information.",
                                    x,
                                    NAME);
                        return 1;
                    }
                }
            }
        }
    } else {
        BackupMode::NoBackup
    };

    if overwrite_mode == OverwriteMode::NoClobber && backup_mode != BackupMode::NoBackup {
        show_error!("options --backup and --no-clobber are mutually exclusive\n\
                    Try '{} --help' for more information.",
                    NAME);
        return 1;
    }

    let backup_suffix = if matches.opt_present("suffix") {
        match matches.opt_str("suffix") {
            Some(x) => x,
            None => {
                show_error!("option '--suffix' requires an argument\n\
                            Try '{} --help' for more information.",
                            NAME);
                return 1;
            }
        }
    } else {
        if let (Ok(s), BackupMode::SimpleBackup) = (env::var("SIMPLE_BACKUP_SUFFIX"), backup_mode) {
            s
        } else {
            "~".to_owned()
        }
    };

    if matches.opt_present("T") && matches.opt_present("t") {
        show_error!("cannot combine --target-directory (-t) and --no-target-directory (-T)");
        return 1;
    }

    let behaviour = Behaviour {
        overwrite: overwrite_mode,
        backup: backup_mode,
        suffix: backup_suffix,
        update: matches.opt_present("u"),
        target_dir: matches.opt_str("t"),
        no_target_dir: matches.opt_present("T"),
        verbose: matches.opt_present("v"),
    };

    let paths: Vec<PathBuf> = {
        fn strip_slashes<'a>(p: &'a Path) -> &'a Path {
            p.components().as_path()
        }
        let to_owned = |p: &Path| p.to_owned();
        let arguments = matches.free.iter().map(Path::new);
        if matches.opt_present("strip-trailing-slashes") {
            arguments.map(strip_slashes).map(to_owned).collect()
        } else {
            arguments.map(to_owned).collect()
        }
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        0
    } else if matches.opt_present("help") {
        help(&usage);
        0
    } else {
        exec(&paths[..], behaviour)
    }
}

fn help(usage: &str) {
    println!("{0} {1}\n\n\
    Usage: {0} SOURCE DEST\n   \
       or: {0} SOURCE... DIRECTORY\n\n\
    {2}",
             NAME,
             VERSION,
             usage);
}

fn exec(files: &[PathBuf], b: Behaviour) -> i32 {
    if let Some(ref name) = b.target_dir {
        return move_files_into_dir(files, &PathBuf::from(name), &b);
    }
    match files.len() {
        0 | 1 => {
            show_error!("missing file operand\n\
                        Try '{} --help' for more information.",
                        NAME);
            return 1;
        }
        2 => {
            let source = &files[0];
            let target = &files[1];
            if !source.exists() {
                show_error!("cannot stat ‘{}’: No such file or directory",
                            source.display());
                return 1;
            }

            if target.is_dir() {
                if b.no_target_dir {
                    if !source.is_dir() {
                        show_error!("cannot overwrite directory ‘{}’ with non-directory",
                                    target.display());
                        return 1;
                    }

                    return match rename(source, target, &b) {
                        Err(e) => {
                            show_error!("{}", e);
                            1
                        }
                        _ => 0,
                    };
                }

                return move_files_into_dir(&[source.clone()], target, &b);
            }

            if let Err(e) = rename(source, target, &b) {
                show_error!("{}", e);
                return 1;
            }
        }
        _ => {
            if b.no_target_dir {
                show_error!("mv: extra operand ‘{}’\n\
                            Try '{} --help' for more information.",
                            files[2].display(),
                            NAME);
                return 1;
            }
            let target_dir = files.last().unwrap();
            move_files_into_dir(&files[..files.len() - 1], target_dir, &b);
        }
    }
    0
}

fn move_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behaviour) -> i32 {
    if !target_dir.is_dir() {
        show_error!("target ‘{}’ is not a directory", target_dir.display());
        return 1;
    }

    let mut all_successful = true;
    for sourcepath in files.iter() {
        let targetpath = match sourcepath.as_os_str().to_str() {
            Some(name) => target_dir.join(name),
            None => {
                show_error!("cannot stat ‘{}’: No such file or directory",
                            sourcepath.display());

                all_successful = false;
                continue;
            }
        };

        if let Err(e) = rename(sourcepath, &targetpath, b) {
            show_error!("mv: cannot move ‘{}’ to ‘{}’: {}",
                        sourcepath.display(),
                        targetpath.display(),
                        e);
            all_successful = false;
        }
    }
    if all_successful {
        0
    } else {
        1
    }
}

fn rename(from: &PathBuf, to: &PathBuf, b: &Behaviour) -> Result<()> {
    let mut backup_path = None;

    if to.exists() {
        match b.overwrite {
            OverwriteMode::NoClobber => return Ok(()),
            OverwriteMode::Interactive => {
                print!("{}: overwrite ‘{}’? ", NAME, to.display());
                if !read_yes() {
                    return Ok(());
                }
            }
            OverwriteMode::Force => {}
        };

        backup_path = match b.backup {
            BackupMode::NoBackup => None,
            BackupMode::SimpleBackup => Some(simple_backup_path(to, &b.suffix)),
            BackupMode::NumberedBackup => Some(numbered_backup_path(to)),
            BackupMode::ExistingBackup => Some(existing_backup_path(to, &b.suffix)),
        };
        if let Some(ref p) = backup_path {
            try!(fs::rename(to, p));
        }

        if b.update {
            if try!(try!(fs::metadata(from)).modified()) <= try!(try!(fs::metadata(to)).modified()) {
                return Ok(());
            }
        }
    }

    try!(fs::rename(from, to));

    if b.verbose {
        print!("‘{}’ -> ‘{}’", from.display(), to.display());
        match backup_path {
            Some(path) => println!(" (backup: ‘{}’)", path.display()),
            None => println!(""),
        }
    }
    Ok(())
}

fn read_yes() -> bool {
    let mut s = String::new();
    match BufReader::new(stdin()).read_line(&mut s) {
        Ok(_) => {
            match s.chars().nth(0) {
                Some(x) => x == 'y' || x == 'Y',
                _ => false,
            }
        }
        _ => false,
    }
}

fn simple_backup_path(path: &PathBuf, suffix: &str) -> PathBuf {
    let mut p = path.to_string_lossy().into_owned();
    p.push_str(suffix);
    PathBuf::from(p)
}

fn numbered_backup_path(path: &PathBuf) -> PathBuf {
    (1_u64..)
        .map(|i| path.with_extension(format!("~{}~", i)))
        .skip_while(|p| p.exists())
        .next()
        .expect("cannot create backup")
}

fn existing_backup_path(path: &PathBuf, suffix: &str) -> PathBuf {
    let test_path = path.with_extension("~1~");
    if test_path.exists() {
        numbered_backup_path(path)
    } else {
        simple_backup_path(path, suffix)
    }
}
<commit_msg>mv: split up uumain<commit_after>#![crate_name = "uu_mv"]

// This file is part of the uutils coreutils package.
//
// (c) Orvar Segerström <orvarsegerstrom@gmail.com>
// (c) Sokovikov Evgeniy  <skv-headless@yandex.ru>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
//

extern crate getopts;

#[macro_use]
extern crate uucore;

use std::fs;
use std::env;
use std::io::{BufRead, BufReader, Result, stdin, Write};
use std::path::{Path, PathBuf};

static NAME: &'static str = "mv";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub struct Behaviour {
    overwrite: OverwriteMode,
    backup: BackupMode,
    suffix: String,
    update: bool,
    target_dir: Option<String>,
    no_target_dir: bool,
    verbose: bool,
}

#[derive(Clone, Eq, PartialEq)]
pub enum OverwriteMode {
    NoClobber,
    Interactive,
    Force,
}

#[derive(Clone, Copy, Eq, PartialEq)]
pub enum BackupMode {
    NoBackup,
    SimpleBackup,
    NumberedBackup,
    ExistingBackup,
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut opts = getopts::Options::new();

    opts.optflagopt("",
                    "backup",
                    "make a backup of each existing destination file",
                    "CONTROL");
    opts.optflag("b", "", "like --backup but does not accept an argument");
    opts.optflag("f", "force", "do not prompt before overwriting");
    opts.optflag("i", "interactive", "prompt before override");
    opts.optflag("n", "no-clobber", "do not overwrite an existing file");
    opts.optflag("",
                 "strip-trailing-slashes",
                 "remove any trailing slashes from each SOURCE\n \
                                                 argument");
    opts.optopt("S", "suffix", "override the usual backup suffix", "SUFFIX");
    opts.optopt("t",
                "target-directory",
                "move all SOURCE arguments into DIRECTORY",
                "DIRECTORY");
    opts.optflag("T", "no-target-directory", "treat DEST as a normal file");
    opts.optflag("u",
                 "update",
                 "move only when the SOURCE file is newer\n \
                                than the destination file or when the\n \
                                destination file is missing");
    opts.optflag("v", "verbose", "explain what is being done");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            show_error!("Invalid options\n{}", f);
            return 1;
        }
    };
    let usage = opts.usage("Move SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.");

    let overwrite_mode = determine_overwrite_mode(&matches);
    let backup_mode = determine_backup_mode(&matches);

    if overwrite_mode == OverwriteMode::NoClobber && backup_mode != BackupMode::NoBackup {
        show_error!("options --backup and --no-clobber are mutually exclusive\n\
                    Try '{} --help' for more information.",
                    NAME);
        return 1;
    }

    let backup_suffix = determine_backup_suffix(backup_mode, &matches);

    if matches.opt_present("T") && matches.opt_present("t") {
        show_error!("cannot combine --target-directory (-t) and --no-target-directory (-T)");
        return 1;
    }

    let behaviour = Behaviour {
        overwrite: overwrite_mode,
        backup: backup_mode,
        suffix: backup_suffix,
        update: matches.opt_present("u"),
        target_dir: matches.opt_str("t"),
        no_target_dir: matches.opt_present("T"),
        verbose: matches.opt_present("v"),
    };

    let paths: Vec<PathBuf> = {
        fn strip_slashes<'a>(p: &'a Path) -> &'a Path {
            p.components().as_path()
        }
        let to_owned = |p: &Path| p.to_owned();
        let arguments = matches.free.iter().map(Path::new);
        if matches.opt_present("strip-trailing-slashes") {
            arguments.map(strip_slashes).map(to_owned).collect()
        } else {
            arguments.map(to_owned).collect()
        }
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        0
    } else if matches.opt_present("help") {
        help(&usage);
        0
    } else {
        exec(&paths[..], behaviour)
    }
}

fn determine_overwrite_mode(matches: &getopts::Matches) -> OverwriteMode {
    // This does not exactly match the GNU implementation:
    // The GNU mv defaults to Force, but if more than one of the
    // overwrite options are supplied, only the last takes effect.
    // To default to no-clobber in that situation seems safer:
    //
    if matches.opt_present("no-clobber") {
        OverwriteMode::NoClobber
    } else if matches.opt_present("interactive") {
        OverwriteMode::Interactive
    } else {
        OverwriteMode::Force
    }
}

fn determine_backup_mode(matches: &getopts::Matches) -> BackupMode {
    if matches.opt_present("b") {
        BackupMode::SimpleBackup
    } else if matches.opt_present("backup") {
        match matches.opt_str("backup") {
            None => BackupMode::SimpleBackup,
            Some(mode) => {
                match &mode[..] {
                    "simple" | "never" => BackupMode::SimpleBackup,
                    "numbered" | "t" => BackupMode::NumberedBackup,
                    "existing" | "nil" => BackupMode::ExistingBackup,
                    "none" | "off" => BackupMode::NoBackup,
                    x => {
                        crash!(1, "invalid argument ‘{}’ for ‘backup type’\n\
                                Try '{} --help' for more information.",
                                    x,
                                    NAME);
                    }
                }
            }
        }
    } else {
        BackupMode::NoBackup
    }
}

fn determine_backup_suffix(backup_mode: BackupMode, matches: &getopts::Matches) -> String {
    if matches.opt_present("suffix") {
        match matches.opt_str("suffix") {
            Some(x) => x,
            None => {
                crash!(1, "option '--suffix' requires an argument\n\
                            Try '{} --help' for more information.",
                            NAME);
            }
        }
    } else {
        if let (Ok(s), BackupMode::SimpleBackup) = (env::var("SIMPLE_BACKUP_SUFFIX"), backup_mode) {
            s
        } else {
            "~".to_owned()
        }
    }
}

fn help(usage: &str) {
    println!("{0} {1}\n\n\
    Usage: {0} SOURCE DEST\n   \
       or: {0} SOURCE... DIRECTORY\n\n\
    {2}",
             NAME,
             VERSION,
             usage);
}

fn exec(files: &[PathBuf], b: Behaviour) -> i32 {
    if let Some(ref name) = b.target_dir {
        return move_files_into_dir(files, &PathBuf::from(name), &b);
    }
    match files.len() {
        0 | 1 => {
            show_error!("missing file operand\n\
                        Try '{} --help' for more information.",
                        NAME);
            return 1;
        }
        2 => {
            let source = &files[0];
            let target = &files[1];
            if !source.exists() {
                show_error!("cannot stat ‘{}’: No such file or directory",
                            source.display());
                return 1;
            }

            if target.is_dir() {
                if b.no_target_dir {
                    if !source.is_dir() {
                        show_error!("cannot overwrite directory ‘{}’ with non-directory",
                                    target.display());
                        return 1;
                    }

                    return match rename(source, target, &b) {
                        Err(e) => {
                            show_error!("{}", e);
                            1
                        }
                        _ => 0,
                    };
                }

                return move_files_into_dir(&[source.clone()], target, &b);
            }

            if let Err(e) = rename(source, target, &b) {
                show_error!("{}", e);
                return 1;
            }
        }
        _ => {
            if b.no_target_dir {
                show_error!("mv: extra operand ‘{}’\n\
                            Try '{} --help' for more information.",
                            files[2].display(),
                            NAME);
                return 1;
            }
            let target_dir = files.last().unwrap();
            move_files_into_dir(&files[..files.len() - 1], target_dir, &b);
        }
    }
    0
}

fn move_files_into_dir(files: &[PathBuf], target_dir: &PathBuf, b: &Behaviour) -> i32 {
    if !target_dir.is_dir() {
        show_error!("target ‘{}’ is not a directory", target_dir.display());
        return 1;
    }

    let mut all_successful = true;
    for sourcepath in files.iter() {
        let targetpath = match sourcepath.as_os_str().to_str() {
            Some(name) => target_dir.join(name),
            None => {
                show_error!("cannot stat ‘{}’: No such file or directory",
                            sourcepath.display());

                all_successful = false;
                continue;
            }
        };

        if let Err(e) = rename(sourcepath, &targetpath, b) {
            show_error!("mv: cannot move ‘{}’ to ‘{}’: {}",
                        sourcepath.display(),
                        targetpath.display(),
                        e);
            all_successful = false;
        }
    }
    if all_successful {
        0
    } else {
        1
    }
}

fn rename(from: &PathBuf, to: &PathBuf, b: &Behaviour) -> Result<()> {
    let mut backup_path = None;

    if to.exists() {
        match b.overwrite {
            OverwriteMode::NoClobber => return Ok(()),
            OverwriteMode::Interactive => {
                print!("{}: overwrite ‘{}’? ", NAME, to.display());
                if !read_yes() {
                    return Ok(());
                }
            }
            OverwriteMode::Force => {}
        };

        backup_path = match b.backup {
            BackupMode::NoBackup => None,
            BackupMode::SimpleBackup => Some(simple_backup_path(to, &b.suffix)),
            BackupMode::NumberedBackup => Some(numbered_backup_path(to)),
            BackupMode::ExistingBackup => Some(existing_backup_path(to, &b.suffix)),
        };
        if let Some(ref p) = backup_path {
            try!(fs::rename(to, p));
        }

        if b.update {
            if try!(try!(fs::metadata(from)).modified()) <= try!(try!(fs::metadata(to)).modified()) {
                return Ok(());
            }
        }
    }

    try!(fs::rename(from, to));

    if b.verbose {
        print!("‘{}’ -> ‘{}’", from.display(), to.display());
        match backup_path {
            Some(path) => println!(" (backup: ‘{}’)", path.display()),
            None => println!(""),
        }
    }
    Ok(())
}

fn read_yes() -> bool {
    let mut s = String::new();
    match BufReader::new(stdin()).read_line(&mut s) {
        Ok(_) => {
            match s.chars().nth(0) {
                Some(x) => x == 'y' || x == 'Y',
                _ => false,
            }
        }
        _ => false,
    }
}

fn simple_backup_path(path: &PathBuf, suffix: &str) -> PathBuf {
    let mut p = path.to_string_lossy().into_owned();
    p.push_str(suffix);
    PathBuf::from(p)
}

fn numbered_backup_path(path: &PathBuf) -> PathBuf {
    (1_u64..)
        .map(|i| path.with_extension(format!("~{}~", i)))
        .skip_while(|p| p.exists())
        .next()
        .expect("cannot create backup")
}

fn existing_backup_path(path: &PathBuf, suffix: &str) -> PathBuf {
    let test_path = path.with_extension("~1~");
    if test_path.exists() {
        numbered_backup_path(path)
    } else {
        simple_backup_path(path, suffix)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 Anatoly Ikorsky
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use crate::{
    connection_like::{ConnectionLike, ToConnection, ToConnectionResult},
    from_row,
    prelude::FromRow,
    queryable::stmt::StatementLike,
    BinaryProtocol, BoxFuture, Params, QueryResult, TextProtocol,
};

/// MySql text query.
///
/// This trait covers the set of `query*` methods on the `Queryable` trait.
/// Please see the corresponding section of the crate level docs for details.
///
/// Example:
///
/// ```rust
/// # use mysql_async::test_misc::get_opts;
/// # #[tokio::main]
/// # async fn main() -> mysql_async::Result<()> {
/// use mysql_async::*;
/// use mysql_async::prelude::*;
/// let pool = Pool::new(get_opts());
///
/// let num: Option<u32> = "SELECT 42".first(&pool).await?;
///
/// assert_eq!(num, Some(42));
/// # Ok(()) }
/// ```
pub trait TextQuery: Send + Sized {
    /// This methods corresponds to [`Queryable::query_iter`].
    fn run<'a, C>(self, conn: C) -> BoxFuture<'a, QueryResult<'a, TextProtocol>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a;

    /// This methods corresponds to [`Queryable::query_first`].
    fn first<'a, T, C>(self, conn: C) -> BoxFuture<'a, Option<T>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        T: FromRow + Send + 'static,
    {
        BoxFuture(Box::pin(async move {
            let mut result = self.run(conn).await?;
            let output = if result.is_empty() {
                None
            } else {
                result.get_row().await?.map(from_row)
            };
            result.drop_result().await?;
            Ok(output)
        }))
    }

    /// This methods corresponds to [`Queryable::query`].
    fn fetch<'a, T, C>(self, conn: C) -> BoxFuture<'a, Vec<T>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        T: FromRow + Send + 'static,
    {
        BoxFuture(Box::pin(async move {
            let result = self.run(conn).await?;
            result.collect_and_drop::<T>().await
        }))
    }

    /// This methods corresponds to [`Queryable::query_fold`].
    fn reduce<'a, T, U, F, C>(self, conn: C, init: U, next: F) -> BoxFuture<'a, U>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        F: FnMut(U, T) -> U + Send + 'a,
        T: FromRow + Send + 'static,
        U: Send + 'a,
    {
        BoxFuture(Box::pin(async move {
            let result = self.run(conn).await?;
            let output = result.reduce_and_drop(init, next).await?;
            Ok(output)
        }))
    }

    /// This methods corresponds to [`Queryable::query_map`].
    fn map<'a, T, U, F, C>(self, conn: C, mut map: F) -> BoxFuture<'a, Vec<U>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        F: FnMut(T) -> U + Send + 'a,
        T: FromRow + Send + 'static,
        U: Send + 'a,
    {
        BoxFuture(Box::pin(async move {
            let result = self
                .reduce(conn, Vec::new(), move |mut acc, row: T| {
                    acc.push(map(row));
                    acc
                })
                .await?;
            Ok(result)
        }))
    }
}

impl<Q: AsRef<str> + Send + Sync> TextQuery for Q {
    fn run<'a, C>(self, conn: C) -> BoxFuture<'a, QueryResult<'a, TextProtocol>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
    {
        BoxFuture(Box::pin(async move {
            let mut conn = match conn.to_connection() {
                ToConnectionResult::Immediate(conn) => conn,
                ToConnectionResult::Mediate(fut) => fut.await?,
            };
            conn.conn_mut().raw_query(self).await?;
            Ok(QueryResult::new(conn))
        }))
    }
}

/// Representaion of a prepared statement query.
///
/// See `BinQuery` for details.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QueryWithParams<Q, P> {
    pub query: Q,
    pub params: P,
}

/// Helper, that constructs [`QueryWithParams`].
pub trait WithParams: Sized {
    fn with<P>(&self, params: P) -> QueryWithParams<Self, P>;
}

impl<'a, T: StatementLike + ?Sized> WithParams for &'a T {
    fn with<P>(&self, params: P) -> QueryWithParams<Self, P> {
        QueryWithParams {
            query: self,
            params,
        }
    }
}

/// MySql prepared statement query.
///
/// This trait covers the set of `exec*` methods on the [`Queryable`] trait.
/// Please see the corresponding section of the crate level docs for details.
///
/// Example:
///
/// ```rust
/// # use mysql_async::test_misc::get_opts;
/// # #[tokio::main]
/// # async fn main() -> mysql_async::Result<()> {
/// use mysql_async::*;
/// use mysql_async::prelude::*;
///
/// let pool = Pool::new(get_opts());
///
/// let row: Option<(u32, String)> = "SELECT ?, ?".with((42_u8, "foo")).first(&pool).await?;
///
/// assert_eq!(row, Some((42, "foo".into())));
/// # Ok(()) }
/// ```
pub trait BinQuery: Send + Sized {
    /// This methods corresponds to [`Queryable::exec_iter`].
    fn run<'a, C>(self, conn: C) -> BoxFuture<'a, QueryResult<'a, BinaryProtocol>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a;

    /// This methods corresponds to [`Queryable::exec_first`].
    fn first<'a, T, C>(self, conn: C) -> BoxFuture<'a, Option<T>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        T: FromRow + Send + 'static,
    {
        BoxFuture(Box::pin(async move {
            let mut result = self.run(conn).await?;
            let output = if result.is_empty() {
                None
            } else {
                result.get_row().await?.map(from_row)
            };
            result.drop_result().await?;
            Ok(output)
        }))
    }

    /// This methods corresponds to [`Queryable::exec`].
    fn fetch<'a, T, C>(self, conn: C) -> BoxFuture<'a, Vec<T>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        T: FromRow + Send + 'static,
    {
        BoxFuture(Box::pin(async move {
            let result = self.run(conn).await?;
            result.collect_and_drop::<T>().await
        }))
    }

    /// This methods corresponds to [`Queryable::exec_fold`].
    fn reduce<'a, T, U, F, C>(self, conn: C, init: U, next: F) -> BoxFuture<'a, U>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        F: FnMut(U, T) -> U + Send + 'a,
        T: FromRow + Send + 'static,
        U: Send + 'a,
    {
        BoxFuture(Box::pin(async move {
            let result = self.run(conn).await?;
            let output = result.reduce_and_drop(init, next).await?;
            Ok(output)
        }))
    }

    /// This methods corresponds to [`Queryable::exec_map`].
    fn map<'a, T, U, F, C>(self, conn: C, mut map: F) -> BoxFuture<'a, Vec<U>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        T: FromRow + Send + 'static,
        F: FnMut(T) -> U + Send + 'a,
        U: Send + 'a,
    {
        BoxFuture(Box::pin(async move {
            let result = self
                .reduce(conn, Vec::new(), move |mut acc, row: T| {
                    acc.push(map(row));
                    acc
                })
                .await?;
            Ok(result)
        }))
    }
}

impl<Q, P> BinQuery for QueryWithParams<&'_ Q, P>
where
    Q: StatementLike + ?Sized,
    P: Into<Params> + Send,
{
    fn run<'a, C>(self, conn: C) -> BoxFuture<'a, QueryResult<'a, BinaryProtocol>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
    {
        BoxFuture(Box::pin(async move {
            let query = self.query;
            let params = self.params.into();

            let mut conn = match conn.to_connection() {
                ToConnectionResult::Immediate(conn) => conn,
                ToConnectionResult::Mediate(fut) => fut.await?,
            };

            let statement = conn.conn_mut().get_statement(query).await?;
            conn.conn_mut()
                .execute_statement(&statement, params)
                .await?;
            Ok(QueryResult::new(conn))
        }))
    }
}

/// Helper trait for batch statement execution.
///
/// This trait covers the [`Queryable::exec_batch`] method.
///
/// Example:
///
/// ```rust
/// # use mysql_async::test_misc::get_opts;
/// # #[tokio::main]
/// # async fn main() -> mysql_async::Result<()> {
/// use mysql_async::*;
/// use mysql_async::prelude::*;
///
/// let pool = Pool::new(get_opts());
///
/// // This will prepare `DO ?` and execute `DO 0`, `DO 1`, `DO 2` and so on.
/// "DO ?"
///     .with((0..10).map(|x| (x,)))
///     .batch(&pool)
///     .await?;
/// # Ok(()) }
/// ```
pub trait BatchQuery {
    fn batch<'a, C>(self, conn: C) -> BoxFuture<'a, ()>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a;
}

impl<Q, I, P> BatchQuery for QueryWithParams<&'_ Q, I>
where
    Q: StatementLike + ?Sized,
    I: IntoIterator<Item = P> + Send,
    I::IntoIter: Send,
    P: Into<Params> + Send,
{
    fn batch<'a, C>(self, conn: C) -> BoxFuture<'a, ()>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
    {
        BoxFuture(Box::pin(async move {
            let query = self.query;
            let params = self.params;

            let mut conn = match conn.to_connection() {
                ToConnectionResult::Immediate(conn) => conn,
                ToConnectionResult::Mediate(fut) => fut.await?,
            };

            let statement = conn.conn_mut().get_statement(query).await?;

            for params in params {
                conn.conn_mut()
                    .execute_statement(&statement, params)
                    .await?;
            }

            Ok(())
        }))
    }
}
<commit_msg>Add TextQuery::ignore and BinQuery::ignore<commit_after>// Copyright (c) 2020 Anatoly Ikorsky
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use crate::{
    connection_like::{ConnectionLike, ToConnection, ToConnectionResult},
    from_row,
    prelude::FromRow,
    queryable::stmt::StatementLike,
    BinaryProtocol, BoxFuture, Params, QueryResult, TextProtocol,
};

/// MySql text query.
///
/// This trait covers the set of `query*` methods on the `Queryable` trait.
/// Please see the corresponding section of the crate level docs for details.
///
/// Example:
///
/// ```rust
/// # use mysql_async::test_misc::get_opts;
/// # #[tokio::main]
/// # async fn main() -> mysql_async::Result<()> {
/// use mysql_async::*;
/// use mysql_async::prelude::*;
/// let pool = Pool::new(get_opts());
///
/// let num: Option<u32> = "SELECT 42".first(&pool).await?;
///
/// assert_eq!(num, Some(42));
/// # Ok(()) }
/// ```
pub trait TextQuery: Send + Sized {
    /// This methods corresponds to [`Queryable::query_iter`].
    fn run<'a, C>(self, conn: C) -> BoxFuture<'a, QueryResult<'a, TextProtocol>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a;

    /// This methods corresponds to [`Queryable::query_first`].
    fn first<'a, T, C>(self, conn: C) -> BoxFuture<'a, Option<T>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        T: FromRow + Send + 'static,
    {
        BoxFuture(Box::pin(async move {
            let mut result = self.run(conn).await?;
            let output = if result.is_empty() {
                None
            } else {
                result.get_row().await?.map(from_row)
            };
            result.drop_result().await?;
            Ok(output)
        }))
    }

    /// This methods corresponds to [`Queryable::query`].
    fn fetch<'a, T, C>(self, conn: C) -> BoxFuture<'a, Vec<T>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        T: FromRow + Send + 'static,
    {
        BoxFuture(Box::pin(async move {
            let result = self.run(conn).await?;
            result.collect_and_drop::<T>().await
        }))
    }

    /// This methods corresponds to [`Queryable::query_fold`].
    fn reduce<'a, T, U, F, C>(self, conn: C, init: U, next: F) -> BoxFuture<'a, U>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        F: FnMut(U, T) -> U + Send + 'a,
        T: FromRow + Send + 'static,
        U: Send + 'a,
    {
        BoxFuture(Box::pin(async move {
            let result = self.run(conn).await?;
            let output = result.reduce_and_drop(init, next).await?;
            Ok(output)
        }))
    }

    /// This methods corresponds to [`Queryable::query_map`].
    fn map<'a, T, U, F, C>(self, conn: C, mut map: F) -> BoxFuture<'a, Vec<U>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        F: FnMut(T) -> U + Send + 'a,
        T: FromRow + Send + 'static,
        U: Send + 'a,
    {
        BoxFuture(Box::pin(async move {
            let result = self
                .reduce(conn, Vec::new(), move |mut acc, row: T| {
                    acc.push(map(row));
                    acc
                })
                .await?;
            Ok(result)
        }))
    }

    /// This method corresponds to [`Queryable::query_drop`].
    fn ignore<'a, C>(self, conn: C) -> BoxFuture<'a, ()>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
    {
        BoxFuture(Box::pin(async move {
            let result = self.run(conn).await?;
            result.drop_result().await?;
            Ok(())
        }))
    }
}

impl<Q: AsRef<str> + Send + Sync> TextQuery for Q {
    fn run<'a, C>(self, conn: C) -> BoxFuture<'a, QueryResult<'a, TextProtocol>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
    {
        BoxFuture(Box::pin(async move {
            let mut conn = match conn.to_connection() {
                ToConnectionResult::Immediate(conn) => conn,
                ToConnectionResult::Mediate(fut) => fut.await?,
            };
            conn.conn_mut().raw_query(self).await?;
            Ok(QueryResult::new(conn))
        }))
    }
}

/// Representaion of a prepared statement query.
///
/// See `BinQuery` for details.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QueryWithParams<Q, P> {
    pub query: Q,
    pub params: P,
}

/// Helper, that constructs [`QueryWithParams`].
pub trait WithParams: Sized {
    fn with<P>(&self, params: P) -> QueryWithParams<Self, P>;
}

impl<'a, T: StatementLike + ?Sized> WithParams for &'a T {
    fn with<P>(&self, params: P) -> QueryWithParams<Self, P> {
        QueryWithParams {
            query: self,
            params,
        }
    }
}

/// MySql prepared statement query.
///
/// This trait covers the set of `exec*` methods on the [`Queryable`] trait.
/// Please see the corresponding section of the crate level docs for details.
///
/// Example:
///
/// ```rust
/// # use mysql_async::test_misc::get_opts;
/// # #[tokio::main]
/// # async fn main() -> mysql_async::Result<()> {
/// use mysql_async::*;
/// use mysql_async::prelude::*;
///
/// let pool = Pool::new(get_opts());
///
/// let row: Option<(u32, String)> = "SELECT ?, ?".with((42_u8, "foo")).first(&pool).await?;
///
/// assert_eq!(row, Some((42, "foo".into())));
/// # Ok(()) }
/// ```
pub trait BinQuery: Send + Sized {
    /// This methods corresponds to [`Queryable::exec_iter`].
    fn run<'a, C>(self, conn: C) -> BoxFuture<'a, QueryResult<'a, BinaryProtocol>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a;

    /// This methods corresponds to [`Queryable::exec_first`].
    fn first<'a, T, C>(self, conn: C) -> BoxFuture<'a, Option<T>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        T: FromRow + Send + 'static,
    {
        BoxFuture(Box::pin(async move {
            let mut result = self.run(conn).await?;
            let output = if result.is_empty() {
                None
            } else {
                result.get_row().await?.map(from_row)
            };
            result.drop_result().await?;
            Ok(output)
        }))
    }

    /// This methods corresponds to [`Queryable::exec`].
    fn fetch<'a, T, C>(self, conn: C) -> BoxFuture<'a, Vec<T>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        T: FromRow + Send + 'static,
    {
        BoxFuture(Box::pin(async move {
            let result = self.run(conn).await?;
            result.collect_and_drop::<T>().await
        }))
    }

    /// This methods corresponds to [`Queryable::exec_fold`].
    fn reduce<'a, T, U, F, C>(self, conn: C, init: U, next: F) -> BoxFuture<'a, U>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        F: FnMut(U, T) -> U + Send + 'a,
        T: FromRow + Send + 'static,
        U: Send + 'a,
    {
        BoxFuture(Box::pin(async move {
            let result = self.run(conn).await?;
            let output = result.reduce_and_drop(init, next).await?;
            Ok(output)
        }))
    }

    /// This methods corresponds to [`Queryable::exec_map`].
    fn map<'a, T, U, F, C>(self, conn: C, mut map: F) -> BoxFuture<'a, Vec<U>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
        T: FromRow + Send + 'static,
        F: FnMut(T) -> U + Send + 'a,
        U: Send + 'a,
    {
        BoxFuture(Box::pin(async move {
            let result = self
                .reduce(conn, Vec::new(), move |mut acc, row: T| {
                    acc.push(map(row));
                    acc
                })
                .await?;
            Ok(result)
        }))
    }

    /// This method corresponds to [`Queryable::exec_drop`].
    fn ignore<'a, C>(self, conn: C) -> BoxFuture<'a, ()>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
    {
        BoxFuture(Box::pin(async move {
            let result = self.run(conn).await?;
            result.drop_result().await?;
            Ok(())
        }))
    }
}

impl<Q, P> BinQuery for QueryWithParams<&'_ Q, P>
where
    Q: StatementLike + ?Sized,
    P: Into<Params> + Send,
{
    fn run<'a, C>(self, conn: C) -> BoxFuture<'a, QueryResult<'a, BinaryProtocol>>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
    {
        BoxFuture(Box::pin(async move {
            let query = self.query;
            let params = self.params.into();

            let mut conn = match conn.to_connection() {
                ToConnectionResult::Immediate(conn) => conn,
                ToConnectionResult::Mediate(fut) => fut.await?,
            };

            let statement = conn.conn_mut().get_statement(query).await?;
            conn.conn_mut()
                .execute_statement(&statement, params)
                .await?;
            Ok(QueryResult::new(conn))
        }))
    }
}

/// Helper trait for batch statement execution.
///
/// This trait covers the [`Queryable::exec_batch`] method.
///
/// Example:
///
/// ```rust
/// # use mysql_async::test_misc::get_opts;
/// # #[tokio::main]
/// # async fn main() -> mysql_async::Result<()> {
/// use mysql_async::*;
/// use mysql_async::prelude::*;
///
/// let pool = Pool::new(get_opts());
///
/// // This will prepare `DO ?` and execute `DO 0`, `DO 1`, `DO 2` and so on.
/// "DO ?"
///     .with((0..10).map(|x| (x,)))
///     .batch(&pool)
///     .await?;
/// # Ok(()) }
/// ```
pub trait BatchQuery {
    fn batch<'a, C>(self, conn: C) -> BoxFuture<'a, ()>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a;
}

impl<Q, I, P> BatchQuery for QueryWithParams<&'_ Q, I>
where
    Q: StatementLike + ?Sized,
    I: IntoIterator<Item = P> + Send,
    I::IntoIter: Send,
    P: Into<Params> + Send,
{
    fn batch<'a, C>(self, conn: C) -> BoxFuture<'a, ()>
    where
        Self: 'a,
        C: ToConnection<'a> + 'a,
    {
        BoxFuture(Box::pin(async move {
            let query = self.query;
            let params = self.params;

            let mut conn = match conn.to_connection() {
                ToConnectionResult::Immediate(conn) => conn,
                ToConnectionResult::Mediate(fut) => fut.await?,
            };

            let statement = conn.conn_mut().get_statement(query).await?;

            for params in params {
                conn.conn_mut()
                    .execute_statement(&statement, params)
                    .await?;
            }

            Ok(())
        }))
    }
}

#[cfg(test)]
mod tests {
    use crate::{prelude::*, test_misc::get_opts, *};

    #[tokio::test]
    async fn should_run_text_query() -> Result<()> {
        let query_static = "SELECT 1, 2 UNION ALL SELECT 3, 4; SELECT 5, 6;";
        let query_string = String::from(query_static);

        macro_rules! test {
            ($query:expr, $conn:expr) => {{
                let mut result = $query.run($conn).await?;
                let result1: Vec<(u8, u8)> = result.collect().await?;
                let result2: Vec<(u8, u8)> = result.collect().await?;
                assert_eq!(result1, vec![(1, 2), (3, 4)]);
                assert_eq!(result2, vec![(5, 6)]);

                $query.ignore($conn).await?;

                let result: Option<(u8, u8)> = $query.first($conn).await?;
                assert_eq!(result, Some((1, 2)));

                let result: Vec<(u8, u8)> = $query.fetch($conn).await?;
                assert_eq!(result, vec![(1, 2), (3, 4)]);

                let result = $query
                    .map($conn, |row: (u8, u8)| format!("{:?}", row))
                    .await?;
                assert_eq!(result, vec![String::from("(1, 2)"), String::from("(3, 4)")]);

                let result = $query
                    .reduce($conn, 0_u8, |acc, row: (u8, u8)| acc + row.0 + row.1)
                    .await?;
                assert_eq!(result, 10);
            }};
        }

        let mut conn = Conn::new(get_opts()).await?;
        test!(query_static, &mut conn);
        test!(query_string.as_str(), &mut conn);
        conn.disconnect().await?;

        let pool = Pool::new(get_opts());
        test!(query_static, &pool);
        test!(query_string.as_str(), &pool);
        pool.disconnect().await?;

        Ok(())
    }
}
<|endoftext|>