<commit_before>use drivers::pio::*;

use programs::common::*;

pub struct PS2 {
    data: PIO8,
    cmd: PIO8,
    lshift: bool,
    rshift: bool,
    caps_lock: bool,
    caps_lock_toggle: bool,
    mouse_packet: [u8; 4],
    mouse_i: usize,
}

impl PS2 {
    pub fn new() -> Box<PS2> {
        let mut module = box PS2 {
            data: PIO8::new(0x60),
            cmd: PIO8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        debug::d("Set Defaults:");
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        debug::dc(' ');
        debug::dbh(self.data.read());
        debug::dl();

        debug::d("Set LEDS:");
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        debug::dc(' ');
        debug::dbh(self.data.read());

        self.wait1();
        self.data.write(0);
        self.wait0();
        debug::dc(' ');
        debug::dbh(self.data.read());
        debug::dl();

        debug::d("Set Scancode Map:");
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        debug::dc(' ');
        debug::dbh(self.data.read());

        self.wait1();
        self.data.write(1);
        self.wait0();
        debug::dc(' ');
        debug::dbh(self.data.read());
        debug::dl();
    }

    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return Option::None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Option::Some(KeyEvent {
            character: char_for_scancode(scancode & 0x7F, shift),
            scancode: scancode & 0x7F,
            pressed: scancode >= 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    pub unsafe fn mouse_init(&mut self) {
        //The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        //Set defaults
        self.mouse_cmd(0xF6);

        //Enable Streaming
        self.mouse_cmd(0xF4);
    }

    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            self.mouse_i = 0;

            return Option::Some(MouseEvent {
                x: x,
                y: y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return Option::None;
    }
}

impl SessionItem for PS2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Option::Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Option::Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}

fn char_for_scancode(scancode: u8, shift: bool) -> char {
    let mut character = '\x00';
    if scancode < 58 {
        if shift {
            character = SCANCODES[scancode as usize][1];
        } else {
            character = SCANCODES[scancode as usize][0];
        }
    }
    character
}

static SCANCODES: [[char; 2]; 58]= [['\0', '\0'],
 ['\x1B', '\x1B'],
 ['1', '!'],
 ['2', '@'],
 ['3', '#'],
 ['4', '$'],
 ['5', '%'],
 ['6', '^'],
 ['7', '&'],
 ['8', '*'],
 ['9', '('],
 ['0', ')'],
 ['-', '_'],
 ['=', '+'],
 ['\0', '\0'],
 ['\t', '\t'],
 ['q', 'Q'],
 ['w', 'W'],
 ['e', 'E'],
 ['r', 'R'],
 ['t', 'T'],
 ['y', 'Y'],
 ['u', 'U'],
 ['i', 'I'],
 ['o', 'O'],
 ['p', 'P'],
 ['[', '{'],
 [']', '}'],
 ['\n', '\n'],
 ['\0', '\0'],
 ['a', 'A'],
 ['s', 'S'],
 ['d', 'D'],
 ['f', 'F'],
 ['g', 'G'],
 ['h', 'H'],
 ['j', 'J'],
 ['k', 'K'],
 ['l', 'L'],
 [';', ':'],
 ['\'', '"'],
 ['`', '~'],
 ['\0', '\0'],
 ['\\', '|'],
 ['z', 'Z'],
 ['x', 'X'],
 ['c', 'C'],
 ['v', 'V'],
 ['b', 'B'],
 ['n', 'N'],
 ['m', 'M'],
 [',', '<'],
 ['.', '>'],
 ['/', '?'],
 ['\0', '\0'],
 ['\0', '\0'],
 ['\0', '\0'],
 [' ', ' ']];
<commit_msg>Fix bug with PS/2<commit_after>use drivers::pio::*;

use programs::common::*;

pub struct PS2 {
    data: PIO8,
    cmd: PIO8,
    lshift: bool,
    rshift: bool,
    caps_lock: bool,
    caps_lock_toggle: bool,
    mouse_packet: [u8; 4],
    mouse_i: usize,
}

impl PS2 {
    pub fn new() -> Box<PS2> {
        let mut module = box PS2 {
            data: PIO8::new(0x60),
            cmd: PIO8::new(0x64),
            lshift: false,
            rshift: false,
            caps_lock: false,
            caps_lock_toggle: false,
            mouse_packet: [0; 4],
            mouse_i: 0,
        };

        unsafe {
            module.keyboard_init();
            module.mouse_init();
        }

        module
    }

    unsafe fn wait0(&self) {
        while (self.cmd.read() & 1) == 0 {}
    }

    unsafe fn wait1(&self) {
        while (self.cmd.read() & 2) == 2 {}
    }

    unsafe fn keyboard_init(&mut self) {
        while (self.cmd.read() & 0x1) == 1 {
            self.data.read();
        }

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let flags = (self.data.read() & 0b00110111) | 1 | 0b10000;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(flags);

        debug::d("Set Defaults:");
        self.wait1();
        self.data.write(0xF6);
        self.wait0();
        debug::dc(' ');
        debug::dbh(self.data.read());
        debug::dl();

        debug::d("Set LEDS:");
        self.wait1();
        self.data.write(0xED);
        self.wait0();
        debug::dc(' ');
        debug::dbh(self.data.read());

        self.wait1();
        self.data.write(0);
        self.wait0();
        debug::dc(' ');
        debug::dbh(self.data.read());
        debug::dl();

        debug::d("Set Scancode Map:");
        self.wait1();
        self.data.write(0xF0);
        self.wait0();
        debug::dc(' ');
        debug::dbh(self.data.read());

        self.wait1();
        self.data.write(1);
        self.wait0();
        debug::dc(' ');
        debug::dbh(self.data.read());
        debug::dl();
    }

    pub fn keyboard_interrupt(&mut self) -> Option<KeyEvent> {
        let scancode = unsafe { self.data.read() };

        if scancode == 0 {
            return Option::None;
        } else if scancode == 0x2A {
            self.lshift = true;
        } else if scancode == 0xAA {
            self.lshift = false;
        } else if scancode == 0x36 {
            self.rshift = true;
        } else if scancode == 0xB6 {
            self.rshift = false;
        } else if scancode == 0x3A {
            if !self.caps_lock {
                self.caps_lock = true;
                self.caps_lock_toggle = true;
            } else {
                self.caps_lock_toggle = false;
            }
        } else if scancode == 0xBA {
            if self.caps_lock && !self.caps_lock_toggle {
                self.caps_lock = false;
            }
        }

        let shift;
        if self.caps_lock {
            shift = !(self.lshift || self.rshift);
        } else {
            shift = self.lshift || self.rshift;
        }

        return Option::Some(KeyEvent {
            character: char_for_scancode(scancode & 0x7F, shift),
            scancode: scancode & 0x7F,
            pressed: scancode < 0x80,
        });
    }

    unsafe fn mouse_cmd(&mut self, byte: u8) -> u8 {
        self.wait1();
        self.cmd.write(0xD4);
        self.wait1();
        self.data.write(byte);

        self.wait0();
        self.data.read()
    }

    pub unsafe fn mouse_init(&mut self) {
        //The Init Dance
        self.wait1();
        self.cmd.write(0xA8);

        self.wait1();
        self.cmd.write(0x20);
        self.wait0();
        let status = self.data.read() | 2;
        self.wait1();
        self.cmd.write(0x60);
        self.wait1();
        self.data.write(status);

        //Set defaults
        self.mouse_cmd(0xF6);

        //Enable Streaming
        self.mouse_cmd(0xF4);
    }

    pub fn mouse_interrupt(&mut self) -> Option<MouseEvent> {
        let byte = unsafe { self.data.read() };
        if self.mouse_i == 0 {
            if byte & 0x8 == 0x8 {
                self.mouse_packet[0] = byte;
                self.mouse_i += 1;
            }
        } else if self.mouse_i == 1 {
            self.mouse_packet[1] = byte;

            self.mouse_i += 1;
        } else {
            self.mouse_packet[2] = byte;

            let left_button = (self.mouse_packet[0] & 1) == 1;
            let right_button = (self.mouse_packet[0] & 2) == 2;
            let middle_button = (self.mouse_packet[0] & 4) == 4;

            let x;
            if (self.mouse_packet[0] & 0x40) != 0x40 && self.mouse_packet[1] != 0 {
                x = self.mouse_packet[1] as isize -
                    (((self.mouse_packet[0] as isize) << 4) & 0x100);
            } else {
                x = 0;
            }

            let y;
            if (self.mouse_packet[0] & 0x80) != 0x80 && self.mouse_packet[2] != 0 {
                y = (((self.mouse_packet[0] as isize) << 3) & 0x100) -
                    self.mouse_packet[2] as isize;
            } else {
                y = 0;
            }

            self.mouse_i = 0;

            return Option::Some(MouseEvent {
                x: x,
                y: y,
                left_button: left_button,
                right_button: right_button,
                middle_button: middle_button,
            });
        }

        return Option::None;
    }
}

impl SessionItem for PS2 {
    fn on_irq(&mut self, irq: u8) {
        if irq == 0x1 || irq == 0xC {
            self.on_poll();
        }
    }

    fn on_poll(&mut self) {
        loop {
            let status = unsafe { self.cmd.read() };
            if status & 0x21 == 1 {
                if let Option::Some(key_event) = self.keyboard_interrupt() {
                    key_event.trigger();
                }
            } else if status & 0x21 == 0x21 {
                if let Option::Some(mouse_event) = self.mouse_interrupt() {
                    mouse_event.trigger();
                }
            } else {
                break;
            }
        }
    }
}

fn char_for_scancode(scancode: u8, shift: bool) -> char {
    let mut character = '\x00';
    if scancode < 58 {
        if shift {
            character = SCANCODES[scancode as usize][1];
        } else {
            character = SCANCODES[scancode as usize][0];
        }
    }
    character
}

static SCANCODES: [[char; 2]; 58]= [['\0', '\0'],
 ['\x1B', '\x1B'],
 ['1', '!'],
 ['2', '@'],
 ['3', '#'],
 ['4', '$'],
 ['5', '%'],
 ['6', '^'],
 ['7', '&'],
 ['8', '*'],
 ['9', '('],
 ['0', ')'],
 ['-', '_'],
 ['=', '+'],
 ['\0', '\0'],
 ['\t', '\t'],
 ['q', 'Q'],
 ['w', 'W'],
 ['e', 'E'],
 ['r', 'R'],
 ['t', 'T'],
 ['y', 'Y'],
 ['u', 'U'],
 ['i', 'I'],
 ['o', 'O'],
 ['p', 'P'],
 ['[', '{'],
 [']', '}'],
 ['\n', '\n'],
 ['\0', '\0'],
 ['a', 'A'],
 ['s', 'S'],
 ['d', 'D'],
 ['f', 'F'],
 ['g', 'G'],
 ['h', 'H'],
 ['j', 'J'],
 ['k', 'K'],
 ['l', 'L'],
 [';', ':'],
 ['\'', '"'],
 ['`', '~'],
 ['\0', '\0'],
 ['\\', '|'],
 ['z', 'Z'],
 ['x', 'X'],
 ['c', 'C'],
 ['v', 'V'],
 ['b', 'B'],
 ['n', 'N'],
 ['m', 'M'],
 [',', '<'],
 ['.', '>'],
 ['/', '?'],
 ['\0', '\0'],
 ['\0', '\0'],
 ['\0', '\0'],
 [' ', ' ']];
<|endoftext|>


<commit_before>use hir::{Adt, ModuleDef};
use ide_db::defs::{Definition, NameRefClass};
use syntax::{
    ast::{self, AstNode, GenericParamsOwner, VisibilityOwner},
    match_ast,
};

use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};

// Assist: convert_tuple_struct_to_named_struct
//
// Converts tuple struct to struct with named fields.
//
// ```
// struct Point$0(f32, f32);
//
// impl Point {
//     pub fn new(x: f32, y: f32) -> Self {
//         Point(x, y)
//     }
//
//     pub fn x(&self) -> f32 {
//         self.0
//     }
//
//     pub fn y(&self) -> f32 {
//         self.1
//     }
// }
// ```
// ->
// ```
// struct Point { field1: f32, field2: f32 }
//
// impl Point {
//     pub fn new(x: f32, y: f32) -> Self {
//         Point { field1: x, field2: y }
//     }
//
//     pub fn x(&self) -> f32 {
//         self.field1
//     }
//
//     pub fn y(&self) -> f32 {
//         self.field2
//     }
// }
// ```
pub(crate) fn convert_tuple_struct_to_named_struct(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
    let tuple_fields = match strukt.field_list()? {
        ast::FieldList::TupleFieldList(it) => it,
        ast::FieldList::RecordFieldList(_) => return None,
    };

    let target = strukt.syntax().text_range();
    acc.add(
        AssistId("convert_tuple_struct_to_named_struct", AssistKind::RefactorRewrite),
        "Convert to named struct",
        target,
        |edit| {
            let names = generate_names(tuple_fields.fields());
            edit_field_references(ctx, edit, tuple_fields.fields(), &names);
            edit_struct_references(ctx, edit, &strukt, &names);
            edit_struct_def(ctx, edit, &strukt, tuple_fields, names);
        },
    )
}

fn edit_struct_def(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    strukt: &ast::Struct,
    tuple_fields: ast::TupleFieldList,
    names: Vec<ast::Name>,
) {
    let record_fields = tuple_fields
        .fields()
        .zip(names)
        .map(|(f, name)| ast::make::record_field(f.visibility(), name, f.ty().unwrap()));
    let record_fields = ast::make::record_field_list(record_fields);
    let tuple_fields_text_range = tuple_fields.syntax().text_range();

    edit.edit_file(ctx.frange.file_id);

    if let Some(w) = strukt.where_clause() {
        edit.delete(w.syntax().text_range());
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
        edit.insert(tuple_fields_text_range.start(), w.syntax().text());
        edit.insert(tuple_fields_text_range.start(), ",");
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
    } else {
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text());
    }

    edit.replace(tuple_fields_text_range, record_fields.to_string());
    strukt.semicolon_token().map(|t| edit.delete(t.text_range()));
}

fn edit_struct_references(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    strukt: &ast::Struct,
    names: &[ast::Name],
) {
    let strukt = ctx.sema.to_def(strukt).unwrap();
    let strukt_def = Definition::ModuleDef(ModuleDef::Adt(Adt::Struct(strukt)));
    let usages = strukt_def.usages(&ctx.sema).include_self_kw_refs(true).all();

    for (file_id, refs) in usages {
        edit.edit_file(file_id);
        for r in refs {
            for node in r.name.syntax().ancestors() {
                match_ast! {
                    match node {
                        ast::TupleStructPat(tuple_struct_pat) => {
                            edit.replace(
                                tuple_struct_pat.syntax().text_range(),
                                ast::make::record_pat_with_fields(
                                    tuple_struct_pat.path().unwrap(),
                                    ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
                                        |(pat, name)| {
                                            ast::make::record_pat_field(
                                                ast::make::name_ref(&name.to_string()),
                                                pat,
                                            )
                                        },
                                    )),
                                )
                                .to_string(),
                            );
                        },
                        // for tuple struct creations like Foo(42)
                        ast::CallExpr(call_expr) => {
                            let path = call_expr.syntax().descendants().find_map(ast::PathExpr::cast).unwrap().path().unwrap();

                            // this also includes method calls like Foo::new(42), we should skip them
                            if let Some(Some(name_ref)) = path.segment().map(|s| s.name_ref()) {
                                match NameRefClass::classify(&ctx.sema, &name_ref) {
                                    Some(NameRefClass::Definition(Definition::SelfType(_))) => {},
                                    Some(NameRefClass::Definition(def)) if def == strukt_def => {},
                                    _ => continue,
                                };
                            }

                            let arg_list =
                                call_expr.syntax().descendants().find_map(ast::ArgList::cast).unwrap();

                            edit.replace(
                                call_expr.syntax().text_range(),
                                ast::make::record_expr(
                                    path,
                                    ast::make::record_expr_field_list(arg_list.args().zip(names).map(
                                        |(expr, name)| {
                                            ast::make::record_expr_field(
                                                ast::make::name_ref(&name.to_string()),
                                                Some(expr),
                                            )
                                        },
                                    )),
                                )
                                .to_string(),
                            );
                        },
                        _ => ()
                    }
                }
            }
        }
    }
}

