<commit_before>extern crate git2;

use prompt_buffer;
use prompt_buffer::{PromptLine, PromptBufferPlugin, PromptLineBuilder};
use git2::{Repository, Error, StatusOptions, STATUS_WT_NEW};
use std::{os, fmt};
use term::color;

enum StatusTypes {
    New,
    Modified,
    Deleted,
    Renamed,
    TypeChange,
    Untracked,
    Clean
}

impl fmt::Show for StatusTypes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            StatusTypes::Clean => " ",
            StatusTypes::Deleted => "D",
            StatusTypes::Modified => "M",
            StatusTypes::New => "A",
            StatusTypes::Renamed => "R",
            StatusTypes::TypeChange => "T",
            StatusTypes::Untracked => "?",
        })
    }
}

struct GitStatus {
    index: StatusTypes,
    workdir: StatusTypes
}

impl GitStatus {
    fn new(f: git2::Status) -> GitStatus {
        GitStatus {
            index:
                     if f.contains(git2::STATUS_INDEX_NEW) { StatusTypes::New }
                else if f.contains(git2::STATUS_INDEX_MODIFIED) { StatusTypes::Modified }
                else if f.contains(git2::STATUS_INDEX_DELETED) { StatusTypes::Deleted }
                else if f.contains(git2::STATUS_INDEX_RENAMED) { StatusTypes::Renamed }
                else if f.contains(git2::STATUS_INDEX_TYPECHANGE) { StatusTypes::TypeChange }
                else if f.contains(git2::STATUS_WT_NEW) { StatusTypes::Untracked }
                else { StatusTypes::Clean },
            workdir:
                     if f.contains(git2::STATUS_WT_NEW) { StatusTypes::Untracked }
                else if f.contains(git2::STATUS_WT_MODIFIED) { StatusTypes::Modified }
                else if f.contains(git2::STATUS_WT_DELETED) { StatusTypes::Deleted }
                else if f.contains(git2::STATUS_WT_RENAMED) { StatusTypes::Renamed }
                else if f.contains(git2::STATUS_WT_TYPECHANGE) { StatusTypes::TypeChange }
                else { StatusTypes::Clean },
        }
    }
}

impl fmt::Show for GitStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", self.index, self.workdir)
    }
}

fn get_git(path: &Path) -> Option<Repository> {
    match Repository::discover(path) {
        Ok(repo) => Some(repo),
        _ => None
    }
}

struct BranchInfo {
    name: Option<String>,
    upstream: Option<String>
}

fn git_branch(repo: &Repository) -> Result<BranchInfo, Error> {
    let mut branches = repo.branches(None).ok().expect("Unable to load branches");

    for (mut branch, _) in branches {
        if !branch.is_head() {
            continue;
        }

        let name = branch.name();
        return Ok(BranchInfo {
            name: match name {
                Ok(n) => match n {
                    Some(value) => Some(value.to_string()),
                    _ => None
                },
                _ => None
            },
            upstream: match branch.upstream() {
                Ok(upstream) => {
                    match upstream.name() {
                        Ok(n) => match n {
                            Some(value) => Some(value.to_string()),
                            _ => None
                        },
                        _ => None
                    }
                },
                Err(_) => None
            }
        });
    }

    match repo.head() {
        Ok(r) => match repo.find_object(r.target().unwrap(), None) {
            Ok(obj) => {
                let sid = obj.short_id().ok().unwrap();
                let s = sid.as_str();
                let short_id = s.unwrap();
                Ok(BranchInfo {
                    name: Some(format!("{}", short_id)),
                    upstream: Some("?".to_string())
                })
            },
            Err(e) => Err(e)
        },
        Err(e) => Err(e)
    }
}

pub struct GitPlugin {
    repo: Option<Repository>,
    path: Path
}

impl GitPlugin {
    pub fn new() -> GitPlugin {
        GitPlugin {
            repo: None,
            path: os::make_absolute(&Path::new(".")).unwrap()
        }
    }

    fn get_repo(&self) -> Result<&Repository, Error> {
        match self.repo {
            Some(ref repo) => Ok(repo),
            None => Err(Error::from_str("No repo"))
        }
    }

    fn status(&self, buffer: &mut Vec<PromptLine>, path: &Path) -> Result<bool, Error> {
        let repo = try!(self.get_repo());

        let st = repo.statuses(Some(StatusOptions::new()
            .include_untracked(true)
            .renames_head_to_index(true)
        ));

        let make_path_relative = |current: Path| {
            let mut fullpath = repo.workdir().unwrap();
            fullpath.push(current);

            fullpath.path_relative_from(path).unwrap()
        };

        match st {
            Ok(statuses) => {
                if statuses.len() <= 0 { return Ok(false) }

                buffer.push(PromptLineBuilder::new()
                    .colored_block(&"Git Status", color::CYAN)
                    .build());

                for stat in statuses.iter() {
                    let mut line = PromptLineBuilder::new_free();

                    let status = GitStatus::new(stat.status());

                    let diff = match stat.head_to_index() {
                        Some(delta) => Some(delta),
                        None => match stat.index_to_workdir() {
                            Some(delta) => Some(delta),
                            None => None
                        }
                    };

                    let val = format!("{} {}", status, match diff {
                        Some(delta) => {
                            let old = make_path_relative(delta.old_file().path().unwrap());
                            let new = make_path_relative(delta.new_file().path().unwrap());

                            if old != new {
                                format!("{} -> {}", old.display(), new.display())
                            } else {
                                format!("{}", old.display())
                            }
                        },
                        None => format!("{}", Path::new(stat.path().unwrap()).display())
                    });

                    line = match status.index {
                        StatusTypes::Clean => line.colored_block(&val, file_state_color(status.workdir)),
                        _ => match status.workdir {
                            StatusTypes::Clean | StatusTypes::Untracked =>
                                line.bold_colored_block(&val, file_state_color(status.index)),
                            _ => line.bold_colored_block(&val, color::RED)
                        }
                    };

                    buffer.push(line.indent().build());
                }

                return Ok(true)
            },
            _ => { return Ok(false) }
        }

        fn file_state_color(state: StatusTypes) -> u16 {
            match state {
                StatusTypes::Clean | StatusTypes::Untracked => color::WHITE,
                StatusTypes::Deleted => color::RED,
                StatusTypes::Modified => color::BLUE,
                StatusTypes::New => color::GREEN,
                StatusTypes::Renamed => color::CYAN,
                StatusTypes::TypeChange => color::YELLOW,
            }
        }
    }

    fn outgoing(&self, buffer: &mut Vec<PromptLine>, has_status: bool) -> Result<bool, Error> {
        let repo = try!(self.get_repo());

        let branches = try!(git_branch(repo));

        let mut revwalk = try!(repo.revwalk());

        let from = try!(repo.revparse_single(branches.upstream.unwrap().as_slice())).id();
        let to = try!(repo.revparse_single(branches.name.unwrap().as_slice())).id();

        try!(revwalk.push(to));
        try!(revwalk.hide(from));

        let mut log_shown = false;

        for id in revwalk {
            let mut commit = try!(repo.find_commit(id));

            if !log_shown {
                buffer.push(PromptLineBuilder::new()
                    .colored_block(&"Git Outgoing", color::CYAN)
                    .indent_by(if has_status { 1 } else { 0 })
                    .build());
                log_shown = true;
            }

            buffer.push(PromptLineBuilder::new_free()
                .indent()
                .block(&format!("{}{} {}",
                    prompt_buffer::reset(),
                    String::from_utf8_lossy(
                        try!(try!(repo.find_object(commit.id(), None)).short_id()).get()
                    ),
                    String::from_utf8_lossy(match commit.summary_bytes() {
                        Some(b) => b,
                        None => continue
                    })))
                .build());
        }

        return Ok(log_shown);
    }

    fn end(&self, buffer: &mut Vec<PromptLine>, indented: bool) -> Result<bool, Error> {
        let repo = try!(self.get_repo());

        let branches = try!(git_branch(repo));

        buffer.push(PromptLineBuilder::new()
            .colored_block(
                &match (branches.name, branches.upstream) {
                    (None, None) => "New Repository".to_string(),
                    (Some(name), None) => name,
                    (Some(name), Some(remote)) => format!("{}{} -> {}{}",
                        name,
                        prompt_buffer::reset(),
                        prompt_buffer::col(color::MAGENTA),
                        remote),
                    _ => "Unknown branch state".to_string()
                }, color::CYAN)
            .indent_by(if indented { 1 } else { 0 })
            .build());

        Ok(true)
    }
}

impl PromptBufferPlugin for GitPlugin {
    fn run(&mut self, path: &Path, lines: &mut Vec<PromptLine>) {
        if self.path != *path || self.repo.is_none() {
            self.path = path.clone();
            self.repo = get_git(&self.path);
        }

        let st = self.status(lines, path).ok().unwrap_or(false);
        let out = self.outgoing(lines, st).ok().unwrap_or(false);
        self.end(lines, st || out).ok();
    }
}
<commit_msg>Fix panics if upstream or name branches are None<commit_after>extern crate git2;