fn edit_field_references(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    fields: impl Iterator<Item = ast::TupleField>,
    names: &[ast::Name],
) {
    for (field, name) in fields.zip(names) {
        let field = match ctx.sema.to_def(&field) {
            Some(it) => it,
            None => continue,
        };
        let def = Definition::Field(field);
        let usages = def.usages(&ctx.sema).all();
        for (file_id, refs) in usages {
            edit.edit_file(file_id);
            for r in refs {
                if let Some(name_ref) = r.name.as_name_ref() {
                    edit.replace(name_ref.syntax().text_range(), name.text());
                }
            }
        }
    }
}

fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Name> {
    fields.enumerate().map(|(i, _)| ast::make::name(&format!("field{}", i + 1))).collect()
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn not_applicable_other_than_tuple_struct() {
        check_assist_not_applicable(
            convert_tuple_struct_to_named_struct,
            r#"struct Foo$0 { bar: u32 };"#,
        );
        check_assist_not_applicable(convert_tuple_struct_to_named_struct, r#"struct Foo$0;"#);
    }

    #[test]
    fn convert_simple_struct() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn new(inner: Inner) -> A {
        A(inner)
    }

    fn new_with_default() -> A {
        A::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.0
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn new(inner: Inner) -> A {
        A { field1: inner }
    }

    fn new_with_default() -> A {
        A::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.field1
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_referenced_via_self_kw() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn new(inner: Inner) -> Self {
        Self(inner)
    }

    fn new_with_default() -> Self {
        Self::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.0
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn new(inner: Inner) -> Self {
        Self { field1: inner }
    }

    fn new_with_default() -> Self {
        Self::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.field1
    }
}"#,
        );
    }

    #[test]
    fn convert_destructured_struct() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn into_inner(self) -> Inner {
        let A(first) = self;
        first
    }

    fn into_inner_via_self(self) -> Inner {
        let Self(first) = self;
        first
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn into_inner(self) -> Inner {
        let A { field1: first } = self;
        first
    }

    fn into_inner_via_self(self) -> Inner {
        let Self { field1: first } = self;
        first
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_with_visibility() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct A$0(pub u32, pub(crate) u64);

impl A {
    fn new() -> A {
        A(42, 42)
    }

    fn into_first(self) -> u32 {
        self.0
    }

    fn into_second(self) -> u64 {
        self.1
    }
}"#,
            r#"
struct A { pub field1: u32, pub(crate) field2: u64 }

impl A {
    fn new() -> A {
        A { field1: 42, field2: 42 }
    }

    fn into_first(self) -> u32 {
        self.field1
    }

    fn into_second(self) -> u64 {
        self.field2
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_with_where_clause() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Wrap$0<T>(T)
where
    T: Display;
"#,
            r#"
struct Wrap<T>
where
    T: Display,
{ field1: T }

"#,
        );
    }
}
<commit_msg>Remove `unwrap`s in "Convert to named struct" assist<commit_after>use hir::{Adt, ModuleDef, Struct};
use ide_db::defs::{Definition, NameRefClass};
use syntax::{
    ast::{self, AstNode, GenericParamsOwner, VisibilityOwner},
    match_ast,
};

use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};

// Assist: convert_tuple_struct_to_named_struct
//
// Converts tuple struct to struct with named fields.
//
// ```
// struct Point$0(f32, f32);
//
// impl Point {
//     pub fn new(x: f32, y: f32) -> Self {
//         Point(x, y)
//     }
//
//     pub fn x(&self) -> f32 {
//         self.0
//     }
//
//     pub fn y(&self) -> f32 {
//         self.1
//     }
// }
// ```
// ->
// ```
// struct Point { field1: f32, field2: f32 }
//
// impl Point {
//     pub fn new(x: f32, y: f32) -> Self {
//         Point { field1: x, field2: y }
//     }
//
//     pub fn x(&self) -> f32 {
//         self.field1
//     }
//
//     pub fn y(&self) -> f32 {
//         self.field2
//     }
// }
// ```
pub(crate) fn convert_tuple_struct_to_named_struct(
    acc: &mut Assists,
    ctx: &AssistContext,
) -> Option<()> {
    let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
    let tuple_fields = match strukt.field_list()? {
        ast::FieldList::TupleFieldList(it) => it,
        ast::FieldList::RecordFieldList(_) => return None,
    };
    let strukt_def = ctx.sema.to_def(&strukt)?;

    let target = strukt.syntax().text_range();
    acc.add(
        AssistId("convert_tuple_struct_to_named_struct", AssistKind::RefactorRewrite),
        "Convert to named struct",
        target,
        |edit| {
            let names = generate_names(tuple_fields.fields());
            edit_field_references(ctx, edit, tuple_fields.fields(), &names);
            edit_struct_references(ctx, edit, strukt_def, &names);
            edit_struct_def(ctx, edit, &strukt, tuple_fields, names);
        },
    )
}

fn edit_struct_def(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    strukt: &ast::Struct,
    tuple_fields: ast::TupleFieldList,
    names: Vec<ast::Name>,
) {
    let record_fields = tuple_fields
        .fields()
        .zip(names)
        .filter_map(|(f, name)| Some(ast::make::record_field(f.visibility(), name, f.ty()?)));
    let record_fields = ast::make::record_field_list(record_fields);
    let tuple_fields_text_range = tuple_fields.syntax().text_range();

    edit.edit_file(ctx.frange.file_id);

    if let Some(w) = strukt.where_clause() {
        edit.delete(w.syntax().text_range());
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
        edit.insert(tuple_fields_text_range.start(), w.syntax().text());
        edit.insert(tuple_fields_text_range.start(), ",");
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_newline().text());
    } else {
        edit.insert(tuple_fields_text_range.start(), ast::make::tokens::single_space().text());
    }

    edit.replace(tuple_fields_text_range, record_fields.to_string());
    strukt.semicolon_token().map(|t| edit.delete(t.text_range()));
}

fn edit_struct_references(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    strukt: Struct,
    names: &[ast::Name],
) {
    let strukt_def = Definition::ModuleDef(ModuleDef::Adt(Adt::Struct(strukt)));
    let usages = strukt_def.usages(&ctx.sema).include_self_kw_refs(true).all();

    for (file_id, refs) in usages {
        edit.edit_file(file_id);
        for r in refs {
            for node in r.name.syntax().ancestors() {
                match_ast! {
                    match node {
                        ast::TupleStructPat(tuple_struct_pat) => {
                            let path = match tuple_struct_pat.path() {
                                Some(it) => it,
                                None => continue,
                            };

                            edit.replace(
                                tuple_struct_pat.syntax().text_range(),
                                ast::make::record_pat_with_fields(
                                    path,
                                    ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
                                        |(pat, name)| {
                                            ast::make::record_pat_field(
                                                ast::make::name_ref(&name.to_string()),
                                                pat,
                                            )
                                        },
                                    )),
                                )
                                .to_string(),
                            );
                        },
                        // for tuple struct creations like Foo(42)
                        ast::CallExpr(call_expr) => {
                            let path = match call_expr.syntax().descendants().find_map(ast::PathExpr::cast).map(|expr| expr.path()) {
                                Some(Some(it)) => it,
                                _ => continue,
                            };

                            // this also includes method calls like Foo::new(42), we should skip them
                            if let Some(Some(name_ref)) = path.segment().map(|s| s.name_ref()) {
                                match NameRefClass::classify(&ctx.sema, &name_ref) {
                                    Some(NameRefClass::Definition(Definition::SelfType(_))) => {},
                                    Some(NameRefClass::Definition(def)) if def == strukt_def => {},
                                    _ => continue,
                                };
                            }

                            let arg_list = match call_expr.syntax().descendants().find_map(ast::ArgList::cast) {
                                Some(it) => it,
                                None => continue,
                            };

                            edit.replace(
                                call_expr.syntax().text_range(),
                                ast::make::record_expr(
                                    path,
                                    ast::make::record_expr_field_list(arg_list.args().zip(names).map(
                                        |(expr, name)| {
                                            ast::make::record_expr_field(
                                                ast::make::name_ref(&name.to_string()),
                                                Some(expr),
                                            )
                                        },
                                    )),
                                )
                                .to_string(),
                            );
                        },
                        _ => ()
                    }
                }
            }
        }
    }
}

fn edit_field_references(
    ctx: &AssistContext,
    edit: &mut AssistBuilder,
    fields: impl Iterator<Item = ast::TupleField>,
    names: &[ast::Name],
) {
    for (field, name) in fields.zip(names) {
        let field = match ctx.sema.to_def(&field) {
            Some(it) => it,
            None => continue,
        };
        let def = Definition::Field(field);
        let usages = def.usages(&ctx.sema).all();
        for (file_id, refs) in usages {
            edit.edit_file(file_id);
            for r in refs {
                if let Some(name_ref) = r.name.as_name_ref() {
                    edit.replace(name_ref.syntax().text_range(), name.text());
                }
            }
        }
    }
}

fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Name> {
    fields.enumerate().map(|(i, _)| ast::make::name(&format!("field{}", i + 1))).collect()
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn not_applicable_other_than_tuple_struct() {
        check_assist_not_applicable(
            convert_tuple_struct_to_named_struct,
            r#"struct Foo$0 { bar: u32 };"#,
        );
        check_assist_not_applicable(convert_tuple_struct_to_named_struct, r#"struct Foo$0;"#);
    }

    #[test]
    fn convert_simple_struct() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn new(inner: Inner) -> A {
        A(inner)
    }

    fn new_with_default() -> A {
        A::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.0
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn new(inner: Inner) -> A {
        A { field1: inner }
    }

    fn new_with_default() -> A {
        A::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.field1
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_referenced_via_self_kw() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn new(inner: Inner) -> Self {
        Self(inner)
    }

    fn new_with_default() -> Self {
        Self::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.0
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn new(inner: Inner) -> Self {
        Self { field1: inner }
    }

    fn new_with_default() -> Self {
        Self::new(Inner)
    }

    fn into_inner(self) -> Inner {
        self.field1
    }
}"#,
        );
    }

    #[test]
    fn convert_destructured_struct() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Inner;
struct A$0(Inner);

impl A {
    fn into_inner(self) -> Inner {
        let A(first) = self;
        first
    }

    fn into_inner_via_self(self) -> Inner {
        let Self(first) = self;
        first
    }
}"#,
            r#"
struct Inner;
struct A { field1: Inner }

impl A {
    fn into_inner(self) -> Inner {
        let A { field1: first } = self;
        first
    }

    fn into_inner_via_self(self) -> Inner {
        let Self { field1: first } = self;
        first
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_with_visibility() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct A$0(pub u32, pub(crate) u64);

impl A {
    fn new() -> A {
        A(42, 42)
    }

    fn into_first(self) -> u32 {
        self.0
    }

    fn into_second(self) -> u64 {
        self.1
    }
}"#,
            r#"
struct A { pub field1: u32, pub(crate) field2: u64 }

impl A {
    fn new() -> A {
        A { field1: 42, field2: 42 }
    }

    fn into_first(self) -> u32 {
        self.field1
    }

    fn into_second(self) -> u64 {
        self.field2
    }
}"#,
        );
    }

    #[test]
    fn convert_struct_with_where_clause() {
        check_assist(
            convert_tuple_struct_to_named_struct,
            r#"
struct Wrap$0<T>(T)
where
    T: Display;
"#,
            r#"
struct Wrap<T>
where
    T: Display,
{ field1: T }

"#,
        );
    }
}
<|endoftext|>


<commit_before>use std::io::{ Write, LineWriter, Error };
use std::result::Result;
use std::fs::File;

pub struct CodeWriter {
    target_descriptor: LineWriter<File>
}

impl CodeWriter {
    // Opens the output file, and gets ready to write into it
    pub fn new(target_file : String) -> Result<Self, Error> {
        let file = File::create(target_file)?;
        let line_writer = LineWriter::new(file);

        Ok( CodeWriter{ target_descriptor: line_writer} )
    }

    // Writes to the file assembly code which represents current arithmetic command
    pub fn write_arithmetic(&mut self, raw : &String, opcode : &String) {
        let helper_comment = format!("// {}\n", raw);
        let code = format!("opcode is {:?}\n", opcode);
        self.target_descriptor.write(&helper_comment.into_bytes());
        self.target_descriptor.write(&code.into_bytes());
    }

    // Writes assembly for push and pop commands
    pub fn write_push_pop(&mut self, raw : &String, segment : &String, index : &usize) {
        let helper_comment = format!("// {}\n", raw);
        let code = format!("segment is {:?}\n", segment);
        self.target_descriptor.write(&helper_comment.into_bytes());
        self.target_descriptor.write(&code.into_bytes());
    }
}

// Just closes the file
fn close() {

}
<commit_msg>first attemp of generating assembly for Hack CPU<commit_after>use std::io::{ Write, LineWriter, Error };
use std::result::Result;
use std::fs::File;

pub struct CodeWriter {
    target_descriptor: LineWriter<File>
}

impl CodeWriter {
    // Opens the output file, and gets ready to write into it
    pub fn new(target_file : String) -> Result<Self, Error> {
        let file = File::create(target_file)?;
        let line_writer = LineWriter::new(file);

        Ok( CodeWriter{ target_descriptor: line_writer} )
    }

    // Writes to the file assembly code which represents current arithmetic command
    pub fn write_arithmetic(&mut self, raw : &String, opcode : &String) {
        let helper_comment = format!("// {}\n", raw);
        let code = format!("opcode is {:?}\n", opcode);
        self.target_descriptor.write(&helper_comment.into_bytes());
        self.target_descriptor.write(&code.into_bytes());
    }

    // Writes assembly for push and pop commands
    pub fn write_push_pop(&mut self, raw : &String, segment : &String, index : &usize) {
        let helper_comment = format!("// {}\n", raw);
        self.target_descriptor.write(&helper_comment.into_bytes());

        let at = format!("@{}\n", index);
        self.target_descriptor.write(&at.into_bytes());

        let action = format!("D=A\n");
        self.target_descriptor.write(&action.into_bytes());

        let set_stack_pointer = format!("@SP\n");
        self.target_descriptor.write(&set_stack_pointer.into_bytes());

        let move_address_to_current_stack_pointer = format!("A=M\n");
        self.target_descriptor.write(&move_address_to_current_stack_pointer.into_bytes());

        let move_value_to_stack = format!("M=D\n");
        self.target_descriptor.write(&move_value_to_stack.into_bytes());

        let set_stack_pointer = format!("@SP\n");
        self.target_descriptor.write(&set_stack_pointer.into_bytes());

        let bump_stack_pointer = format!("M=M+1\n");
        self.target_descriptor.write(&bump_stack_pointer.into_bytes());
    }
}

// Just closes the file
fn close() {

}
<|endoftext|>


<commit_before>#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum Fixity {
    Prefix,
    Infix,
    Postfix,
}