use prompt_buffer;
use prompt_buffer::{PromptLine, PromptBufferPlugin, PromptLineBuilder};
use git2::{Repository, Error, StatusOptions, STATUS_WT_NEW};
use std::{os, fmt};
use term::color;

enum StatusTypes {
    New,
    Modified,
    Deleted,
    Renamed,
    TypeChange,
    Untracked,
    Clean
}

impl fmt::Show for StatusTypes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            StatusTypes::Clean => " ",
            StatusTypes::Deleted => "D",
            StatusTypes::Modified => "M",
            StatusTypes::New => "A",
            StatusTypes::Renamed => "R",
            StatusTypes::TypeChange => "T",
            StatusTypes::Untracked => "?",
        })
    }
}

struct GitStatus {
    index: StatusTypes,
    workdir: StatusTypes
}

impl GitStatus {
    fn new(f: git2::Status) -> GitStatus {
        GitStatus {
            index:
                     if f.contains(git2::STATUS_INDEX_NEW) { StatusTypes::New }
                else if f.contains(git2::STATUS_INDEX_MODIFIED) { StatusTypes::Modified }
                else if f.contains(git2::STATUS_INDEX_DELETED) { StatusTypes::Deleted }
                else if f.contains(git2::STATUS_INDEX_RENAMED) { StatusTypes::Renamed }
                else if f.contains(git2::STATUS_INDEX_TYPECHANGE) { StatusTypes::TypeChange }
                else if f.contains(git2::STATUS_WT_NEW) { StatusTypes::Untracked }
                else { StatusTypes::Clean },
            workdir:
                     if f.contains(git2::STATUS_WT_NEW) { StatusTypes::Untracked }
                else if f.contains(git2::STATUS_WT_MODIFIED) { StatusTypes::Modified }
                else if f.contains(git2::STATUS_WT_DELETED) { StatusTypes::Deleted }
                else if f.contains(git2::STATUS_WT_RENAMED) { StatusTypes::Renamed }
                else if f.contains(git2::STATUS_WT_TYPECHANGE) { StatusTypes::TypeChange }
                else { StatusTypes::Clean },
        }
    }
}

impl fmt::Show for GitStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}{}", self.index, self.workdir)
    }
}

fn get_git(path: &Path) -> Option<Repository> {
    match Repository::discover(path) {
        Ok(repo) => Some(repo),
        _ => None
    }
}

struct BranchInfo {
    name: Option<String>,
    upstream: Option<String>
}

fn git_branch(repo: &Repository) -> Result<BranchInfo, Error> {
    let mut branches = repo.branches(None).ok().expect("Unable to load branches");

    for (mut branch, _) in branches {
        if !branch.is_head() {
            continue;
        }

        let name = branch.name();
        return Ok(BranchInfo {
            name: match name {
                Ok(n) => match n {
                    Some(value) => Some(value.to_string()),
                    _ => None
                },
                _ => None
            },
            upstream: match branch.upstream() {
                Ok(upstream) => {
                    match upstream.name() {
                        Ok(n) => match n {
                            Some(value) => Some(value.to_string()),
                            _ => None
                        },
                        _ => None
                    }
                },
                Err(_) => None
            }
        });
    }

    match repo.head() {
        Ok(r) => match repo.find_object(r.target().unwrap(), None) {
            Ok(obj) => {
                let sid = obj.short_id().ok().unwrap();
                let s = sid.as_str();
                let short_id = s.unwrap();
                Ok(BranchInfo {
                    name: Some(format!("{}", short_id)),
                    upstream: Some("?".to_string())
                })
            },
            Err(e) => Err(e)
        },
        Err(e) => Err(e)
    }
}

pub struct GitPlugin {
    repo: Option<Repository>,
    path: Path
}

impl GitPlugin {
    pub fn new() -> GitPlugin {
        GitPlugin {
            repo: None,
            path: os::make_absolute(&Path::new(".")).unwrap()
        }
    }

    fn get_repo(&self) -> Result<&Repository, Error> {
        match self.repo {
            Some(ref repo) => Ok(repo),
            None => Err(Error::from_str("No repo"))
        }
    }

    fn status(&self, buffer: &mut Vec<PromptLine>, path: &Path) -> Result<bool, Error> {
        let repo = try!(self.get_repo());

        let st = repo.statuses(Some(StatusOptions::new()
            .include_untracked(true)
            .renames_head_to_index(true)
        ));

        let make_path_relative = |current: Path| {
            let mut fullpath = repo.workdir().unwrap();
            fullpath.push(current);

            fullpath.path_relative_from(path).unwrap()
        };

        match st {
            Ok(statuses) => {
                if statuses.len() <= 0 { return Ok(false) }

                buffer.push(PromptLineBuilder::new()
                    .colored_block(&"Git Status", color::CYAN)
                    .build());

                for stat in statuses.iter() {
                    let mut line = PromptLineBuilder::new_free();

                    let status = GitStatus::new(stat.status());

                    let diff = match stat.head_to_index() {
                        Some(delta) => Some(delta),
                        None => match stat.index_to_workdir() {
                            Some(delta) => Some(delta),
                            None => None
                        }
                    };

                    let val = format!("{} {}", status, match diff {
                        Some(delta) => {
                            let old = make_path_relative(delta.old_file().path().unwrap());
                            let new = make_path_relative(delta.new_file().path().unwrap());

                            if old != new {
                                format!("{} -> {}", old.display(), new.display())
                            } else {
                                format!("{}", old.display())
                            }
                        },
                        None => format!("{}", Path::new(stat.path().unwrap()).display())
                    });

                    line = match status.index {
                        StatusTypes::Clean => line.colored_block(&val, file_state_color(status.workdir)),
                        _ => match status.workdir {
                            StatusTypes::Clean | StatusTypes::Untracked =>
                                line.bold_colored_block(&val, file_state_color(status.index)),
                            _ => line.bold_colored_block(&val, color::RED)
                        }
                    };

                    buffer.push(line.indent().build());
                }

                return Ok(true)
            },
            _ => { return Ok(false) }
        }

        fn file_state_color(state: StatusTypes) -> u16 {
            match state {
                StatusTypes::Clean | StatusTypes::Untracked => color::WHITE,
                StatusTypes::Deleted => color::RED,
                StatusTypes::Modified => color::BLUE,
                StatusTypes::New => color::GREEN,
                StatusTypes::Renamed => color::CYAN,
                StatusTypes::TypeChange => color::YELLOW,
            }
        }
    }

    fn outgoing(&self, buffer: &mut Vec<PromptLine>, has_status: bool) -> Result<bool, Error> {
        let repo = try!(self.get_repo());

        let branches = try!(git_branch(repo));

        let mut revwalk = try!(repo.revwalk());

        let from = try!(repo.revparse_single(branches.upstream.unwrap_or("HEAD".to_string()).as_slice())).id();
        let to = try!(repo.revparse_single(branches.name.unwrap_or("HEAD".to_string()).as_slice())).id();

        try!(revwalk.push(to));
        try!(revwalk.hide(from));

        let mut log_shown = false;

        for id in revwalk {
            let mut commit = try!(repo.find_commit(id));

            if !log_shown {
                buffer.push(PromptLineBuilder::new()
                    .colored_block(&"Git Outgoing", color::CYAN)
                    .indent_by(if has_status { 1 } else { 0 })
                    .build());
                log_shown = true;
            }

            buffer.push(PromptLineBuilder::new_free()
                .indent()
                .block(&format!("{}{} {}",
                    prompt_buffer::reset(),
                    String::from_utf8_lossy(
                        try!(try!(repo.find_object(commit.id(), None)).short_id()).get()
                    ),
                    String::from_utf8_lossy(match commit.summary_bytes() {
                        Some(b) => b,
                        None => continue
                    })))
                .build());
        }

        return Ok(log_shown);
    }

    fn end(&self, buffer: &mut Vec<PromptLine>, indented: bool) -> Result<bool, Error> {
        let repo = try!(self.get_repo());

        let branches = try!(git_branch(repo));

        buffer.push(PromptLineBuilder::new()
            .colored_block(
                &match (branches.name, branches.upstream) {
                    (None, None) => "New Repository".to_string(),
                    (Some(name), None) => name,
                    (Some(name), Some(remote)) => format!("{}{} -> {}{}",
                        name,
                        prompt_buffer::reset(),
                        prompt_buffer::col(color::MAGENTA),
                        remote),
                    _ => "Unknown branch state".to_string()
                }, color::CYAN)
            .indent_by(if indented { 1 } else { 0 })
            .build());

        Ok(true)
    }
}

impl PromptBufferPlugin for GitPlugin {
    fn run(&mut self, path: &Path, lines: &mut Vec<PromptLine>) {
        if self.path != *path || self.repo.is_none() {
            self.path = path.clone();
            self.repo = get_git(&self.path);
        }

        let st = self.status(lines, path).ok().unwrap_or(false);
        let out = self.outgoing(lines, st).ok().unwrap_or(false);
        self.end(lines, st || out).ok();
    }
}
<|endoftext|>


<commit_before>//! `ToSql` and `FromSql` implementation for JSON `Value`.
extern crate serde_json;

use libc::c_int;
use self::serde_json::Value;

use {Error, Result};
use types::{FromSql, ToSql};