//TODO: Move Fixity into its own module and replace these string literals with `const` declarations
impl Fixity {
    fn from_string(string: String) -> Option<Self> {
        Some(match string.as_ref() {
            "PREFIX" => Fixity::Prefix,
            "INFIX" => Fixity::Infix,
            "POSTFIX" => Fixity::Postfix,
            _ => return None,
        })
    }
}

impl ToString for Fixity {
    fn to_string(&self) -> String {
        String::from(match *self {
            Fixity::Prefix => "PREFIX",
            Fixity::Infix => "INFIX",
            Fixity::Postfix => "POSTFIX",
        })
    }
}

<commit_msg>Finished planned Fixity string refactor<commit_after>const PREFIX_STRING: &'static str = "FIXITY_PREFIX";
const INFIX_STRING: &'static str = "FIXITY_INFIX";
const POSTFIX_STRING: &'static str = "FIXITY_POSTFIX";

#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum Fixity {
    Prefix,
    Infix,
    Postfix,
}

impl Fixity {
    fn from_string(string: String) -> Option<Self> {
        Some(match string.as_ref() {
            PREFIX_STRING => Fixity::Prefix,
            INFIX_STRING => Fixity::Infix,
            POSTFIX_STRING => Fixity::Postfix,
            _ => return None,
        })
    }
}

impl ToString for Fixity {
    fn to_string(&self) -> String {
        String::from(match *self {
            Fixity::Prefix => PREFIX_STRING,
            Fixity::Infix => INFIX_STRING,
            Fixity::Postfix => POSTFIX_STRING,
        })
    }
}

<|endoftext|>


<commit_before>use ::glob;
use ::zip;
use std::fs;
use zip_info::WriteZipInfo;

/// Info Writer for multiple archive files:
pub struct MultiArchiveFlatWriter<'a> {
   path_names: &'a [String],
}

impl<'a> MultiArchiveFlatWriter<'a> {
    pub fn new(file_paths: &'a [String]) -> MultiArchiveFlatWriter<'a> {
        MultiArchiveFlatWriter { path_names: file_paths }
    }
}

impl<'a> WriteZipInfo for MultiArchiveFlatWriter<'a> {
    /// Given path names for multiple archives, concatenate their
    /// names, contents, and stats:
    fn write_zip_info(&mut self, exclude: &str) -> String {
        let mut output = Vec::new();

        for path_name in self.path_names {
            let archive_info = ZipInfoFlatWriter::new(path_name.as_str())
                .write_zip_info(exclude);

            output.push(archive_info);
        }

        output.join("\n")
    }
}

pub struct ZipInfoFlatWriter<'a> {
    archive: zip::ZipArchive<fs::File>,
    path_name: &'a str,
}

impl<'a> ZipInfoFlatWriter<'a> {
    /// Open a zip archive for this writer:
    pub fn new(file_path: &str) -> ZipInfoFlatWriter {
        let file = fs::File::open(file_path).unwrap();

        let whole_archive = zip::ZipArchive::new(file).unwrap();

        ZipInfoFlatWriter { archive: whole_archive, path_name: file_path }
    }
}

impl<'a> WriteZipInfo for ZipInfoFlatWriter<'a> {
    /// Concatenate Zip file name with indented stats for an archive:
    fn write_zip_info(&mut self, exclude: &str) -> String {
        let mut info = format!("{}", self.path_name);

        let exclude_pattern = glob::Pattern::new(exclude).unwrap();

        for i in 0..self.archive.len() {
            let archive_item = self.archive.by_index(i).unwrap();

            if !exclude_pattern.matches(archive_item.name()) {
                info = format!("{}{}", info, info_for_archive_item(archive_item));
            }
        }

        info
    }
}

fn info_for_archive_item(archive_item: zip::read::ZipFile) -> String {
    let mut info = String::new();
    let item_path = archive_item.name();
    info = format!("{}\n\t{}", info, item_path);

    let compression_type = archive_item.compression();
    info = format!("{}\n\t\tCompression type: {}", info, compression_type);

    let original_size = archive_item.size();
    info = format!("{}\n\t\tOriginal size: {}", info, original_size);

    let compressed_size = archive_item.compressed_size();
    info = format!("{}\n\t\tCompressed size: {}", info, compressed_size);

    if original_size > 0 {
        let compression_rate =
            (original_size as f64 - compressed_size as f64)
            / original_size as f64;
        let compression_perc = format!("{:.*}%", 2, compression_rate * 100.0);
        info = format!("{}\n\t\tCompression_rate: {}", info, compression_perc);
    }

    let comment = archive_item.comment();
    if comment.len() > 0 {
        info = format!("{}\n\t\tComment: {}", info, comment);
    }

    info
}
<commit_msg>Fix indent<commit_after>use ::glob;
use ::zip;
use std::fs;
use zip_info::WriteZipInfo;

/// Info Writer for multiple archive files:
pub struct MultiArchiveFlatWriter<'a> {
    path_names: &'a [String],
}

impl<'a> MultiArchiveFlatWriter<'a> {
    pub fn new(file_paths: &'a [String]) -> MultiArchiveFlatWriter<'a> {
        MultiArchiveFlatWriter { path_names: file_paths }
    }
}

impl<'a> WriteZipInfo for MultiArchiveFlatWriter<'a> {
    /// Given path names for multiple archives, concatenate their
    /// names, contents, and stats:
    fn write_zip_info(&mut self, exclude: &str) -> String {
        let mut output = Vec::new();

        for path_name in self.path_names {
            let archive_info = ZipInfoFlatWriter::new(path_name.as_str())
                .write_zip_info(exclude);

            output.push(archive_info);
        }

        output.join("\n")
    }
}

pub struct ZipInfoFlatWriter<'a> {
    archive: zip::ZipArchive<fs::File>,
    path_name: &'a str,
}

impl<'a> ZipInfoFlatWriter<'a> {
    /// Open a zip archive for this writer:
    pub fn new(file_path: &str) -> ZipInfoFlatWriter {
        let file = fs::File::open(file_path).unwrap();

        let whole_archive = zip::ZipArchive::new(file).unwrap();

        ZipInfoFlatWriter { archive: whole_archive, path_name: file_path }
    }
}

impl<'a> WriteZipInfo for ZipInfoFlatWriter<'a> {
    /// Concatenate Zip file name with indented stats for an archive:
    fn write_zip_info(&mut self, exclude: &str) -> String {
        let mut info = format!("{}", self.path_name);

        let exclude_pattern = glob::Pattern::new(exclude).unwrap();

        for i in 0..self.archive.len() {
            let archive_item = self.archive.by_index(i).unwrap();

            if !exclude_pattern.matches(archive_item.name()) {
                info = format!("{}{}", info, info_for_archive_item(archive_item));
            }
        }

        info
    }
}

fn info_for_archive_item(archive_item: zip::read::ZipFile) -> String {
    let mut info = String::new();
    let item_path = archive_item.name();
    info = format!("{}\n\t{}", info, item_path);

    let compression_type = archive_item.compression();
    info = format!("{}\n\t\tCompression type: {}", info, compression_type);

    let original_size = archive_item.size();
    info = format!("{}\n\t\tOriginal size: {}", info, original_size);

    let compressed_size = archive_item.compressed_size();
    info = format!("{}\n\t\tCompressed size: {}", info, compressed_size);

    if original_size > 0 {
        let compression_rate =
            (original_size as f64 - compressed_size as f64)
            / original_size as f64;
        let compression_perc = format!("{:.*}%", 2, compression_rate * 100.0);
        info = format!("{}\n\t\tCompression_rate: {}", info, compression_perc);
    }

    let comment = archive_item.comment();
    if comment.len() > 0 {
        info = format!("{}\n\t\tComment: {}", info, comment);
    }

    info
}
<|endoftext|>


<commit_before>#[repr(i32)]
pub enum Weight {
  Normal = 0,
  Bold = 1
}

<commit_msg>Copied documentation from Cairo for font weight<commit_after>//! Describe font weight

///  Specifies variants of a font face based on their weight.
///
/// Since 1.0i
#[repr(i32)]
pub enum Weight {
  /// Normal font weight, since 1.0
  Normal = 0,
  /// Bold font weight, since 1.0
  Bold = 1
}

<|endoftext|>


<commit_before>extern crate websocket;

use std;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use std::collections::BTreeMap;

use websocket::{Message, Sender, Receiver};
use websocket::message::Type;
use websocket::client::request::Url;

use hyper::header::{Cookie, CookieJar};

use time;

use rustc_serialize::json;
use rustc_serialize::json::Json;
use rustc_serialize::Decodable;

use game::Clock;

// making a move
// out {"t":"move","d":{"from":"e2","to":"e4","b":1}}
// in {t: "ack"}
// in {"v":1,"t":"move","d":{"uci":"e2e4","san":"e4","fen":"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR","ply":1,"clock":{"white":172800,"black":172800},"dests":{"b8":"a6c6","g8":"f6h6","h7":"h6h5","d7":"d6d5","g7":"g6g5","c7":"c6c5","f7":"f6f5","b7":"b6b5","e7":"e6e5","a7":"a6a5"},"crazyhouse":{"pockets":[{},{}]}}}
// other player moved
// in {"v":2,"t":"move","d":{"uci":"g7g5","san":"g5","fen":"rnbqkbnr/pppppp1p/8/6p1/4P3/8/PPPP1PPP/RNBQKBNR","ply":2,"clock":{"white":172800,"black":172800},"dests":{"a2":"a3a4","g1":"f3h3e2","d1":"e2f3g4h5","e1":"e2","d2":"d3d4","b1":"a3c3","e4":"e5","f1":"e2d3c4b5a6","h2":"h3h4","b2":"b3b4","f2":"f3f4","c2":"c3c4","g2":"g3g4"},"crazyhouse":{"pockets":[{},{}]}}}

enum LilaMessage {
    Move(Move),
    Clock(Clock),
}

impl LilaMessage {
    fn decode(obj: &BTreeMap<String, json::Json>) -> Option<LilaMessage> {
        fn decode<T: Decodable>(data: json::Json) -> T {
            let mut decoder = json::Decoder::new(data);
            Decodable::decode(&mut decoder).unwrap()
        }
        let data = obj.get("d");
        match (obj.get("t").and_then(|t| t.as_string()), data) {
            // TODO: gone, crowd, end, tvSelect, challenges, drop,
            // following_enters, following_leaves, following_onlines,
            // following_playing, following_stopped_plaing,
            // message, analysisProgress, reload, and more
            (Some("move"), Some(data)) => {
                Some(LilaMessage::Move(decode(data.to_owned())))
            },
            (Some("clock"), Some(data)) => {
                Some(LilaMessage::Clock(decode(data.to_owned())))
            },
            (Some(ref t), d) => {
                warn!("unhandled: {}, {:?}", t, d);
                None
            },
            _ => {
                warn!("unhandled: Missing type");
                None
            }
        }
    }

}

#[derive(RustcDecodable)]
struct Move {
    clock: Option<Clock>,
    fen: String,
}

#[derive(RustcEncodable)]
struct PingPacket {
    t: String,
    v: u64
}

impl PingPacket {
    pub fn new(version: u64) -> PingPacket {
        PingPacket {
            t: "p".to_string(),
            v: version
        }
    }

    pub fn to_message(&self) -> Message<'static> {
        Message::text(json::encode(self).unwrap())
    }
}

#[allow(dead_code)]
#[derive(RustcEncodable)]
pub struct MovePacket {
    t: String,
    d: Dest,
}

#[allow(dead_code)]
#[derive(RustcEncodable)]
pub struct Dest {
    pub from: String,
    pub to: String,
    // pub: i8, // bool, but 0 or 1
}