use ffi;
use ffi::sqlite3_stmt;
use ffi::sqlite3_column_type;

/// Serialize JSON `Value` to text.
impl ToSql for Value {
    unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
        let s = serde_json::to_string(self).unwrap();
        s.bind_parameter(stmt, col)
    }
}

/// Deserialize text/blob to JSON `Value`.
impl FromSql for Value {
    unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> Result<Value> {
        match sqlite3_column_type(stmt, col) {
            ffi::SQLITE_TEXT => {
                let s = try!(String::column_result(stmt, col));
                match serde_json::from_str(&s) {
                    Ok(v) => Ok(v),
                    Err(err) => Err(Error::FromSqlConversionFailure(Box::new(err))),
                }
            }
            ffi::SQLITE_BLOB => {
                let blob: Vec<u8> = try!(FromSql::column_result(stmt, col));
                match serde_json::from_slice(&blob[..]) {
                    Ok(v) => Ok(v),
                    Err(err) => Err(Error::FromSqlConversionFailure(Box::new(err))),
                }
            }
            _ => Err(Error::InvalidColumnType),
        }
    }
}

#[cfg(test)]
mod test {
    use Connection;
    use super::serde_json;

    fn checked_memory_handle() -> Connection {
        let db = Connection::open_in_memory().unwrap();
        db.execute_batch("CREATE TABLE foo (t TEXT, b BLOB)").unwrap();
        db
    }

    #[test]
    fn test_json_value() {
        let db = checked_memory_handle();

        let json = "{\"foo\": 13, \"bar\": \"baz\"}";
        let data: serde_json::Value = serde_json::from_str(json).unwrap();
        db.execute("INSERT INTO foo (t, b) VALUES (?, ?)",
                   &[&data, &json.as_bytes()])
          .unwrap();

        let t: serde_json::Value = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap();
        assert_eq!(data, t);
        let b: serde_json::Value = db.query_row("SELECT b FROM foo", &[], |r| r.get(0)).unwrap();
        assert_eq!(data, b);
    }
}
<commit_msg>Minor code cleanup/refactoring. No functional changes.<commit_after>//! `ToSql` and `FromSql` implementation for JSON `Value`.
extern crate serde_json;

use libc::c_int;
use self::serde_json::Value;

use {Error, Result};
use types::{FromSql, ToSql};

use ffi;
use ffi::sqlite3_stmt;
use ffi::sqlite3_column_type;

/// Serialize JSON `Value` to text.
impl ToSql for Value {
    unsafe fn bind_parameter(&self, stmt: *mut sqlite3_stmt, col: c_int) -> c_int {
        let s = serde_json::to_string(self).unwrap();
        s.bind_parameter(stmt, col)
    }
}

/// Deserialize text/blob to JSON `Value`.
impl FromSql for Value {
    unsafe fn column_result(stmt: *mut sqlite3_stmt, col: c_int) -> Result<Value> {
        let value_result = match sqlite3_column_type(stmt, col) {
            ffi::SQLITE_TEXT => {
                let s = try!(String::column_result(stmt, col));
                serde_json::from_str(&s)
            }
            ffi::SQLITE_BLOB => {
                let blob = try!(Vec::<u8>::column_result(stmt, col));
                serde_json::from_slice(&blob)
            }
            _ => return Err(Error::InvalidColumnType)
        };
        value_result.map_err(|err| { Error::FromSqlConversionFailure(Box::new(err)) })
    }
}

#[cfg(test)]
mod test {
    use Connection;
    use super::serde_json;

    fn checked_memory_handle() -> Connection {
        let db = Connection::open_in_memory().unwrap();
        db.execute_batch("CREATE TABLE foo (t TEXT, b BLOB)").unwrap();
        db
    }