pub fn connect(cjar: &CookieJar, base_url: String, sri: String, pov: Arc<Mutex<super::Pov>>) {
    let url;
    let version;
    {
        let pov = pov.lock().unwrap();
        let v = match pov.player.version {
            Some(v) => v as u64,
            None => 0
        };
        url = Url::parse(&format!("ws://{}{}?sri={}&version={}", base_url, pov.url.socket.clone(), sri, v)).unwrap();
        version = Arc::new(Mutex::new(v));
    }

    // TODO: this unwrap fails when url is wrong, port for example
    let mut request = websocket::Client::connect(url).unwrap();
    request.headers.set(Cookie::from_cookie_jar(&cjar));

    let response = request.send().unwrap();

    match response.validate() {
        Ok(()) => (),
        Err(e) => {
            error!("reponse validation error: {:?}", e);
            debug!("reponse status: {:?}, headers: {:?}", response.status, response.headers);
            return;
        }
    };

    //println!("Successfully connected");

    let (mut sender, mut receiver) = response.begin().split();

    let (tx, rx) = mpsc::channel();

    let tx_1 = tx.clone();

    let _send_loop = thread::spawn(move || {
        loop {
            let message: Message = match rx.recv() {
                Ok(m) => m,
                Err(e) => {
                    error!("Send loop, could not read next message: {:?}", e);
                    return;
                }
            };
            trace!("Transmit raw: {:?}", message);
            debug!("Transmit msg: {}",
                   &std::str::from_utf8(&message.payload).unwrap());
            match message.opcode {
                Type::Close => {
                    let _ = sender.send_message(&message);
                    return;
                }
                _ => (),
            }
            match sender.send_message(&message) {
                Ok(()) => (),
                Err(e) => {
                    error!("Send loop: could not send message: {:?}", e);
                    let _ = sender.send_message(&Message::close());
                    return;
                }
            }
        }
    });

    let (pong_tx, pong_rx) = mpsc::channel();
    let pov_1 = pov.clone();
    let version_1 = version.clone();
    let _receive_loop = thread::spawn(move || {

        let handle = |obj: &BTreeMap<String, json::Json>| {
            if let (Some(v), Ok(mut version)) = (obj.get("v").and_then(|v| v.as_u64()), version_1.lock()) {
                if v <= *version {
                    debug!("Already has event {}", v);
                    return;
                } else if *version + 1 < v {
                    debug!("Event gap detected from {} to {}", *version, v);
                    return;
                }
                *version = v;
            }
            let mut pov = pov_1.lock().unwrap();
            match LilaMessage::decode(obj) {
                Some(LilaMessage::Move(m)) => {
                    pov.game.fen = m.fen;
                    if let Some(c) = m.clock {
                        pov.clock = Some(c);
                    };
                },
                Some(LilaMessage::Clock(c)) => {
                    pov.clock = Some(c);
                },
                //LilaMessage::End => tx_1.send(Message::close()).unwrap(),
                _ => ()
            };
        };

        for message in receiver.incoming_messages() {
            let message: Message = match message {
                Ok(m) => m,
                Err(e) => {
                    warn!("Receive loop error: {:?}", e);
                    let _ = tx_1.send(Message::close());
                    return;
                }
            };
            match message.opcode {
                Type::Close => {
                    let _ = tx_1.send(Message::close());
                    return;
                }
                Type::Ping => match tx_1.send(Message::pong(message.payload)) {
                    Ok(()) => (),
                    Err(e) => {
                        warn!("Could not send pong: {:?}", e);
                        return;
                    }
                },
                Type::Text => {
                    let str_payload = std::str::from_utf8(&message.payload).unwrap();
                    trace!("Received raw: {:?}", &message.payload);
                    trace!("Received str: {}", str_payload);
                    let json = Json::from_str(str_payload).unwrap();
                    debug!("Received obj: {:?}", json);
                    if json.is_object() {
                        let obj = json.as_object().unwrap();
                        match obj.get("t").and_then(|t| t.as_string()) {
                            Some("n") => pong_tx.send(()).unwrap(),
                            Some("b") => { // batch
                                let data = obj.get("d").unwrap();
                                for item in data.as_array().unwrap().iter() {
                                    let obj = item.as_object().unwrap();
                                    handle(obj);
                                }
                            },
                            _ => handle(obj)
                        }
                    }
                }
                _ => debug!("Unhandled message: {:?}", message),
            }
        }
    });

    let tx_2 = tx.clone();
    let version_2 = version.clone();
    thread::spawn(move || loop {
        thread::sleep(Duration::from_millis(2000));

        let ping;
        { ping = PingPacket::new(*version_2.lock().unwrap()).to_message(); }
        let before = time::now_utc();
        tx_2.send(ping).unwrap(); // TODO: stop pinging when socket is closed
        pong_rx.recv().unwrap();
        let after = time::now_utc();
        debug!("Ping time: {}", after-before);
    });

    //let _ = send_loop.join();
    //let _ = receive_loop.join();
}

<commit_msg>unwrap!? in my code? unthinkable, let's hide & log<commit_after>extern crate websocket;

use std;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use std::collections::BTreeMap;

use websocket::{Message, Sender, Receiver};
use websocket::message::Type;
use websocket::client::request::Url;

use hyper::header::{Cookie, CookieJar};

use time;

use rustc_serialize::json;
use rustc_serialize::json::Json;
use rustc_serialize::Decodable;

use game::Clock;

// making a move
// out {"t":"move","d":{"from":"e2","to":"e4","b":1}}
// in {t: "ack"}
// in {"v":1,"t":"move","d":{"uci":"e2e4","san":"e4","fen":"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR","ply":1,"clock":{"white":172800,"black":172800},"dests":{"b8":"a6c6","g8":"f6h6","h7":"h6h5","d7":"d6d5","g7":"g6g5","c7":"c6c5","f7":"f6f5","b7":"b6b5","e7":"e6e5","a7":"a6a5"},"crazyhouse":{"pockets":[{},{}]}}}
// other player moved
// in {"v":2,"t":"move","d":{"uci":"g7g5","san":"g5","fen":"rnbqkbnr/pppppp1p/8/6p1/4P3/8/PPPP1PPP/RNBQKBNR","ply":2,"clock":{"white":172800,"black":172800},"dests":{"a2":"a3a4","g1":"f3h3e2","d1":"e2f3g4h5","e1":"e2","d2":"d3d4","b1":"a3c3","e4":"e5","f1":"e2d3c4b5a6","h2":"h3h4","b2":"b3b4","f2":"f3f4","c2":"c3c4","g2":"g3g4"},"crazyhouse":{"pockets":[{},{}]}}}

enum LilaMessage {
    Move(Move),
    Clock(Clock),
}

impl LilaMessage {
    fn decode(obj: &BTreeMap<String, json::Json>) -> Option<LilaMessage> {
        fn decode<T: Decodable>(data: &json::Json) -> Option<T> {
            let mut decoder = json::Decoder::new(data.to_owned());
            Decodable::decode(&mut decoder)
                .map_err(|e| error!("could not decode: {}", e)).ok()
        }
        let data = obj.get("d");
        match (obj.get("t").and_then(|t| t.as_string()), data) {
            // TODO: gone, crowd, end, tvSelect, challenges, drop,
            // following_enters, following_leaves, following_onlines,
            // following_playing, following_stopped_plaing,
            // message, analysisProgress, reload, and more
            (Some("move"), Some(data)) => decode(data).map(|d| LilaMessage::Move(d)),
            (Some("clock"), Some(data)) => decode(data).map(|d| LilaMessage::Clock(d)),
            (Some(ref t), d) => {
                warn!("unhandled: {}, {:?}", t, d);
                None
            },
            _ => {
                warn!("unhandled: Missing type");
                None
            }
        }
    }

}

#[derive(RustcDecodable)]
struct Move {
    clock: Option<Clock>,
    fen: String,
}

#[derive(RustcEncodable)]
struct PingPacket {
    t: String,
    v: u64
}

impl PingPacket {
    pub fn new(version: u64) -> PingPacket {
        PingPacket {
            t: "p".to_string(),
            v: version
        }
    }

    pub fn to_message(&self) -> Message<'static> {
        Message::text(json::encode(self).unwrap())
    }
}

#[allow(dead_code)]
#[derive(RustcEncodable)]
pub struct MovePacket {
    t: String,
    d: Dest,
}

#[allow(dead_code)]
#[derive(RustcEncodable)]
pub struct Dest {
    pub from: String,
    pub to: String,
    // pub: i8, // bool, but 0 or 1
}

pub fn connect(cjar: &CookieJar, base_url: String, sri: String, pov: Arc<Mutex<super::Pov>>) {
    let url;
    let version;
    {
        let pov = pov.lock().unwrap();
        let v = match pov.player.version {
            Some(v) => v as u64,
            None => 0
        };
        url = Url::parse(&format!("ws://{}{}?sri={}&version={}", base_url, pov.url.socket.clone(), sri, v)).unwrap();
        version = Arc::new(Mutex::new(v));
    }

    // TODO: this unwrap fails when url is wrong, port for example
    let mut request = websocket::Client::connect(url).unwrap();
    request.headers.set(Cookie::from_cookie_jar(&cjar));

    let response = request.send().unwrap();

    match response.validate() {
        Ok(()) => (),
        Err(e) => {
            error!("reponse validation error: {:?}", e);
            debug!("reponse status: {:?}, headers: {:?}", response.status, response.headers);
            return;
        }
    };

    //println!("Successfully connected");

    let (mut sender, mut receiver) = response.begin().split();

    let (tx, rx) = mpsc::channel();

    let tx_1 = tx.clone();

    let _send_loop = thread::spawn(move || {
        loop {
            let message: Message = match rx.recv() {
                Ok(m) => m,
                Err(e) => {
                    error!("Send loop, could not read next message: {:?}", e);
                    return;
                }
            };
            trace!("Transmit raw: {:?}", message);
            debug!("Transmit msg: {}",
                   &std::str::from_utf8(&message.payload).unwrap());
            match message.opcode {
                Type::Close => {
                    let _ = sender.send_message(&message);
                    return;
                }
                _ => (),
            }
            match sender.send_message(&message) {
                Ok(()) => (),
                Err(e) => {
                    error!("Send loop: could not send message: {:?}", e);
                    let _ = sender.send_message(&Message::close());
                    return;
                }
            }
        }
    });

    let (pong_tx, pong_rx) = mpsc::channel();
    let pov_1 = pov.clone();
    let version_1 = version.clone();
    let _receive_loop = thread::spawn(move || {

        let handle = |obj: &BTreeMap<String, json::Json>| {
            if let (Some(v), Ok(mut version)) = (obj.get("v").and_then(|v| v.as_u64()), version_1.lock()) {
                if v <= *version {
                    debug!("Already has event {}", v);
                    return;
                } else if *version + 1 < v {
                    debug!("Event gap detected from {} to {}", *version, v);
                    return;
                }
                *version = v;
            }
            let mut pov = pov_1.lock().unwrap();
            match LilaMessage::decode(obj) {
                Some(LilaMessage::Move(m)) => {
                    pov.game.fen = m.fen;
                    if let Some(c) = m.clock {
                        pov.clock = Some(c);
                    };
                },
                Some(LilaMessage::Clock(c)) => {
                    pov.clock = Some(c);
                },
                //LilaMessage::End => tx_1.send(Message::close()).unwrap(),
                _ => ()
            };
        };

        for message in receiver.incoming_messages() {
            let message: Message = match message {
                Ok(m) => m,
                Err(e) => {
                    warn!("Receive loop error: {:?}", e);
                    let _ = tx_1.send(Message::close());
                    return;
                }
            };
            match message.opcode {
                Type::Close => {
                    let _ = tx_1.send(Message::close());
                    return;
                }
                Type::Ping => match tx_1.send(Message::pong(message.payload)) {
                    Ok(()) => (),
                    Err(e) => {
                        warn!("Could not send pong: {:?}", e);
                        return;
                    }
                },
                Type::Text => {
                    let str_payload = std::str::from_utf8(&message.payload).unwrap();
                    trace!("Received raw: {:?}", &message.payload);
                    trace!("Received str: {}", str_payload);
                    let json = Json::from_str(str_payload).unwrap();
                    debug!("Received obj: {:?}", json);
                    if json.is_object() {
                        let obj = json.as_object().unwrap();
                        match obj.get("t").and_then(|t| t.as_string()) {
                            Some("n") => pong_tx.send(()).unwrap(),
                            Some("b") => { // batch
                                let data = obj.get("d").unwrap();
                                for item in data.as_array().unwrap().iter() {
                                    let obj = item.as_object().unwrap();
                                    handle(obj);
                                }
                            },
                            _ => handle(obj)
                        }
                    }
                }
                _ => debug!("Unhandled message: {:?}", message),
            }
        }
    });

    let tx_2 = tx.clone();
    let version_2 = version.clone();
    thread::spawn(move || loop {
        thread::sleep(Duration::from_millis(2000));

        let ping;
        { ping = PingPacket::new(*version_2.lock().unwrap()).to_message(); }
        let before = time::now_utc();
        tx_2.send(ping).unwrap(); // TODO: stop pinging when socket is closed
        pong_rx.recv().unwrap();
        let after = time::now_utc();
        debug!("Ping time: {}", after-before);
    });

    //let _ = send_loop.join();
    //let _ = receive_loop.join();
}

<|endoftext|>


<commit_before>//! Protocol-related utilities
//!
//! This module contains several handlers to manage the Wayland protocol
//! and the clients.
//!
//! Most utilities provided in this module work in the same way:
//!
//! - An `init` function or method will take the event loop as argument and
//!   insert one or more globals into it.
//! - If you want to remove a previously inserted global, just call the
//!   `destroy()` method on the associated `Global`. If you don't plan to
//!   destroy the global at all, you don't need to bother keeping the
//!   `Global` around.

use std::sync::atomic::{AtomicUsize, Ordering};

pub mod compositor;
pub mod data_device;
#[cfg(feature = "backend_drm")]
pub mod dmabuf;
pub mod explicit_synchronization;
pub mod output;
pub mod seat;
pub mod shell;
pub mod shm;

/// A global [`SerialCounter`] for use in your compositor.
///
/// Is is also used internally by some parts of Smithay.
pub static SERIAL_COUNTER: SerialCounter = SerialCounter {
    serial: AtomicUsize::new(0),
};

/// A counter for generating serials, for use in the client protocol
///
/// A global instance of this counter is available as the `SERIAL_COUNTER`
/// static. It is recommended to only use this global counter to ensure the
/// uniqueness of serials.
///
/// The counter will wrap around on overflow, ensuring it can run for as long
/// as needed.
pub struct SerialCounter {
    // TODO: replace with an AtomicU32 when stabilized
    serial: AtomicUsize,
}

impl SerialCounter {
    /// Retrieve the next serial from the counter
    pub fn next_serial(&self) -> u32 {
        self.serial.fetch_add(1, Ordering::AcqRel) as u32
    }
}
<commit_msg>Implement Serial type to take wrap-around into account<commit_after>//! Protocol-related utilities
//!
//! This module contains several handlers to manage the Wayland protocol
//! and the clients.
//!
//! Most utilities provided in this module work in the same way:
//!
//! - An `init` function or method will take the event loop as argument and
//!   insert one or more globals into it.
//! - If you want to remove a previously inserted global, just call the
//!   `destroy()` method on the associated `Global`. If you don't plan to
//!   destroy the global at all, you don't need to bother keeping the
//!   `Global` around.

use std::sync::atomic::{AtomicUsize, Ordering};

pub mod compositor;
pub mod data_device;
#[cfg(feature = "backend_drm")]
pub mod dmabuf;
pub mod explicit_synchronization;
pub mod output;
pub mod seat;
pub mod shell;
pub mod shm;

/// A global [`SerialCounter`] for use in your compositor.
///
/// Is is also used internally by some parts of Smithay.
pub static SERIAL_COUNTER: SerialCounter = SerialCounter {
    serial: AtomicUsize::new(0),
};

/// A serial type, whose comparison takes into account the wrapping-around behavior of the
/// underlying counter.
#[derive(Debug, Copy, Clone)]
pub struct Serial(u32);

impl PartialEq for Serial {
    fn eq(&self, other: &Self) -> bool {
        self.0 == other.0
    }
}

impl Eq for Serial {}

impl PartialOrd for Serial {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        let distance = if self.0 > other.0 {
            self.0 - other.0
        } else {
            other.0 - self.0
        };
        if distance < u32::MAX / 2 {
            self.0.partial_cmp(&other.0)
        } else {
            // wrap-around occured, invert comparison
            other.0.partial_cmp(&self.0)
        }
    }
}

impl From<u32> for Serial {
    fn from(n: u32) -> Self {
        Serial(n)
    }
}

impl From<Serial> for u32 {
    fn from(serial: Serial) -> u32 {
        serial.0
    }
}

/// A counter for generating serials, for use in the client protocol
///
/// A global instance of this counter is available as the `SERIAL_COUNTER`
/// static. It is recommended to only use this global counter to ensure the
/// uniqueness of serials.
///
/// The counter will wrap around on overflow, ensuring it can run for as long
/// as needed.
pub struct SerialCounter {
    // TODO: replace with an AtomicU32 when stabilized
    serial: AtomicUsize,
}

impl SerialCounter {
    /// Retrieve the next serial from the counter
    pub fn next_serial(&self) -> Serial {
        Serial(self.serial.fetch_add(1, Ordering::AcqRel) as u32)
    }
}
<|endoftext|>


<commit_before>use byteorder::{ReadBytesExt, LittleEndian};
use std::io::prelude::*;
use std::io::BufReader;
use std::io::SeekFrom;
use std::fs::File;
use std::cmp::Ordering;
use utils;
use errors::Word2VecError;

/// Representation of a word vector space
///
/// Each word of a vocabulary is represented by a vector. All words span a vector space. This data
/// structure manages this vector space of words.
pub struct WordVector {
    vocabulary: Vec<(String, Vec<f32>)>,
    vector_size: usize,
}

impl WordVector {
    /// Load a word vector space from file
    ///
    /// Word2vec is able to store the word vectors in a binary file. This function parses the file
    /// and loads the vectors into RAM.
    pub fn load_from_binary(file_name: &str) -> Result<WordVector, Word2VecError> {
        let file = try!(File::open(file_name));
        let mut reader = BufReader::new(file);
        let mut header = String::new();
        try!(reader.read_line(&mut header));
        let header_info = header.split_whitespace()
            .filter_map(|x| x.parse::<usize>().ok())
            .take(2)
            .collect::<Vec<usize>>();
        if header_info.len() != 2 {
            return Err(Word2VecError::WrongHeader);
        }
        let vocabulary_size = header_info[0];
        let vector_size = header_info[1];
        let mut vocabulary: Vec<(String, Vec<f32>)> = Vec::with_capacity(vocabulary_size);
        for _ in 0..vocabulary_size {
            let mut word_bytes: Vec<u8> = Vec::new();
            try!(reader.read_until(b' ', &mut word_bytes));
            word_bytes.pop();
            let word = try!(String::from_utf8(word_bytes));
            let mut current_vector: Vec<f32> = Vec::with_capacity(vector_size);
            for _ in 0..vector_size {
                let val = try!(reader.read_f32::<LittleEndian>());
                current_vector.push(val);
            }
            utils::vector_norm(&mut current_vector);
            vocabulary.push((word, current_vector));
            try!(reader.seek(SeekFrom::Current(1)));
        }
        Ok(WordVector {
            vocabulary: vocabulary,
            vector_size: vector_size,
        })
    }