    #[test]
    fn test_json_value() {
        let db = checked_memory_handle();

        let json = r#"{"foo": 13, "bar": "baz"}"#;
        let data: serde_json::Value = serde_json::from_str(json).unwrap();
        db.execute("INSERT INTO foo (t, b) VALUES (?, ?)",
                   &[&data, &json.as_bytes()])
          .unwrap();

        let t: serde_json::Value = db.query_row("SELECT t FROM foo", &[], |r| r.get(0)).unwrap();
        assert_eq!(data, t);
        let b: serde_json::Value = db.query_row("SELECT b FROM foo", &[], |r| r.get(0)).unwrap();
        assert_eq!(data, b);
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;

struct History {
    h: Vec<(usize, usize)>
}

struct Board {
        board: [usize; 8],
}

impl Board{
    fn new() -> Board {
        Board{
            board: [8,8,8,8,8,8,8,8]
        }
    }

    fn set(&mut self, x: usize, y: usize){
        self.board[x] = y;
    }

    fn get(&self, x: usize) -> usize {
        self.board[x]
    }

    fn pos_set(&self, x: usize, y: usize) -> bool {
        self.get(x) == y
    }

    fn done(&self) -> bool {
        for i in 0..self.board.len() {
            if self.board[i] == 8 {
                return false;
            }
        }
        return true;
    }

    fn print(&self){
        println!("\n---------------------------------");
        for i in 0..8 {
            print!("|");
            for j in 0..8 {
                match self.get(j).cmp(&i) {
                    Ordering::Equal     => print!(" {} |", "X"),
                    Ordering::Greater   => print!(" {} |", " "),
                    Ordering::Less      => print!(" {} |", " "),
                }
            }
            println!("\n---------------------------------");
        }
    }

    fn collision(&self, x: usize, y: usize) -> bool {
        // col
        if self.get(x) != 8 {
            //println!("column true");
            return true;
        }

        for i in 0..8 {
            if self.pos_set(i, y) {
                //println!("row true");
                return true;
            }
        }

        let mut x_pos;
        let mut y_pos;
        if x < (7 - y) {
            x_pos = 0;
            y_pos = y + x;
        } else {
            x_pos = x - (7 - y);
            y_pos = 7;
        }

        loop {
            if self.pos_set(x_pos, y_pos){
                //println!("diag 1 found");
                return true;
            }
            if y_pos == 0 {
                break;
            }
            if x_pos == 7 {
                break;
            }
            x_pos = x_pos + 1;
            y_pos = y_pos - 1;
        }

        let mut x_pos;
        let mut y_pos;
        if y < x {
            x_pos = x - y;
            y_pos = 0;
        } else {
            x_pos = 0;
            y_pos = y - x;
        }

        loop {
            if self.pos_set(x_pos, y_pos){
                //println!("diag 1 found");
                return true;
            }
            if y_pos == 7 {
                break;
            }
            if x_pos == 7 {
                break;
            }
            x_pos = x_pos + 1;
            y_pos = y_pos + 1;
        }

        return false;
    }
}

fn find_my_queens(board: &mut Board, history: &mut History, row: usize, col: usize){
    if board.done() {
        board.print();
        return;
    }

    let r = row % 8;
    let mut c = 0;
    let mut found = false;
    for i in col..8 {
        if !board.collision(i, r){
            c = i;
            found = true;
            break;
        }
    }

    if found {
        board.set(c, r);
        history.h.push((c, r));
        find_my_queens(board, history, r + 1, 0);
    } else {
        match history.h.pop() {
            Some((x,_)) => {
                board.set(x, 8);
                if r == 0 {
                    find_my_queens(board, history, r, x + 1)
                } else {
                    find_my_queens(board, history, r - 1, x + 1)
                }
            }
            None => {}
        }
    }
}

fn main() {

    for i in 0..8 {
        for j in 0..8 {
            let mut board = Board::new();
            let mut history = History { h: vec![] };
            find_my_queens(&mut board, &mut history, i, j);
        }
    }
}
<commit_msg>add size of board as argument<commit_after>use std::cmp::Ordering;
use std::env;

struct History {
    h: Vec<(usize, usize)>
}

struct Board {
        board: Vec<usize>,
        size: usize
}

impl Board{
    fn new(size: usize) -> Board {
        Board{
            board: vec![size; size],
            size: size,
        }
    }

    fn set(&mut self, x: usize, y: usize){
        self.board[x] = y;
    }

    fn get(&self, x: usize) -> usize {
        self.board[x]
    }

    fn pos_set(&self, x: usize, y: usize) -> bool {
        self.get(x) == y
    }

    fn done(&self) -> bool {
        for i in 0..self.board.len() {
            if self.board[i] == self.size {
                return false;
            }
        }
        return true;
    }

    fn print(&self){
        self.print_line();
        for i in 0..self.size {
            print!("|");
            for j in 0..self.size {
                match self.get(j).cmp(&i) {
                    Ordering::Equal     => print!(" {} |", "X"),
                    Ordering::Greater   => print!(" {} |", " "),
                    Ordering::Less      => print!(" {} |", " "),
                }
            }
            self.print_line();
        }
    }

    fn print_line(&self) {
        print!("\n+");
        for i in 0..self.size {
            print!("---+");
        }
        print!("\n");
    }

    fn collision(&self, x: usize, y: usize) -> bool {
        // col
        if self.get(x) != self.size {
            return true;
        }

        for i in 0..self.size {
            if self.pos_set(i, y) {
                return true;
            }
        }

        let mut x_pos;
        let mut y_pos;
        if x < (self.size - 1 - y) {
            x_pos = 0;
            y_pos = y + x;
        } else {
            x_pos = x - (self.size - 1 - y);
            y_pos = self.size - 1;
        }

        loop {
            if self.pos_set(x_pos, y_pos){
                //println!("diag 1 found");
                return true;
            }
            if y_pos == 0 || x_pos == self.size - 1 {
                break;
            }
            x_pos = x_pos + 1;
            y_pos = y_pos - 1;
        }

        let mut x_pos;
        let mut y_pos;
        if y < x {
            x_pos = x - y;
            y_pos = 0;
        } else {
            x_pos = 0;
            y_pos = y - x;
        }

        loop {
            if self.pos_set(x_pos, y_pos){
                //println!("diag 1 found");
                return true;
            }
            if y_pos == self.size - 1 || x_pos == self.size - 1 {
                break;
            }
            x_pos = x_pos + 1;
            y_pos = y_pos + 1;
        }

        return false;
    }
}

fn find_my_queens(board: &mut Board, history: &mut History, row: usize, col: usize){
    if board.done() {
        board.print();
        return;
    }

    let r = row % board.size;
    let mut c = 0;
    let mut found = false;
    for i in col..board.size {
        if !board.collision(i, r){
            c = i;
            found = true;
            break;
        }
    }

    if found {
        board.set(c, r);
        history.h.push((c, r));
        find_my_queens(board, history, r + 1, 0);

    } else {
        match history.h.pop() {
            Some((x,_)) => {
                let size = board.size;
                board.set(x, size);
                if r == 0 {
                    find_my_queens(board, history, r, x + 1)
                } else {
                    find_my_queens(board, history, r - 1, x + 1)
                }
            }
            None => {}
        }
    }
}

fn main() {
    let size = 8;
    let arg = env::args()
                .nth(1)
                .map(|x| x.trim().parse());

    let size = match arg {
        Some(Ok(n)) => n,
        _ => size
    };

    for j in 0..size {
        let mut board = Board::new(size);
        let mut history = History { h: vec![] };
        find_my_queens(&mut board, &mut history, 0, j);
    }
}
<|endoftext|>


<commit_before><commit_msg>Prevent re-use of real mode areas, adjust areas instead of panic<commit_after><|endoftext|>


<commit_before><commit_msg>Remove redundant kind_name formatting<commit_after><|endoftext|>


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

//! A library for passing arbitrary file descriptors when spawning child processes.
//!
//! # Example
//!
//! ```rust
//! use command_fds::{CommandFdExt, FdMapping};
//! use std::fs::File;
//! use std::os::unix::io::AsRawFd;
//! use std::process::Command;
//!
//! // Open a file.
//! let file = File::open("Cargo.toml").unwrap();
//!
//! // Prepare to run `ls -l /proc/self/fd` with some FDs mapped.
//! let mut command = Command::new("ls");
//! command.arg("-l").arg("/proc/self/fd");
//! command
//!     .fd_mappings(vec![
//!         // Map `file` as FD 3 in the child process.
//!         FdMapping {
//!             parent_fd: file.as_raw_fd(),
//!             child_fd: 3,
//!         },
//!         // Map this process's stdin as FD 5 in the child process.
//!         FdMapping {
//!             parent_fd: 0,
//!             child_fd: 5,
//!         },
//!     ])
//!     .unwrap();
//!
//! // Spawn the child process.
//! let mut child = command.spawn().unwrap();
//! child.wait().unwrap();
//! ```

use nix::fcntl::{fcntl, FcntlArg};
use nix::unistd::dup2;
use std::cmp::max;
use std::io::{self, ErrorKind};
use std::os::unix::io::RawFd;
use std::os::unix::process::CommandExt;
use std::process::Command;
use thiserror::Error;

/// A mapping from a file descriptor in the parent to a file descriptor in the child, to be applied
/// when spawning a child process.
///
/// The parent_fd must be kept open until after the child is spawned.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FdMapping {
    pub parent_fd: RawFd,
    pub child_fd: RawFd,
}

/// Error setting up FD mappings, because there were two or more mappings for the same child FD.
#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
#[error("Two or more mappings for the same child FD")]
pub struct FdMappingCollision;

/// Extension to add file descriptor mappings to a [`Command`].
pub trait CommandFdExt {
    /// Adds the given set of file descriptor to the command.
    ///
    /// Calling this more than once on the same command may result in unexpected behaviour.
    fn fd_mappings(&mut self, mappings: Vec<FdMapping>) -> Result<(), FdMappingCollision>;
}

impl CommandFdExt for Command {
    fn fd_mappings(&mut self, mappings: Vec<FdMapping>) -> Result<(), FdMappingCollision> {
        // Validate that there are no conflicting mappings to the same child FD.
        let mut child_fds: Vec<RawFd> = mappings.iter().map(|mapping| mapping.child_fd).collect();
        child_fds.sort_unstable();
        child_fds.dedup();
        if child_fds.len() != mappings.len() {
            return Err(FdMappingCollision);
        }

        // Register the callback to apply the mappings after forking but before execing.
        unsafe {
            self.pre_exec(move || map_fds(&mappings));
        }

        Ok(())
    }
}

fn map_fds(mappings: &[FdMapping]) -> io::Result<()> {
    if mappings.is_empty() {
        // No need to do anything, and finding first_unused_fd would fail.
        return Ok(());
    }

    // Find the first FD which is higher than any parent or child FD in the mapping, so we can
    // safely use it and higher FDs as temporary FDs. There may be other files open with these FDs,
    // so we still need to ensure we don't conflict with them.
    let first_safe_fd = mappings
        .iter()
        .map(|mapping| max(mapping.parent_fd, mapping.child_fd))
        .max()
        .unwrap()
        + 1;

    // If any parent FDs conflict with child FDs, then first duplicate them to a temporary FD which
    // is clear of either range.
    let child_fds: Vec<RawFd> = mappings.iter().map(|mapping| mapping.child_fd).collect();
    let mappings = mappings
        .iter()
        .map(|mapping| {
            Ok(if child_fds.contains(&mapping.parent_fd) {
                let temporary_fd =
                    fcntl(mapping.parent_fd, FcntlArg::F_DUPFD_CLOEXEC(first_safe_fd))?;
                FdMapping {
                    parent_fd: temporary_fd,
                    child_fd: mapping.child_fd,
                }
            } else {
                mapping.to_owned()
            })
        })
        .collect::<nix::Result<Vec<_>>>()
        .map_err(nix_to_io_error)?;

    // Now we can actually duplicate FDs to the desired child FDs.
    for mapping in mappings {
        // This closes child_fd if it is already open as something else, and clears the FD_CLOEXEC
        // flag on child_fd.
        dup2(mapping.parent_fd, mapping.child_fd).map_err(nix_to_io_error)?;
    }

    Ok(())
}

/// Convert a [`nix::Error`] to a [`std::io::Error`].
fn nix_to_io_error(error: nix::Error) -> io::Error {
    if let nix::Error::Sys(errno) = error {
        io::Error::from_raw_os_error(errno as i32)
    } else {
        io::Error::new(ErrorKind::Other, error)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use nix::unistd::close;
    use std::collections::HashSet;
    use std::fs::{read_dir, File};
    use std::os::unix::io::AsRawFd;
    use std::process::Output;
    use std::str;

    #[test]
    fn conflicting_mappings() {
        close_excess_fds();

        let mut command = Command::new("ls");

        // The same mapping can't be included twice.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
            ]),
            Err(FdMappingCollision)
        );