    fn get_index(&self, word: &str) -> Option<usize> {
        self.vocabulary.iter().position(|x| x.0 == word)
    }

    /// Get word vector for the given word.
    pub fn get_vector(&self, word: &str) -> Option<&Vec<f32>> {
        let index = self.get_index(word);
        match index {
            Some(val) => Some(&self.vocabulary[val].1),
            None => None,
        }
    }

    /// Compute consine distance to similar words.
    ///
    /// The words in the vector space are characterized through the position and angle to each
    /// other. This method calculates the `n` closest words via the cosine of the requested word to
    /// all other words.
    pub fn cosine(&self, word: &str, n: usize) -> Option<Vec<(String, f32)>> {
        let word_vector = self.get_vector(word);
        match word_vector {
            Some(val) => { // save index and cosine distance to current word
                let mut metrics: Vec<(usize, f32)> = Vec::with_capacity(self.vocabulary.len());
                metrics.extend(self.vocabulary.iter().enumerate().
                        map(|(i, other_val)|
                    (i, utils::dot_product(&other_val.1, val))));
                metrics.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
                Some(metrics[1..n+1].iter().map(|&(idx, dist)|
                         (self.vocabulary[idx].clone().0, dist)).collect())
            }
            None => None,
        }
    }

    pub fn analogy(&self, pos: Vec<&str>, neg: Vec<&str>, n: usize) -> Option<Vec<(String, f32)>> {
        let mut vectors: Vec<Vec<f32>> = Vec::new();
        let mut exclude: Vec<String> = Vec::new();
        for word in pos {
            exclude.push(word.to_string());
            match self.get_vector(word) {
                Some(val) => vectors.push(val.clone()),
                None => {}
            }
        }
        for word in neg.iter() {
            exclude.push(word.to_string());
            match self.get_vector(word) {
                Some(val) => vectors.push(val.iter().map(|x| -x).collect::<Vec<f32>>()),
                None => {}
            }
        }
        if exclude.is_empty() {
            return None;
        }
        let mut mean: Vec<f32> = Vec::with_capacity(self.vector_size);
        for i in 0..self.vector_size {
            mean.push(utils::mean(vectors.iter().map(|v| v[i])));
        }
        let mut metrics: Vec<(&String, f32)> = Vec::new();
        for word in self.vocabulary.iter() {
            metrics.push((&word.0, utils::dot_product(&word.1, &mean)));
        }
        metrics.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
        metrics.retain(|x| !exclude.contains(&x.0));
        Some(metrics.iter().take(n).map(|&(x,y)| (x.clone(), y)).collect())
    }

    /// Get the number of all known words from the vocabulary.
    pub fn word_count(&self) -> usize {
        self.vocabulary.len()
    }

    /// Return the number of columns of the word vector.
    pub fn get_col_count(&self) -> usize {
        self.vector_size // size == column count
    }

    /// Get all known words from the vocabulary.
    pub fn get_words<'a>(&'a self) -> Words<'a> {
        Words::new(&self.vocabulary)
    }
}

pub struct Words<'parent> {
    words: &'parent Vec<(String, Vec<f32>)>,
    index: usize,
}

impl<'a> Words<'a> {
    fn new(x: &'a Vec<(String, Vec<f32>)>) -> Words<'a> {
        Words {
            words: x,
            index: 0,
        }
    }
}

impl<'a> Iterator for Words<'a> {
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.words.len() {
            return None;
        }
        self.index += 1;
        Some(self.words[self.index - 1].0.clone())
    }
}
<commit_msg>Recognize binary vector files without line breaks<commit_after>use byteorder::{ReadBytesExt, LittleEndian};
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::cmp::Ordering;
use utils;
use errors::Word2VecError;

/// Representation of a word vector space
///
/// Each word of a vocabulary is represented by a vector. All words span a vector space. This data
/// structure manages this vector space of words.
pub struct WordVector {
    vocabulary: Vec<(String, Vec<f32>)>,
    vector_size: usize,
}

impl WordVector {
    /// Load a word vector space from file
    ///
    /// Word2vec is able to store the word vectors in a binary file. This function parses the file
    /// and loads the vectors into RAM.
    pub fn load_from_binary(file_name: &str) -> Result<WordVector, Word2VecError> {
        let file = try!(File::open(file_name));
        let mut reader = BufReader::new(file);
        let mut header = String::new();
        try!(reader.read_line(&mut header));
        let header_info = header.split_whitespace()
            .filter_map(|x| x.parse::<usize>().ok())
            .take(2)
            .collect::<Vec<usize>>();
        if header_info.len() != 2 {
            return Err(Word2VecError::WrongHeader);
        }
        let vocabulary_size = header_info[0];
        let vector_size = header_info[1];
        let mut vocabulary: Vec<(String, Vec<f32>)> = Vec::with_capacity(vocabulary_size);
        for _ in 0..vocabulary_size {
            let mut word_bytes: Vec<u8> = Vec::new();
            try!(reader.read_until(b' ', &mut word_bytes));
            // trim newlines, some vector files have newlines in front of a new word, others don't
            let word = try!(String::from_utf8(word_bytes)).trim().into();
            let mut current_vector: Vec<f32> = Vec::with_capacity(vector_size);
            for _ in 0..vector_size {
                let val = try!(reader.read_f32::<LittleEndian>());
                current_vector.push(val);
            }
            utils::vector_norm(&mut current_vector);
            vocabulary.push((word, current_vector));
        }
        Ok(WordVector {
            vocabulary: vocabulary,
            vector_size: vector_size,
        })
    }

    fn get_index(&self, word: &str) -> Option<usize> {
        self.vocabulary.iter().position(|x| x.0 == word)
    }

    /// Get word vector for the given word.
    pub fn get_vector(&self, word: &str) -> Option<&Vec<f32>> {
        let index = self.get_index(word);
        match index {
            Some(val) => Some(&self.vocabulary[val].1),
            None => None,
        }
    }

    /// Compute consine distance to similar words.
    ///
    /// The words in the vector space are characterized through the position and angle to each
    /// other. This method calculates the `n` closest words via the cosine of the requested word to
    /// all other words.
    pub fn cosine(&self, word: &str, n: usize) -> Option<Vec<(String, f32)>> {
        let word_vector = self.get_vector(word);
        match word_vector {
            Some(val) => { // save index and cosine distance to current word
                let mut metrics: Vec<(usize, f32)> = Vec::with_capacity(self.vocabulary.len());
                metrics.extend(self.vocabulary.iter().enumerate().
                        map(|(i, other_val)|
                    (i, utils::dot_product(&other_val.1, val))));
                metrics.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
                Some(metrics[1..n+1].iter().map(|&(idx, dist)|
                         (self.vocabulary[idx].clone().0, dist)).collect())
            }
            None => None,
        }
    }

    pub fn analogy(&self, pos: Vec<&str>, neg: Vec<&str>, n: usize) -> Option<Vec<(String, f32)>> {
        let mut vectors: Vec<Vec<f32>> = Vec::new();
        let mut exclude: Vec<String> = Vec::new();
        for word in pos {
            exclude.push(word.to_string());
            match self.get_vector(word) {
                Some(val) => vectors.push(val.clone()),
                None => {}
            }
        }
        for word in neg.iter() {
            exclude.push(word.to_string());
            match self.get_vector(word) {
                Some(val) => vectors.push(val.iter().map(|x| -x).collect::<Vec<f32>>()),
                None => {}
            }
        }
        if exclude.is_empty() {
            return None;
        }
        let mut mean: Vec<f32> = Vec::with_capacity(self.vector_size);
        for i in 0..self.vector_size {
            mean.push(utils::mean(vectors.iter().map(|v| v[i])));
        }
        let mut metrics: Vec<(&String, f32)> = Vec::new();
        for word in self.vocabulary.iter() {
            metrics.push((&word.0, utils::dot_product(&word.1, &mean)));
        }
        metrics.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
        metrics.retain(|x| !exclude.contains(&x.0));
        Some(metrics.iter().take(n).map(|&(x,y)| (x.clone(), y)).collect())
    }

    /// Get the number of all known words from the vocabulary.
    pub fn word_count(&self) -> usize {
        self.vocabulary.len()
    }

    /// Return the number of columns of the word vector.
    pub fn get_col_count(&self) -> usize {
        self.vector_size // size == column count
    }

    /// Get all known words from the vocabulary.
    pub fn get_words<'a>(&'a self) -> Words<'a> {
        Words::new(&self.vocabulary)
    }
}

pub struct Words<'parent> {
    words: &'parent Vec<(String, Vec<f32>)>,
    index: usize,
}

impl<'a> Words<'a> {
    fn new(x: &'a Vec<(String, Vec<f32>)>) -> Words<'a> {
        Words {
            words: x,
            index: 0,
        }
    }
}

impl<'a> Iterator for Words<'a> {
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        if self.index >= self.words.len() {
            return None;
        }
        self.index += 1;
        Some(self.words[self.index - 1].0.clone())
    }
}
<|endoftext|>