        // Mapping two different FDs to the same FD isn't allowed either.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
                FdMapping {
                    child_fd: 4,
                    parent_fd: 6,
                },
            ]),
            Err(FdMappingCollision)
        );
    }

    #[test]
    fn no_mappings() {
        close_excess_fds();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        assert_eq!(command.fd_mappings(vec![]), Ok(()));

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3]);
    }

    #[test]
    fn one_mapping() {
        close_excess_fds();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file = File::open("testdata/file1.txt").unwrap();
        // Map the file an otherwise unused FD.
        assert_eq!(
            command.fd_mappings(vec![FdMapping {
                parent_fd: file.as_raw_fd(),
                child_fd: 5,
            },]),
            Ok(())
        );

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3, 5]);
    }

    #[test]
    fn swap_mappings() {
        close_excess_fds();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file1 = File::open("testdata/file1.txt").unwrap();
        let file2 = File::open("testdata/file2.txt").unwrap();
        let fd1 = file1.as_raw_fd();
        let fd2 = file2.as_raw_fd();
        // Map files to each other's FDs, to ensure that the temporary FD logic works.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    parent_fd: fd1,
                    child_fd: fd2,
                },
                FdMapping {
                    parent_fd: fd2,
                    child_fd: fd1,
                },
            ]),
            Ok(())
        );

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3, fd1, fd2]);
    }

    #[test]
    fn map_stdin() {
        close_excess_fds();

        let mut command = Command::new("cat");

        let file = File::open("testdata/file1.txt").unwrap();
        // Map the file to stdin.
        assert_eq!(
            command.fd_mappings(vec![FdMapping {
                parent_fd: file.as_raw_fd(),
                child_fd: 0,
            },]),
            Ok(())
        );

        let output = command.output().unwrap();
        assert!(output.status.success());
        assert_eq!(output.stdout, b"test 1");
    }

    /// Parse the output of ls into a set of filenames
    fn parse_ls_output(output: &[u8]) -> HashSet<String> {
        str::from_utf8(output)
            .unwrap()
            .split_terminator("\n")
            .map(str::to_owned)
            .collect()
    }

    /// Check that the output of `ls /proc/self/fd` contains the expected set of FDs.
    fn expect_fds(output: &Output, expected_fds: &[RawFd]) {
        assert!(output.status.success());
        let expected_fds: HashSet<String> = expected_fds.iter().map(RawFd::to_string).collect();
        assert_eq!(parse_ls_output(&output.stdout), expected_fds);
    }

    /// Close all file descriptors apart from stdin, stdout and stderr.
    ///
    /// This is necessary because GitHub Actions opens a bunch of others for some reason.
    fn close_excess_fds() {
        let dir = read_dir("/proc/self/fd").unwrap();
        for entry in dir {
            let entry = entry.unwrap();
            let fd: RawFd = entry.file_name().to_str().unwrap().parse().unwrap();
            if fd > 3 {
                close(fd).unwrap();
            }
        }
    }
}
<commit_msg>Only close excess FDs once, not before each test.<commit_after>// Copyright 2021, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A library for passing arbitrary file descriptors when spawning child processes.
//!
//! # Example
//!
//! ```rust
//! use command_fds::{CommandFdExt, FdMapping};
//! use std::fs::File;
//! use std::os::unix::io::AsRawFd;
//! use std::process::Command;
//!
//! // Open a file.
//! let file = File::open("Cargo.toml").unwrap();
//!
//! // Prepare to run `ls -l /proc/self/fd` with some FDs mapped.
//! let mut command = Command::new("ls");
//! command.arg("-l").arg("/proc/self/fd");
//! command
//!     .fd_mappings(vec![
//!         // Map `file` as FD 3 in the child process.
//!         FdMapping {
//!             parent_fd: file.as_raw_fd(),
//!             child_fd: 3,
//!         },
//!         // Map this process's stdin as FD 5 in the child process.
//!         FdMapping {
//!             parent_fd: 0,
//!             child_fd: 5,
//!         },
//!     ])
//!     .unwrap();
//!
//! // Spawn the child process.
//! let mut child = command.spawn().unwrap();
//! child.wait().unwrap();
//! ```

use nix::fcntl::{fcntl, FcntlArg};
use nix::unistd::dup2;
use std::cmp::max;
use std::io::{self, ErrorKind};
use std::os::unix::io::RawFd;
use std::os::unix::process::CommandExt;
use std::process::Command;
use thiserror::Error;

/// A mapping from a file descriptor in the parent to a file descriptor in the child, to be applied
/// when spawning a child process.
///
/// The parent_fd must be kept open until after the child is spawned.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FdMapping {
    pub parent_fd: RawFd,
    pub child_fd: RawFd,
}

/// Error setting up FD mappings, because there were two or more mappings for the same child FD.
#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
#[error("Two or more mappings for the same child FD")]
pub struct FdMappingCollision;

/// Extension to add file descriptor mappings to a [`Command`].
pub trait CommandFdExt {
    /// Adds the given set of file descriptor to the command.
    ///
    /// Calling this more than once on the same command may result in unexpected behaviour.
    fn fd_mappings(&mut self, mappings: Vec<FdMapping>) -> Result<(), FdMappingCollision>;
}

impl CommandFdExt for Command {
    fn fd_mappings(&mut self, mappings: Vec<FdMapping>) -> Result<(), FdMappingCollision> {
        // Validate that there are no conflicting mappings to the same child FD.
        let mut child_fds: Vec<RawFd> = mappings.iter().map(|mapping| mapping.child_fd).collect();
        child_fds.sort_unstable();
        child_fds.dedup();
        if child_fds.len() != mappings.len() {
            return Err(FdMappingCollision);
        }

        // Register the callback to apply the mappings after forking but before execing.
        unsafe {
            self.pre_exec(move || map_fds(&mappings));
        }

        Ok(())
    }
}

fn map_fds(mappings: &[FdMapping]) -> io::Result<()> {
    if mappings.is_empty() {
        // No need to do anything, and finding first_unused_fd would fail.
        return Ok(());
    }

    // Find the first FD which is higher than any parent or child FD in the mapping, so we can
    // safely use it and higher FDs as temporary FDs. There may be other files open with these FDs,
    // so we still need to ensure we don't conflict with them.
    let first_safe_fd = mappings
        .iter()
        .map(|mapping| max(mapping.parent_fd, mapping.child_fd))
        .max()
        .unwrap()
        + 1;

    // If any parent FDs conflict with child FDs, then first duplicate them to a temporary FD which
    // is clear of either range.
    let child_fds: Vec<RawFd> = mappings.iter().map(|mapping| mapping.child_fd).collect();
    let mappings = mappings
        .iter()
        .map(|mapping| {
            Ok(if child_fds.contains(&mapping.parent_fd) {
                let temporary_fd =
                    fcntl(mapping.parent_fd, FcntlArg::F_DUPFD_CLOEXEC(first_safe_fd))?;
                FdMapping {
                    parent_fd: temporary_fd,
                    child_fd: mapping.child_fd,
                }
            } else {
                mapping.to_owned()
            })
        })
        .collect::<nix::Result<Vec<_>>>()
        .map_err(nix_to_io_error)?;

    // Now we can actually duplicate FDs to the desired child FDs.
    for mapping in mappings {
        // This closes child_fd if it is already open as something else, and clears the FD_CLOEXEC
        // flag on child_fd.
        dup2(mapping.parent_fd, mapping.child_fd).map_err(nix_to_io_error)?;
    }

    Ok(())
}

/// Convert a [`nix::Error`] to a [`std::io::Error`].
fn nix_to_io_error(error: nix::Error) -> io::Error {
    if let nix::Error::Sys(errno) = error {
        io::Error::from_raw_os_error(errno as i32)
    } else {
        io::Error::new(ErrorKind::Other, error)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use nix::unistd::close;
    use std::collections::HashSet;
    use std::fs::{read_dir, File};
    use std::os::unix::io::AsRawFd;
    use std::process::Output;
    use std::str;
    use std::sync::Once;

    static SETUP: Once = Once::new();

    #[test]
    fn conflicting_mappings() {
        setup();

        let mut command = Command::new("ls");

        // The same mapping can't be included twice.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
            ]),
            Err(FdMappingCollision)
        );

        // Mapping two different FDs to the same FD isn't allowed either.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    child_fd: 4,
                    parent_fd: 5,
                },
                FdMapping {
                    child_fd: 4,
                    parent_fd: 6,
                },
            ]),
            Err(FdMappingCollision)
        );
    }

    #[test]
    fn no_mappings() {
        setup();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        assert_eq!(command.fd_mappings(vec![]), Ok(()));

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3], 0);
    }

    #[test]
    fn one_mapping() {
        setup();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file = File::open("testdata/file1.txt").unwrap();
        // Map the file an otherwise unused FD.
        assert_eq!(
            command.fd_mappings(vec![FdMapping {
                parent_fd: file.as_raw_fd(),
                child_fd: 5,
            },]),
            Ok(())
        );

        let output = command.output().unwrap();
        expect_fds(&output, &[0, 1, 2, 3, 5], 0);
    }

    #[test]
    fn swap_mappings() {
        setup();

        let mut command = Command::new("ls");
        command.arg("/proc/self/fd");

        let file1 = File::open("testdata/file1.txt").unwrap();
        let file2 = File::open("testdata/file2.txt").unwrap();
        let fd1 = file1.as_raw_fd();
        let fd2 = file2.as_raw_fd();
        // Map files to each other's FDs, to ensure that the temporary FD logic works.
        assert_eq!(
            command.fd_mappings(vec![
                FdMapping {
                    parent_fd: fd1,
                    child_fd: fd2,
                },
                FdMapping {
                    parent_fd: fd2,
                    child_fd: fd1,
                },
            ]),
            Ok(())
        );

        let output = command.output().unwrap();
        // Expect one more Fd for the /proc/self/fd directory. We can't predict what number it will
        // be assigned, because 3 might or might not be taken already by fd1 or fd2.
        expect_fds(&output, &[0, 1, 2, fd1, fd2], 1);
    }

    #[test]
    fn map_stdin() {
        setup();

        let mut command = Command::new("cat");

        let file = File::open("testdata/file1.txt").unwrap();
        // Map the file to stdin.
        assert_eq!(
            command.fd_mappings(vec![FdMapping {
                parent_fd: file.as_raw_fd(),
                child_fd: 0,
            },]),
            Ok(())
        );

        let output = command.output().unwrap();
        assert!(output.status.success());
        assert_eq!(output.stdout, b"test 1");
    }

    /// Parse the output of ls into a set of filenames
    fn parse_ls_output(output: &[u8]) -> HashSet<String> {
        str::from_utf8(output)
            .unwrap()
            .split_terminator("\n")
            .map(str::to_owned)
            .collect()
    }

    /// Check that the output of `ls /proc/self/fd` contains the expected set of FDs, plus exactly
    /// `extra` extra FDs.
    fn expect_fds(output: &Output, expected_fds: &[RawFd], extra: usize) {
        assert!(output.status.success());
        let expected_fds: HashSet<String> = expected_fds.iter().map(RawFd::to_string).collect();
        let fds = parse_ls_output(&output.stdout);
        if extra == 0 {
            assert_eq!(fds, expected_fds);
        } else {
            assert!(expected_fds.is_subset(&fds));
            assert_eq!(fds.len(), expected_fds.len() + extra);
        }
    }

    fn setup() {
        SETUP.call_once(close_excess_fds);
    }

    /// Close all file descriptors apart from stdin, stdout and stderr.
    ///
    /// This is necessary because GitHub Actions opens a bunch of others for some reason.
    fn close_excess_fds() {
        let dir = read_dir("/proc/self/fd").unwrap();
        for entry in dir {
            let entry = entry.unwrap();
            let fd: RawFd = entry.file_name().to_str().unwrap().parse().unwrap();
            if fd > 3 {
                close(fd).unwrap();
            }
        }
    }
}
<|endoftext|>


<commit_before>//! The `neon` crate provides the entire [Neon](https://www.neon-bindings.com/) API.

extern crate neon_runtime;
extern crate cslice;

#[cfg(test)]
extern crate rustc_version;

pub mod mem;
pub mod vm;
pub mod scope;
pub mod js;
pub mod task;

#[doc(hidden)]
pub mod macro_internal;

/// Register the current crate as a Node module, providing startup
/// logic for initializing the module object at runtime.
///
/// Example:
///
/// ```rust,ignore
/// register_module!(m, {
///     m.export("foo", foo)?;
///     m.export("bar", bar)?;
///     m.export("baz", baz)?;
///     Ok(())
/// });
/// ```
#[macro_export]
macro_rules! register_module {
    ($module:ident, $init:block) => {
        // Mark this function as a global constructor (like C++).
        #[allow(improper_ctypes)]
        #[cfg_attr(target_os = "linux", link_section = ".ctors")]
        #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
        #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
        pub static __LOAD_NEON_MODULE: extern "C" fn() = {
            fn __init_neon_module(mut $module: $crate::vm::Module) -> $crate::vm::VmResult<()> $init

            extern "C" fn __load_neon_module() {
                // Put everything else in the ctor fn so the user fn can't see it.
                #[repr(C)]
                struct __NodeModule {
                    version: i32,
                    flags: u32,
                    dso_handle: *mut u8,
                    filename: *const u8,
                    register_func: Option<extern "C" fn(
                        $crate::mem::Handle<$crate::js::JsObject>, *mut u8, *mut u8)>,
                    context_register_func: Option<extern "C" fn(
                        $crate::mem::Handle<$crate::js::JsObject>, *mut u8, *mut u8, *mut u8)>,
                    modname: *const u8,
                    priv_data: *mut u8,
                    link: *mut __NodeModule
                }

                static mut __NODE_MODULE: __NodeModule = __NodeModule {
                    version: 0,
                    flags: 0,
                    dso_handle: 0 as *mut _,
                    filename: b"neon_source.rs\0" as *const u8,
                    register_func: Some(__register_neon_module),
                    context_register_func: None,
                    modname: b"neon_module\0" as *const u8,
                    priv_data: 0 as *mut _,
                    link: 0 as *mut _
                };

                extern "C" fn __register_neon_module(
                        m: $crate::mem::Handle<$crate::js::JsObject>, _: *mut u8, _: *mut u8) {
                    $crate::vm::Module::initialize(m, __init_neon_module);
                }

                extern "C" {
                    fn node_module_register(module: *mut __NodeModule);
                }

                // Suppress the default Rust panic hook, which prints diagnostics to stderr.
                ::std::panic::set_hook(::std::boxed::Box::new(|_| { }));

                unsafe {
                    // Set the ABI version based on the NODE_MODULE_VERSION constant provided by the current node headers.
                    __NODE_MODULE.version = $crate::macro_internal::runtime::module::get_version();
                    node_module_register(&mut __NODE_MODULE);
                }
            }

            __load_neon_module
        };
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! class_definition {
    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; init($call:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          {
                              fn _______allocator_rust_y_u_no_hygienic_items_______($call: $crate::vm::FunctionCall<$crate::js::JsUndefined>) -> $crate::vm::VmResult<$typ> {
                                  $body
                              }

                              $crate::macro_internal::AllocateKernel::new(_______allocator_rust_y_u_no_hygienic_items_______)
                          } ;
                          $call_ctor ;
                          $new_ctor ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; ($($mname:tt)*) ; ($($mdef:tt)*) ; method $name:ident($call:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          $call_ctor ;
                          $new_ctor ;
                          ($($mname)* $name) ;
                          ($($mdef)* {
                              fn _______method_rust_y_u_no_hygienic_items_______($call: $crate::vm::FunctionCall<$cls>) -> $crate::vm::JsResult<$crate::js::JsValue> {
                                  $body
                              }

                              $crate::macro_internal::MethodKernel::new(_______method_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; constructor($call:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          $call_ctor ;
                          ({
                              fn _______constructor_rust_y_u_no_hygienic_items_______($call: $crate::vm::FunctionCall<$cls>) -> $crate::vm::VmResult<Option<$crate::mem::Handle<$crate::js::JsObject>>> {
                                  $body
                              }

                              $crate::macro_internal::ConstructKernel::new(_______constructor_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; call($call:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          ({
                              fn _______call_rust_y_u_no_hygienic_items_______($call: $crate::vm::FunctionCall<$crate::js::JsValue>) -> $crate::vm::JsResult<$crate::js::JsValue> {
                                  $body
                              }

                              $crate::macro_internal::ConstructorCallKernel::new(_______call_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $new_ctor ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:block ; ($($call_ctor:block)*) ; ($($new_ctor:block)*) ; ($($mname:ident)*) ; ($($mdef:block)*) ; $($rest:tt)* ) => {
        impl $crate::js::class::Class for $cls {
            type Internals = $typ;

            fn setup<'a, T: $crate::scope::Scope<'a>>(_: &mut T) -> $crate::vm::VmResult<$crate::js::class::ClassDescriptor<'a, Self>> {
                ::std::result::Result::Ok(Self::describe(stringify!($cname), $allocator)
                                             $(.construct($new_ctor))*
                                             $(.call($call_ctor))*
                                             $(.method(stringify!($mname), $mdef))*)
            }
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! impl_managed {
    ($cls:ident) => {
        impl $crate::mem::Managed for $cls {
            fn to_raw(self) -> $crate::macro_internal::runtime::raw::Local {
                let $cls(raw) = self;
                raw
            }

            fn from_raw(raw: $crate::macro_internal::runtime::raw::Local) -> Self {
                $cls(raw)
            }
        }
    }
}

/// Declare custom native JavaScript types with Rust implementations.
///
/// Example:
///
/// ```rust,ignore
/// pub struct Greeter {
///     greeting: String
/// }
///
/// declare_types! {
///
///     /// A class for generating greeting strings.
///     pub class JsGreeter for Greeter {
///         init(call) {
///             let scope = call.scope;
///             let greeting = call.arguments.require(scope, 0)?.to_string(scope)?.value();
///             Ok(Greeter {
///                 greeting: greeting
///             })
///         }
///
///         method hello(call) {
///             let scope = call.scope;
///             let name = call.arguments.require(scope, 0)?.to_string(scope)?.value();
///             let msg = vm::lock(call.arguments.this(scope), |greeter| {
///                 format!("{}, {}!", greeter.greeting, name)
///             });
///             Ok(JsString::new_or_throw(scope, &msg[..])?.upcast())
///         }
///     }
///
/// }
/// ```
#[macro_export]
macro_rules! declare_types {
    { $(#[$attr:meta])* pub class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
        declare_types! { $(#[$attr])* pub class $cls as $typ for $typ { $($body)* } $($rest)* }
    };

    { $(#[$attr:meta])* class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
        declare_types! { $(#[$attr])* class $cls as $typ for $typ { $($body)* } $($rest)* }
    };

    { $(#[$attr:meta])* pub class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
        #[derive(Copy, Clone)]
        #[repr(C)]
        $(#[$attr])*
        pub struct $cls($crate::macro_internal::runtime::raw::Local);

        impl_managed!($cls);

        class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);

        declare_types! { $($rest)* }
    };

    { $(#[$attr:meta])* class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
        #[derive(Copy, Clone)]
        #[repr(C)]
        $(#[$attr])*
        struct $cls($crate::macro_internal::runtime::raw::Local);

        impl_managed!($cls);

        class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);

        declare_types! { $($rest)* }
    };

    { } => { };
}

#[cfg(not(neon_profile = "release"))]
compile_error!("Neon only builds with --release. For tests, try `cargo test --release`.");

#[test]
fn cli_test() {
    use std::process::Command;
    if cfg!(target_os = "windows") {
        assert!(Command::new("cmd")
                        .args(&["/C", "echo Implement this later"])
                        .status()
                        .expect("failed to execute process")
                        .success());
        assert!(Command::new("cmd")
                        .args(&["/C", "echo Implement this later"])
                        .status()
                        .expect("failed to execute process")
                        .success());
    } else {
        assert!(Command::new("sh")
                        .arg("-c")
                        .arg("cd cli && npm install && npm run transpile")
                        .status()
                        .expect("failed to execute process")
                        .success());
        assert!(Command::new("sh")
                        .arg("-c")
                        .arg("cd test/cli && npm install && npm run transpile && npm test")
                        .status()
                        .expect("failed to execute process")
                        .success());
    };
}

#[test]
fn static_test() {
    use rustc_version::{version_meta, Channel};
    #[cfg(windows)]
    use std::env;

    if version_meta().unwrap().channel != Channel::Nightly { return };
    use std::process::Command;
    if cfg!(target_os = "windows") {
        assert!(Command::new("cmd")
                        .args(&["/C", "echo Implement this later"])
                        .status()
                        .expect("failed to execute process")
                        .success());
    } else {
        assert!(Command::new("sh")
                        .arg("-c")
                        .arg("cd test/static && cargo test")
                        .status()
                        .expect("failed to execute process")
                        .success());
    };
}

#[test]
fn dynamic_test() {
    use std::process::Command;
    #[cfg(windows)]
    use std::env;

    if cfg!(target_os = "windows") {
        assert!(Command::new("cmd")
                .args(&["/C", "echo Implement this later"])
                .status()
                .expect("failed to execute process")
                .success());
        assert!(Command::new("cmd")
                .args(&["/C", "echo Implement this later"])
                .status()
                .expect("failed to execute process")
                .success());
    } else {
        assert!(Command::new("sh")
                .arg("-c")
                .arg("cd cli && npm install && cd ../test/dynamic && npm install && npm test")
                .status()
                .expect("failed to execute process")
                .success());
    }
}
<commit_msg>limit the error to windows only<commit_after>//! The `neon` crate provides the entire [Neon](https://www.neon-bindings.com/) API.

extern crate neon_runtime;
extern crate cslice;

#[cfg(test)]
extern crate rustc_version;

pub mod mem;
pub mod vm;
pub mod scope;
pub mod js;
pub mod task;

#[doc(hidden)]
pub mod macro_internal;

/// Register the current crate as a Node module, providing startup
/// logic for initializing the module object at runtime.
///
/// Example:
///
/// ```rust,ignore
/// register_module!(m, {
///     m.export("foo", foo)?;
///     m.export("bar", bar)?;
///     m.export("baz", baz)?;
///     Ok(())
/// });
/// ```
#[macro_export]
macro_rules! register_module {
    ($module:ident, $init:block) => {
        // Mark this function as a global constructor (like C++).
        #[allow(improper_ctypes)]
        #[cfg_attr(target_os = "linux", link_section = ".ctors")]
        #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
        #[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
        pub static __LOAD_NEON_MODULE: extern "C" fn() = {
            fn __init_neon_module(mut $module: $crate::vm::Module) -> $crate::vm::VmResult<()> $init

            extern "C" fn __load_neon_module() {
                // Put everything else in the ctor fn so the user fn can't see it.
                #[repr(C)]
                struct __NodeModule {
                    version: i32,
                    flags: u32,
                    dso_handle: *mut u8,
                    filename: *const u8,
                    register_func: Option<extern "C" fn(
                        $crate::mem::Handle<$crate::js::JsObject>, *mut u8, *mut u8)>,
                    context_register_func: Option<extern "C" fn(
                        $crate::mem::Handle<$crate::js::JsObject>, *mut u8, *mut u8, *mut u8)>,
                    modname: *const u8,
                    priv_data: *mut u8,
                    link: *mut __NodeModule
                }

                static mut __NODE_MODULE: __NodeModule = __NodeModule {
                    version: 0,
                    flags: 0,
                    dso_handle: 0 as *mut _,
                    filename: b"neon_source.rs\0" as *const u8,
                    register_func: Some(__register_neon_module),
                    context_register_func: None,
                    modname: b"neon_module\0" as *const u8,
                    priv_data: 0 as *mut _,
                    link: 0 as *mut _
                };

                extern "C" fn __register_neon_module(
                        m: $crate::mem::Handle<$crate::js::JsObject>, _: *mut u8, _: *mut u8) {
                    $crate::vm::Module::initialize(m, __init_neon_module);
                }

                extern "C" {
                    fn node_module_register(module: *mut __NodeModule);
                }

                // Suppress the default Rust panic hook, which prints diagnostics to stderr.
                ::std::panic::set_hook(::std::boxed::Box::new(|_| { }));

                unsafe {
                    // Set the ABI version based on the NODE_MODULE_VERSION constant provided by the current node headers.
                    __NODE_MODULE.version = $crate::macro_internal::runtime::module::get_version();
                    node_module_register(&mut __NODE_MODULE);
                }
            }

            __load_neon_module
        };
    }
}

#[doc(hidden)]
#[macro_export]
macro_rules! class_definition {
    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; init($call:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          {
                              fn _______allocator_rust_y_u_no_hygienic_items_______($call: $crate::vm::FunctionCall<$crate::js::JsUndefined>) -> $crate::vm::VmResult<$typ> {
                                  $body
                              }

                              $crate::macro_internal::AllocateKernel::new(_______allocator_rust_y_u_no_hygienic_items_______)
                          } ;
                          $call_ctor ;
                          $new_ctor ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; ($($mname:tt)*) ; ($($mdef:tt)*) ; method $name:ident($call:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          $call_ctor ;
                          $new_ctor ;
                          ($($mname)* $name) ;
                          ($($mdef)* {
                              fn _______method_rust_y_u_no_hygienic_items_______($call: $crate::vm::FunctionCall<$cls>) -> $crate::vm::JsResult<$crate::js::JsValue> {
                                  $body
                              }

                              $crate::macro_internal::MethodKernel::new(_______method_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; constructor($call:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          $call_ctor ;
                          ({
                              fn _______constructor_rust_y_u_no_hygienic_items_______($call: $crate::vm::FunctionCall<$cls>) -> $crate::vm::VmResult<Option<$crate::mem::Handle<$crate::js::JsObject>>> {
                                  $body
                              }

                              $crate::macro_internal::ConstructKernel::new(_______constructor_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; call($call:pat) $body:block $($rest:tt)* ) => {
        class_definition!($cls ;
                          $cname ;
                          $typ ;
                          $allocator ;
                          ({
                              fn _______call_rust_y_u_no_hygienic_items_______($call: $crate::vm::FunctionCall<$crate::js::JsValue>) -> $crate::vm::JsResult<$crate::js::JsValue> {
                                  $body
                              }

                              $crate::macro_internal::ConstructorCallKernel::new(_______call_rust_y_u_no_hygienic_items_______)
                          }) ;
                          $new_ctor ;
                          $mnames ;
                          $mdefs ;
                          $($rest)*);
    };

    ( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:block ; ($($call_ctor:block)*) ; ($($new_ctor:block)*) ; ($($mname:ident)*) ; ($($mdef:block)*) ; $($rest:tt)* ) => {
        impl $crate::js::class::Class for $cls {
            type Internals = $typ;

            fn setup<'a, T: $crate::scope::Scope<'a>>(_: &mut T) -> $crate::vm::VmResult<$crate::js::class::ClassDescriptor<'a, Self>> {
                ::std::result::Result::Ok(Self::describe(stringify!($cname), $allocator)
                                             $(.construct($new_ctor))*
                                             $(.call($call_ctor))*
                                             $(.method(stringify!($mname), $mdef))*)
            }
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! impl_managed {
    ($cls:ident) => {
        impl $crate::mem::Managed for $cls {
            fn to_raw(self) -> $crate::macro_internal::runtime::raw::Local {
                let $cls(raw) = self;
                raw
            }

            fn from_raw(raw: $crate::macro_internal::runtime::raw::Local) -> Self {
                $cls(raw)
            }
        }
    }
}

/// Declare custom native JavaScript types with Rust implementations.
///
/// Example:
///
/// ```rust,ignore
/// pub struct Greeter {
///     greeting: String
/// }
///
/// declare_types! {
///
///     /// A class for generating greeting strings.
///     pub class JsGreeter for Greeter {
///         init(call) {
///             let scope = call.scope;
///             let greeting = call.arguments.require(scope, 0)?.to_string(scope)?.value();
///             Ok(Greeter {
///                 greeting: greeting
///             })
///         }
///
///         method hello(call) {
///             let scope = call.scope;
///             let name = call.arguments.require(scope, 0)?.to_string(scope)?.value();
///             let msg = vm::lock(call.arguments.this(scope), |greeter| {
///                 format!("{}, {}!", greeter.greeting, name)
///             });
///             Ok(JsString::new_or_throw(scope, &msg[..])?.upcast())
///         }
///     }
///
/// }
/// ```
#[macro_export]
macro_rules! declare_types {
    { $(#[$attr:meta])* pub class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
        declare_types! { $(#[$attr])* pub class $cls as $typ for $typ { $($body)* } $($rest)* }
    };

    { $(#[$attr:meta])* class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
        declare_types! { $(#[$attr])* class $cls as $typ for $typ { $($body)* } $($rest)* }
    };

    { $(#[$attr:meta])* pub class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
        #[derive(Copy, Clone)]
        #[repr(C)]
        $(#[$attr])*
        pub struct $cls($crate::macro_internal::runtime::raw::Local);

        impl_managed!($cls);

        class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);

        declare_types! { $($rest)* }
    };

    { $(#[$attr:meta])* class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
        #[derive(Copy, Clone)]
        #[repr(C)]
        $(#[$attr])*
        struct $cls($crate::macro_internal::runtime::raw::Local);

        impl_managed!($cls);

        class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);

        declare_types! { $($rest)* }
    };

    { } => { };
}

#[cfg(all(windows, not(neon_profile = "release")))]
compile_error!("Neon only builds with --release. For tests, try `cargo test --release`.");

#[test]
fn cli_test() {
    use std::process::Command;
    if cfg!(target_os = "windows") {
        assert!(Command::new("cmd")
                        .args(&["/C", "echo Implement this later"])
                        .status()
                        .expect("failed to execute process")
                        .success());
        assert!(Command::new("cmd")
                        .args(&["/C", "echo Implement this later"])
                        .status()
                        .expect("failed to execute process")
                        .success());
    } else {
        assert!(Command::new("sh")
                        .arg("-c")
                        .arg("cd cli && npm install && npm run transpile")
                        .status()
                        .expect("failed to execute process")
                        .success());
        assert!(Command::new("sh")
                        .arg("-c")
                        .arg("cd test/cli && npm install && npm run transpile && npm test")
                        .status()
                        .expect("failed to execute process")
                        .success());
    };
}

#[test]
fn static_test() {
    use rustc_version::{version_meta, Channel};
    #[cfg(windows)]
    use std::env;

    if version_meta().unwrap().channel != Channel::Nightly { return };
    use std::process::Command;
    if cfg!(target_os = "windows") {
        assert!(Command::new("cmd")
                        .args(&["/C", "echo Implement this later"])
                        .status()
                        .expect("failed to execute process")
                        .success());
    } else {
        assert!(Command::new("sh")
                        .arg("-c")
                        .arg("cd test/static && cargo test")
                        .status()
                        .expect("failed to execute process")
                        .success());
    };
}

#[test]
fn dynamic_test() {
    use std::process::Command;
    #[cfg(windows)]
    use std::env;

    if cfg!(target_os = "windows") {
        assert!(Command::new("cmd")
                .args(&["/C", "echo Implement this later"])
                .status()
                .expect("failed to execute process")
                .success());
        assert!(Command::new("cmd")
                .args(&["/C", "echo Implement this later"])
                .status()
                .expect("failed to execute process")
                .success());
    } else {
        assert!(Command::new("sh")
                .arg("-c")
                .arg("cd cli && npm install && cd ../test/dynamic && npm install && npm test")
                .status()
                .expect("failed to execute process")
                .success());
    }
}
<|endoftext|>


<commit_before>use std::net::UdpSocket;
use std::net::{Ipv6Addr, Ipv4Addr};
use std::net::ToSocketAddrs;

pub fn parse_mac(macstr: String) -> Result<Vec<u8>, &'static str> {
    let vec: Vec<u8> = macstr.split(':')
        .map(|s| u8::from_str_radix(s, 16).expect(&format!("Not a hex number: {}", s)))
        .collect();
    if vec.len() == 6 {
        Ok(vec)
    } else {
        Err("Illegal MAC address length.")
    }
}

pub fn send_magic_packet_v4(mac: Vec<u8>) -> Result<(), &'static str> {
    let buf = create_payload(mac);
    let socket = create_socket((Ipv4Addr::new(0, 0, 0, 0), 0)).expect("Could not create socket.");
    socket.connect((Ipv4Addr::new(255, 255, 255, 255), 0)).expect("Could not create connection.");
    socket.send(&buf).expect("Could not send packet.");
    Ok(())
}

pub fn send_magic_packet_v6(mac: Vec<u8>) -> Result<(), &'static str> {
    let buf = create_payload(mac);
    let socket = create_socket((Ipv6Addr::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 0))
        .expect("Could not create socket.");
    socket.connect((Ipv6Addr::new(0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02), 0))
        .expect("Could not create connection.");
    socket.send(&buf).expect("Could not send packet.");
    Ok(())
}

fn create_payload(mac: Vec<u8>) -> [u8; 17 * 6] {
    let mut buf: [u8; 17 * 6] = [0xFF; 17 * 6];
    for x in 1..17 {
        for y in 0..6 {
            buf[x * 6 + y] = mac[y];
        }
    }
    buf
}

fn create_socket<A: ToSocketAddrs>(address: A) -> Result<UdpSocket, std::io::Error> {
    let socket = UdpSocket::bind(address).unwrap();
    socket.set_broadcast(true)?;
    Ok(socket)
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_parse_mac() {
        assert_eq!(super::parse_mac("FF:FF:FF:FF:FF:FF".to_string()),
        Ok(vec![255, 255, 255, 255, 255, 255]));
        assert_eq!(super::parse_mac("00:00:00:00:00:00".to_string()),
        Ok(vec![0, 0, 0, 0, 0, 0]));
    }

    #[test]
    fn test_create_socket() {
        assert!(super::create_socket("127.0.0.1:0").is_ok());
        assert!(super::create_socket("[::1]:0").is_ok());
    }

    #[test]
    fn test_create_payload() {
        let payload = super::create_payload(vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05]);
        let result = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
        assert_eq!(payload.len(), result.len());
        assert!(payload.iter().zip(
        result.iter()).all(|(a, b)| a == b));
    }
}
<commit_msg>comments added<commit_after>//! #The Rust Wake On LAN tool.
use std::net::UdpSocket;
use std::net::{Ipv6Addr, Ipv4Addr};
use std::net::ToSocketAddrs;

/// Parses the MAC address from a given string.
///
/// #Example
///
/// ```
/// let mac = wol::parse_mac("AA:FF:B0:12:34:56".to_string());
/// assert_eq!(mac, Ok(vec![0xAA, 0xFF, 0xB0, 0x12, 0x34, 0x56]))
/// ```
pub fn parse_mac(mac: String) -> Result<Vec<u8>, &'static str> {
    let vec: Vec<u8> = mac.split(':')
        .map(|s| u8::from_str_radix(s, 16).expect(&format!("Not a hex number: {}", s)))
        .collect();
    if vec.len() == 6 {
        Ok(vec)
    } else {
        Err("Illegal MAC address length.")
    }
}

/// Sends the magic packet per UDP/IPv4.
///
/// #Example
///
/// ```
/// wol::send_magic_packet_v4(vec![0xAA, 0xFF, 0xB0, 0x12, 0x34, 0x56]);
/// ```
pub fn send_magic_packet_v4(mac: Vec<u8>) -> Result<(), &'static str> {
    let buf = create_payload(mac);
    let socket = create_socket((Ipv4Addr::new(0, 0, 0, 0), 0)).expect("Could not create socket.");
    socket.connect((Ipv4Addr::new(255, 255, 255, 255), 0)).expect("Could not create connection.");
    socket.send(&buf).expect("Could not send packet.");
    Ok(())
}

/// Sends the magic packet per UDP/IPv6.
///
/// #Example
///
/// ```
/// wol::send_magic_packet_v6(vec![0xAA, 0xFF, 0xB0, 0x12, 0x34, 0x56]);
/// ```
pub fn send_magic_packet_v6(mac: Vec<u8>) -> Result<(), &'static str> {
    let buf = create_payload(mac);
    let socket = create_socket((Ipv6Addr::new(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), 0))
        .expect("Could not create socket.");
    socket.connect((Ipv6Addr::new(0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02), 0))
        .expect("Could not create connection.");
    socket.send(&buf).expect("Could not send packet.");
    Ok(())
}

/// Creates the payload for the magic packet.
fn create_payload(mac: Vec<u8>) -> [u8; 17 * 6] {
    let mut buf: [u8; 17 * 6] = [0xFF; 17 * 6];
    for x in 1..17 {
        for y in 0..6 {
            buf[x * 6 + y] = mac[y];
        }
    }
    buf
}

// Creates the UdpSocket.
fn create_socket<A: ToSocketAddrs>(address: A) -> Result<UdpSocket, std::io::Error> {
    let socket = UdpSocket::bind(address).unwrap();
    socket.set_broadcast(true)?;
    Ok(socket)
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_parse_mac() {
        assert_eq!(super::parse_mac("FF:FF:FF:FF:FF:FF".to_string()),
        Ok(vec![255, 255, 255, 255, 255, 255]));
        assert_eq!(super::parse_mac("00:00:00:00:00:00".to_string()),
        Ok(vec![0, 0, 0, 0, 0, 0]));
    }

    #[test]
    fn test_create_socket() {
        assert!(super::create_socket("127.0.0.1:0").is_ok());
        assert!(super::create_socket("[::1]:0").is_ok());
    }

    #[test]
    fn test_create_payload() {
        let payload = super::create_payload(vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05]);
        let result = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
            0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
        assert_eq!(payload.len(), result.len());
        assert!(payload.iter().zip(
        result.iter()).all(|(a, b)| a == b));
    }
}
<|endoftext|>