<commit_before>/**
   A parallel word-frequency counting program.

   This is meant primarily to demonstrate Rust's MapReduce framework.

   It takes a list of files on the command line and outputs a list of
   words along with how many times each word is used.

*/

use std;

import std::io;
import option = std::option::t;
import std::option::some;
import std::option::none;
import std::str;
import std::vec;
import std::map;

mod map_reduce {
    export putter;
    export getter;
    export mapper;
    export reducer;
    export map_reduce;

    type putter = fn(str, str) -> ();

    type mapper = fn(str, putter);

    type getter = fn() -> option[str];

    type reducer = fn(str, getter);

    fn map_reduce (vec[str] inputs,
                   mapper f,
                   reducer reduce) {
        auto intermediates = map::new_str_hash[vec[str]]();

        fn emit(&map::hashmap[str, vec[str]] im,
                str key, str val) {
            auto old = [];
            alt(im.remove(key)) {
                case (some(?v)) {
                    old = v;
                }
                case (none) { }
            }

            im.insert(key, old + [val]);
        }

        for (str i in inputs) {
            f(i, bind emit(intermediates, _, _));
        }

        fn get(vec[str] vals, &mutable uint i) -> option[str] {
            i += 1u;
            if(i <= vec::len(vals)) {
                some(vals.(i - 1u))
            }
            else {
                none
            }
        }

        for each (@tup(str, vec[str]) kv in intermediates.items()) {
            auto i = 0u;
            reduce(kv._0, bind get(kv._1, i));
        }
    }
}

fn main(vec[str] argv) {
    if(vec::len(argv) < 2u) {
        auto out = io::stdout();

        out.write_line(#fmt("Usage: %s <filename> ...", argv.(0)));
        fail;
    }

    fn map(str filename, map_reduce::putter emit) {
        auto f = io::file_reader(filename);

        while(true) {
            alt(read_word(f)) {
                case (some(?w)) {
                    emit(w, "1");
                }
                case (none) {
                    break;
                }
            }
        }
    }

    fn reduce(str word, map_reduce::getter get) {
        auto count = 0;

        while(true) {
            alt(get()) {
                case(some(_)) { count += 1 }
                case(none) { break }
            }
        }

        auto out = io::stdout();
        out.write_line(#fmt("%s: %d", word, count));
    }

    map_reduce::map_reduce(vec::slice(argv, 1u, vec::len(argv)), map, reduce);
}

fn read_word(io::reader r) -> option[str] {
    auto w = "";

    while(!r.eof()) {
        auto c = r.read_char();

        if(is_word_char(c)) {
            w += str::from_char(c);
        }
        else {
            if(w != "") {
                ret some(w);
            }
        }
    }
    ret none;
}

fn is_digit(char c) -> bool {
    alt(c) {
        case ('0') { true }
        case ('1') { true }
        case ('2') { true }
        case ('3') { true }
        case ('4') { true }
        case ('5') { true }
        case ('6') { true }
        case ('7') { true }
        case ('8') { true }
        case ('9') { true }
        case (_) { false }
    }
}

fn is_alpha_lower (char c) -> bool {
    alt(c) {
        case ('a') { true }
        case ('b') { true }
        case ('c') { true }
        case ('d') { true }
        case ('e') { true }
        case ('f') { true }
        case ('g') { true }
        case ('h') { true }
        case ('i') { true }
        case ('j') { true }
        case ('k') { true }
        case ('l') { true }
        case ('m') { true }
        case ('n') { true }
        case ('o') { true }
        case ('p') { true }
        case ('q') { true }
        case ('r') { true }
        case ('s') { true }
        case ('t') { true }
        case ('u') { true }
        case ('v') { true }
        case ('w') { true }
        case ('x') { true }
        case ('y') { true }
        case ('z') { true }
        case (_) { false }
    }
}

fn is_alpha_upper (char c) -> bool {
    alt(c) {
        case ('A') { true }
        case ('B') { true }
        case ('C') { true }
        case ('D') { true }
        case ('E') { true }
        case ('F') { true }
        case ('G') { true }
        case ('H') { true }
        case ('I') { true }
        case ('J') { true }
        case ('K') { true }
        case ('L') { true }
        case ('M') { true }
        case ('N') { true }
        case ('O') { true }
        case ('P') { true }
        case ('Q') { true }
        case ('R') { true }
        case ('S') { true }
        case ('T') { true }
        case ('U') { true }
        case ('V') { true }
        case ('W') { true }
        case ('X') { true }
        case ('Y') { true }
        case ('Z') { true }
        case (_) { false }
    }
}

fn is_alpha(char c) -> bool {
    is_alpha_upper(c) || is_alpha_lower(c)
}

fn is_word_char(char c) -> bool {
    is_alpha(c) || is_digit(c) || c == '_'
}<commit_msg>Task-ified the word count program.<commit_after>/**
   A parallel word-frequency counting program.

   This is meant primarily to demonstrate Rust's MapReduce framework.

   It takes a list of files on the command line and outputs a list of
   words along with how many times each word is used.

*/

use std;

import std::io;
import option = std::option::t;
import std::option::some;
import std::option::none;
import std::str;
import std::vec;
import std::map;

fn map(str filename, map_reduce::putter emit) {
    auto f = io::file_reader(filename);

    while(true) {
        alt(read_word(f)) {
            case (some(?w)) {
                emit(w, "1");
            }
            case (none) {
                break;
            }
        }
    }
}

fn reduce(str word, map_reduce::getter get) {
    auto count = 0;

    while(true) {
        alt(get()) {
            case(some(_)) { count += 1 }
            case(none) { break }
        }
    }

    auto out = io::stdout();
    out.write_line(#fmt("%s: %d", word, count));
}

mod map_reduce {
    export putter;
    export getter;
    export mapper;
    export reducer;
    export map_reduce;

    type putter = fn(str, str) -> ();

    type mapper = fn(str, putter);

    type getter = fn() -> option[str];

    type reducer = fn(str, getter);

    tag ctrl_proto {
        find_reducer(str, chan[chan[reduce_proto]]);
        mapper_done;
    }

    tag reduce_proto {
        emit_val(str);
        done;
    }

    fn start_mappers(chan[ctrl_proto] ctrl,
                     vec[str] inputs) {
        for(str i in inputs) {
            spawn map_task(ctrl, i);
        }
    }

    fn map_task(chan[ctrl_proto] ctrl,
                str input) {

        auto intermediates = map::new_str_hash();

        fn emit(&map::hashmap[str, chan[reduce_proto]] im,
                chan[ctrl_proto] ctrl,
                str key, str val) {
            auto c;
            alt(im.find(key)) {
                case(some(?_c)) {
                    c = _c
                }
                case(none) {
                    auto p = port[chan[reduce_proto]]();
                    ctrl <| find_reducer(key, chan(p));
                    p |> c;
                    im.insert(key, c);
                }
            }
            c <| emit_val(val);
        }

        map(input, bind emit(intermediates, ctrl, _, _));
        ctrl <| mapper_done;
    }

    fn reduce_task(str key, chan[chan[reduce_proto]] out) {
        auto p = port();

        out <| chan(p);

        fn get(port[reduce_proto] p) -> option[str] {
            auto m;
            p |> m;

            alt(m) {
                case(emit_val(?v)) { ret some(v); }
                case(done) { ret none; }
            }
        }

        reduce(key, bind get(p));
    }

    fn map_reduce (vec[str] inputs) {
        auto ctrl = port[ctrl_proto]();

        // This task becomes the master control task. It spawns others
        // to do the rest.

        let map::hashmap[str, chan[reduce_proto]] reducers;

        reducers = map::new_str_hash();

        start_mappers(chan(ctrl), inputs);

        auto num_mappers = vec::len(inputs) as int;

        while(num_mappers > 0) {
            auto m;
            ctrl |> m;

            alt(m) {
                case(mapper_done) { num_mappers -= 1; }
                case(find_reducer(?k, ?cc)) {
                    auto c;
                    alt(reducers.find(k)) {
                        case(some(?_c)) { c = _c; }
                        case(none) {
                            auto p = port();
                            spawn reduce_task(k, chan(p));
                            p |> c;
                            reducers.insert(k, c);
                        }
                    }
                    cc <| c;
                }
            }
        }

        for each(@tup(str, chan[reduce_proto]) kv in reducers.items()) {
            kv._1 <| done;
        }
    }
}

fn main(vec[str] argv) {
    if(vec::len(argv) < 2u) {
        auto out = io::stdout();

        out.write_line(#fmt("Usage: %s <filename> ...", argv.(0)));
        fail;
    }

    map_reduce::map_reduce(vec::slice(argv, 1u, vec::len(argv)));
}

fn read_word(io::reader r) -> option[str] {
    auto w = "";

    while(!r.eof()) {
        auto c = r.read_char();

        if(is_word_char(c)) {
            w += str::from_char(c);
        }
        else {
            if(w != "") {
                ret some(w);
            }
        }
    }
    ret none;
}

fn is_digit(char c) -> bool {
    alt(c) {
        case ('0') { true }
        case ('1') { true }
        case ('2') { true }
        case ('3') { true }
        case ('4') { true }
        case ('5') { true }
        case ('6') { true }
        case ('7') { true }
        case ('8') { true }
        case ('9') { true }
        case (_) { false }
    }
}

fn is_alpha_lower (char c) -> bool {
    alt(c) {
        case ('a') { true }
        case ('b') { true }
        case ('c') { true }
        case ('d') { true }
        case ('e') { true }
        case ('f') { true }
        case ('g') { true }
        case ('h') { true }
        case ('i') { true }
        case ('j') { true }
        case ('k') { true }
        case ('l') { true }
        case ('m') { true }
        case ('n') { true }
        case ('o') { true }
        case ('p') { true }
        case ('q') { true }
        case ('r') { true }
        case ('s') { true }
        case ('t') { true }
        case ('u') { true }
        case ('v') { true }
        case ('w') { true }
        case ('x') { true }
        case ('y') { true }
        case ('z') { true }
        case (_) { false }
    }
}

fn is_alpha_upper (char c) -> bool {
    alt(c) {
        case ('A') { true }
        case ('B') { true }
        case ('C') { true }
        case ('D') { true }
        case ('E') { true }
        case ('F') { true }
        case ('G') { true }
        case ('H') { true }
        case ('I') { true }
        case ('J') { true }
        case ('K') { true }
        case ('L') { true }
        case ('M') { true }
        case ('N') { true }
        case ('O') { true }
        case ('P') { true }
        case ('Q') { true }
        case ('R') { true }
        case ('S') { true }
        case ('T') { true }
        case ('U') { true }
        case ('V') { true }
        case ('W') { true }
        case ('X') { true }
        case ('Y') { true }
        case ('Z') { true }
        case (_) { false }
    }
}

fn is_alpha(char c) -> bool {
    is_alpha_upper(c) || is_alpha_lower(c)
}

fn is_word_char(char c) -> bool {
    is_alpha(c) || is_digit(c) || c == '_'
}<|endoftext|>


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

#[derive(PartialEq, Eq)]
struct NewBool(bool);

#[derive(PartialEq, Eq)]
enum Direction {
    North,
    East,
    South,
    West
}

#[derive(PartialEq, Eq)]
struct Foo {
    bar: Option<Direction>,
    baz: NewBool
}

#[derive(PartialEq, Eq)]
enum EnumWithStructVariants {
    Variant1(bool),
    Variant2 {
        dir: Direction
    }
}

const TRUE_TRUE: (bool, bool) = (true, true);
const NONE: Option<Direction> = None;
const EAST: Direction = Direction::East;
const NEW_FALSE: NewBool = NewBool(false);
const STATIC_FOO: Foo = Foo { bar: Some(Direction::South), baz: NEW_FALSE };
const VARIANT2_NORTH: EnumWithStructVariants = EnumWithStructVariants::Variant2 {
    dir: Direction::North };

pub mod glfw {
    #[derive(Copy, Clone, PartialEq, Eq)]
    pub struct InputState(usize);

    pub const RELEASE  : InputState = InputState(0);
    pub const PRESS    : InputState = InputState(1);
    pub const REPEAT   : InputState = InputState(2);
}

fn issue_6533() {
    use glfw;

    fn action_to_str(state: glfw::InputState) -> &'static str {
        use glfw::{RELEASE, PRESS, REPEAT};
        match state {
            RELEASE => { "Released" }
            PRESS   => { "Pressed"  }
            REPEAT  => { "Repeated" }
            _       => { "Unknown"  }
        }
    }

    assert_eq!(action_to_str(glfw::RELEASE), "Released");
    assert_eq!(action_to_str(glfw::PRESS), "Pressed");
    assert_eq!(action_to_str(glfw::REPEAT), "Repeated");
}

fn issue_13626() {
    const VAL: [u8; 1] = [0];
    match [1] {
        VAL => unreachable!(),
        _ => ()
    }
}

fn issue_14576() {
    type Foo = (i32, i32);
    const ON: Foo = (1, 1);
    const OFF: Foo = (0, 0);

    match (1, 1) {
        OFF => unreachable!(),
        ON => (),
        _ => unreachable!()
    }

    #[derive(PartialEq, Eq)]
    enum C { D = 3, E = 4 }
    const F : C = C::D;

    assert_eq!(match C::D { F => 1, _ => 2, }, 1);
}

fn issue_13731() {
    #[derive(PartialEq, Eq)]
    enum A { AA(()) }
    const B: A = A::AA(());

    match A::AA(()) {
        B => ()
    }
}

fn issue_15393() {
    #![allow(dead_code)]
    #[derive(PartialEq, Eq)]
    struct Flags {
        bits: usize
    }

    const FOO: Flags = Flags { bits: 0x01 };
    const BAR: Flags = Flags { bits: 0x02 };
    match (Flags { bits: 0x02 }) {
        FOO => unreachable!(),
        BAR => (),
        _ => unreachable!()
    }
}

fn main() {
    assert_eq!(match (true, false) {
        TRUE_TRUE => 1,
        (false, false) => 2,
        (false, true) => 3,
        (true, false) => 4
    }, 4);

    assert_eq!(match Some(Some(Direction::North)) {
        Some(NONE) => 1,
        Some(Some(Direction::North)) => 2,
        Some(Some(EAST)) => 3,
        Some(Some(Direction::South)) => 4,
        Some(Some(Direction::West)) => 5,
        None => 6
    }, 2);

    assert_eq!(match (Foo { bar: Some(Direction::West), baz: NewBool(true) }) {
        Foo { bar: None, baz: NewBool(true) } => 1,
        Foo { bar: NONE, baz: NEW_FALSE } => 2,
        STATIC_FOO => 3,
        Foo { bar: _, baz: NEW_FALSE } => 4,
        Foo { bar: Some(Direction::West), baz: NewBool(true) } => 5,
        Foo { bar: Some(Direction::South), baz: NewBool(true) } => 6,
        Foo { bar: Some(EAST), .. } => 7,
        Foo { bar: Some(Direction::North), baz: NewBool(true) } => 8
    }, 5);

    assert_eq!(match (EnumWithStructVariants::Variant2 { dir: Direction::North }) {
        EnumWithStructVariants::Variant1(true) => 1,
        EnumWithStructVariants::Variant1(false) => 2,
        EnumWithStructVariants::Variant2 { dir: Direction::West } => 3,
        VARIANT2_NORTH => 4,
        EnumWithStructVariants::Variant2 { dir: Direction::South } => 5,
        EnumWithStructVariants::Variant2 { dir: Direction::East } => 6
    }, 4);

    issue_6533();
    issue_13626();
    issue_13731();
    issue_14576();
    issue_15393();
}
<commit_msg>statics in match arm: compile with -g<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -g

#[derive(PartialEq, Eq)]
struct NewBool(bool);

#[derive(PartialEq, Eq)]
enum Direction {
    North,
    East,
    South,
    West
}

#[derive(PartialEq, Eq)]
struct Foo {
    bar: Option<Direction>,
    baz: NewBool
}

#[derive(PartialEq, Eq)]
enum EnumWithStructVariants {
    Variant1(bool),
    Variant2 {
        dir: Direction
    }
}

const TRUE_TRUE: (bool, bool) = (true, true);
const NONE: Option<Direction> = None;
const EAST: Direction = Direction::East;
const NEW_FALSE: NewBool = NewBool(false);
const STATIC_FOO: Foo = Foo { bar: Some(Direction::South), baz: NEW_FALSE };
const VARIANT2_NORTH: EnumWithStructVariants = EnumWithStructVariants::Variant2 {
    dir: Direction::North };

pub mod glfw {
    #[derive(Copy, Clone, PartialEq, Eq)]
    pub struct InputState(usize);

    pub const RELEASE  : InputState = InputState(0);
    pub const PRESS    : InputState = InputState(1);
    pub const REPEAT   : InputState = InputState(2);
}

fn issue_6533() {
    use glfw;

    fn action_to_str(state: glfw::InputState) -> &'static str {
        use glfw::{RELEASE, PRESS, REPEAT};
        match state {
            RELEASE => { "Released" }
            PRESS   => { "Pressed"  }
            REPEAT  => { "Repeated" }
            _       => { "Unknown"  }
        }
    }

    assert_eq!(action_to_str(glfw::RELEASE), "Released");
    assert_eq!(action_to_str(glfw::PRESS), "Pressed");
    assert_eq!(action_to_str(glfw::REPEAT), "Repeated");
}

fn issue_13626() {
    const VAL: [u8; 1] = [0];
    match [1] {
        VAL => unreachable!(),
        _ => ()
    }
}

fn issue_14576() {
    type Foo = (i32, i32);
    const ON: Foo = (1, 1);
    const OFF: Foo = (0, 0);

    match (1, 1) {
        OFF => unreachable!(),
        ON => (),
        _ => unreachable!()
    }

    #[derive(PartialEq, Eq)]
    enum C { D = 3, E = 4 }
    const F : C = C::D;

    assert_eq!(match C::D { F => 1, _ => 2, }, 1);
}

fn issue_13731() {
    #[derive(PartialEq, Eq)]
    enum A { AA(()) }
    const B: A = A::AA(());

    match A::AA(()) {
        B => ()
    }
}

fn issue_15393() {
    #![allow(dead_code)]
    #[derive(PartialEq, Eq)]
    struct Flags {
        bits: usize
    }

    const FOO: Flags = Flags { bits: 0x01 };
    const BAR: Flags = Flags { bits: 0x02 };
    match (Flags { bits: 0x02 }) {
        FOO => unreachable!(),
        BAR => (),
        _ => unreachable!()
    }
}

fn main() {
    assert_eq!(match (true, false) {
        TRUE_TRUE => 1,
        (false, false) => 2,
        (false, true) => 3,
        (true, false) => 4
    }, 4);

    assert_eq!(match Some(Some(Direction::North)) {
        Some(NONE) => 1,
        Some(Some(Direction::North)) => 2,
        Some(Some(EAST)) => 3,
        Some(Some(Direction::South)) => 4,
        Some(Some(Direction::West)) => 5,
        None => 6
    }, 2);

    assert_eq!(match (Foo { bar: Some(Direction::West), baz: NewBool(true) }) {
        Foo { bar: None, baz: NewBool(true) } => 1,
        Foo { bar: NONE, baz: NEW_FALSE } => 2,
        STATIC_FOO => 3,
        Foo { bar: _, baz: NEW_FALSE } => 4,
        Foo { bar: Some(Direction::West), baz: NewBool(true) } => 5,
        Foo { bar: Some(Direction::South), baz: NewBool(true) } => 6,
        Foo { bar: Some(EAST), .. } => 7,
        Foo { bar: Some(Direction::North), baz: NewBool(true) } => 8
    }, 5);

    assert_eq!(match (EnumWithStructVariants::Variant2 { dir: Direction::North }) {
        EnumWithStructVariants::Variant1(true) => 1,
        EnumWithStructVariants::Variant1(false) => 2,
        EnumWithStructVariants::Variant2 { dir: Direction::West } => 3,
        VARIANT2_NORTH => 4,
        EnumWithStructVariants::Variant2 { dir: Direction::South } => 5,
        EnumWithStructVariants::Variant2 { dir: Direction::East } => 6
    }, 4);

    issue_6533();
    issue_13626();
    issue_13731();
    issue_14576();
    issue_15393();
}
<|endoftext|>


<commit_before>use DocId;
use docset::{DocSet, SkipResult};
use postings::Postings;
use query::{Intersection, Scorer};

struct PostingsWithOffset<TPostings> {
    offset: u32,
    postings: TPostings
}

impl<TPostings: Postings> PostingsWithOffset<TPostings> {
    pub fn new(segment_postings: TPostings, offset: u32) -> PostingsWithOffset<TPostings> {
        PostingsWithOffset {
            offset,
            postings: segment_postings
        }
    }

    pub fn positions(&mut self, output: &mut Vec<u32>) {
        self.postings.positions_with_offset(self.offset, output)
    }
}

impl<TPostings: Postings> DocSet for PostingsWithOffset<TPostings> {
    fn advance(&mut self) -> bool {
        self.postings.advance()
    }

    fn skip_next(&mut self, target: DocId) -> SkipResult {
        self.postings.skip_next(target)
    }

    fn doc(&self) -> DocId {
        self.postings.doc()
    }

    fn size_hint(&self) -> u32 {
        self.postings.size_hint()
    }
}

pub struct PhraseScorer<TPostings: Postings> {
    intersection_docset: Intersection<PostingsWithOffset<TPostings>, PostingsWithOffset<TPostings>>,
    num_docsets: usize,
    left: Vec<u32>,
    right: Vec<u32>
}

fn intersection_count(left: &[u32], right: &[u32]) -> usize {
    let mut left_i = 0;
    let mut right_i = 0;
    let mut count = 0;
    while left_i < left.len() && right_i < right.len() {
        if left[left_i] < right[right_i] {
            left_i += 1;
        } else if right[right_i] < left[left_i] {
            right_i += 1;
        } else {
            count+=1;
            left_i += 1;
            right_i += 1;
        }
    }
    count
}

impl<TPostings: Postings> PhraseScorer<TPostings> {

    pub fn new(term_postings: Vec<TPostings>) -> PhraseScorer<TPostings> {
        let num_docsets = term_postings.len();
        let postings_with_offsets = term_postings
            .into_iter()
            .enumerate()
            .map(|(offset, postings)| PostingsWithOffset::new(postings, (num_docsets - offset) as u32))
            .collect::<Vec<_>>();
        PhraseScorer {
            intersection_docset: Intersection::new(postings_with_offsets),
            num_docsets,
            left: Vec::with_capacity(100),
            right: Vec::with_capacity(100)
        }
    }

    fn phrase_match(&mut self) -> bool {
        // TODO early exit when we don't care about the phrase frequency
        {
            self.intersection_docset.docset_mut_specialized(0).positions(&mut self.left);
        }
        let mut intersection_len = self.left.len();
        for i in 1..self.num_docsets {
            {
                self.intersection_docset.docset_mut_specialized(i).positions(&mut self.right);
            }
            intersection_len = intersection_count(&mut self.left[..intersection_len], &self.right[..]);
            if intersection_len == 0 {
                return false;
            }
        }
        return true;
    }
}

impl<TPostings: Postings> DocSet for PhraseScorer<TPostings> {
    fn advance(&mut self) -> bool {
        while self.intersection_docset.advance() {
            if self.phrase_match() {
                return true;
            }
        }
        false
    }

    fn skip_next(&mut self, target: DocId) -> SkipResult {
        if self.intersection_docset.skip_next(target) == SkipResult::End {
            return SkipResult::End;
        }
        if self.phrase_match() {
            if self.doc() == target {
                return SkipResult::Reached;
            } else {
                return SkipResult::OverStep;
            }
        }
        if self.advance() {
            SkipResult::OverStep
        } else {
            SkipResult::End
        }
    }

    fn doc(&self) -> DocId {
        self.intersection_docset.doc()
    }

    fn size_hint(&self) -> u32 {
        self.intersection_docset.size_hint()
    }
}

impl<TPostings: Postings> Scorer for PhraseScorer<TPostings> {
    fn score(&mut self) -> f32 {
        1f32
    }
}

#[cfg(test)]
mod tests {

    use tests;
    use test::Bencher;
    use super::intersection_count;

    #[bench]
    fn bench_intersection(b: &mut Bencher) {
        let left = tests::sample_with_seed(10, 0.1, 1);
        let right = tests::sample_with_seed(2, 0.05, 2);
        b.iter(|| {
            intersection_count(&left, &right);
        });
    }
}<commit_msg>Added<commit_after>use DocId;
use docset::{DocSet, SkipResult};
use postings::Postings;
use query::{Intersection, Scorer};

struct PostingsWithOffset<TPostings> {
    offset: u32,
    postings: TPostings
}

impl<TPostings: Postings> PostingsWithOffset<TPostings> {
    pub fn new(segment_postings: TPostings, offset: u32) -> PostingsWithOffset<TPostings> {
        PostingsWithOffset {
            offset,
            postings: segment_postings
        }
    }

    pub fn positions(&mut self, output: &mut Vec<u32>) {
        self.postings.positions_with_offset(self.offset, output)
    }
}

impl<TPostings: Postings> DocSet for PostingsWithOffset<TPostings> {
    fn advance(&mut self) -> bool {
        self.postings.advance()
    }

    fn skip_next(&mut self, target: DocId) -> SkipResult {
        self.postings.skip_next(target)
    }

    fn doc(&self) -> DocId {
        self.postings.doc()
    }

    fn size_hint(&self) -> u32 {
        self.postings.size_hint()
    }
}

pub struct PhraseScorer<TPostings: Postings> {
    intersection_docset: Intersection<PostingsWithOffset<TPostings>, PostingsWithOffset<TPostings>>,
    num_docsets: usize,
    left: Vec<u32>,
    right: Vec<u32>
}

fn intersection_count(left: &mut [u32], right: &[u32]) -> usize {
    let mut left_i = 0;
    let mut right_i = 0;
    let mut count = 0;
    while left_i < left.len() && right_i < right.len() {
        let left_val = left[left_i];
        let right_val = right[right_i];
        if left_val < right_val {
            left_i += 1;
        } else if right_val < left_val {
            right_i += 1;
        } else {
            count += 1;
            left_i += 1;
            right_i += 1;
        }
    }
    count
}

fn intersection_arr(left: &mut [u32], right: &[u32]) -> usize {
    let mut left_i = 0;
    let mut right_i = 0;
    let mut count = 0;
    let left_len = left.len();
    let right_len = right.len();
    while left_i < left_len && right_i < right_len {
        let left_val = left[left_i];
        let right_val = right[right_i];
        if left_val < right_val {
            left_i += 1;
        } else if right_val < left_val {
            right_i += 1;
        } else {
            left[count] = left_val;
            count += 1;
            left_i += 1;
            right_i += 1;
        }
    }
    count
}

impl<TPostings: Postings> PhraseScorer<TPostings> {

    pub fn new(term_postings: Vec<TPostings>) -> PhraseScorer<TPostings> {
        let num_docsets = term_postings.len();
        let postings_with_offsets = term_postings
            .into_iter()
            .enumerate()
            .map(|(offset, postings)| PostingsWithOffset::new(postings, (num_docsets - offset) as u32))
            .collect::<Vec<_>>();
        PhraseScorer {
            intersection_docset: Intersection::new(postings_with_offsets),
            num_docsets,
            left: Vec::with_capacity(100),
            right: Vec::with_capacity(100)
        }
    }

    fn phrase_match(&mut self) -> bool {
        // TODO early exit when we don't care about the phrase frequency
        {
            self.intersection_docset.docset_mut_specialized(0).positions(&mut self.left);
        }
        let mut intersection_len = self.left.len();
        for i in 1..self.num_docsets - 1 {
            {
                self.intersection_docset.docset_mut_specialized(i).positions(&mut self.right);
            }
            intersection_len = intersection_arr(&mut self.left[..intersection_len], &self.right[..]);
            if intersection_len == 0 {
                return false;
            }
        }

        self.intersection_docset.docset_mut_specialized(self.num_docsets - 1).positions(&mut self.right);
        intersection_len = intersection_count(&mut self.left[..intersection_len], &self.right[..]);
        intersection_len > 0
    }
}

impl<TPostings: Postings> DocSet for PhraseScorer<TPostings> {
    fn advance(&mut self) -> bool {
        while self.intersection_docset.advance() {
            if self.phrase_match() {
                return true;
            }
        }
        false
    }

    fn skip_next(&mut self, target: DocId) -> SkipResult {
        if self.intersection_docset.skip_next(target) == SkipResult::End {
            return SkipResult::End;
        }
        if self.phrase_match() {
            if self.doc() == target {
                return SkipResult::Reached;
            } else {
                return SkipResult::OverStep;
            }
        }
        if self.advance() {
            SkipResult::OverStep
        } else {
            SkipResult::End
        }
    }

    fn doc(&self) -> DocId {
        self.intersection_docset.doc()
    }

    fn size_hint(&self) -> u32 {
        self.intersection_docset.size_hint()
    }
}

impl<TPostings: Postings> Scorer for PhraseScorer<TPostings> {
    fn score(&mut self) -> f32 {
        1f32
    }
}

#[cfg(test)]
mod tests {

    use tests;
    use test::Bencher;
    use super::intersection_count;

    #[bench]
    fn bench_intersection(b: &mut Bencher) {
        let left = tests::sample_with_seed(10, 0.1, 1);
        let right = tests::sample_with_seed(2, 0.05, 2);
        b.iter(|| {
            intersection_count(&left, &right);
        });
    }
}<|endoftext|>


<commit_before>use std::io::Write;
use std::ops::Add;

use crate::deserialize::{self, FromSql, FromSqlRow};
use crate::expression::AsExpression;
use crate::pg::{Pg, PgValue};
use crate::serialize::{self, IsNull, Output, ToSql};
use crate::sql_types::{self, Date, Interval, Time, Timestamp, Timestamptz};

#[cfg(feature = "chrono")]
mod chrono;
#[cfg(feature = "quickcheck")]
mod quickcheck_impls;
mod std_time;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, AsExpression, FromSqlRow)]
#[sql_type = "Timestamp"]
#[sql_type = "Timestamptz"]
/// Timestamps are represented in Postgres as a 64 bit signed integer representing the number of
/// microseconds since January 1st 2000. This struct is a dumb wrapper type, meant only to indicate
/// the integer's meaning.
pub struct PgTimestamp(pub i64);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, AsExpression, FromSqlRow)]
#[sql_type = "Date"]
/// Dates are represented in Postgres as a 32 bit signed integer representing the number of julian
/// days since January 1st 2000. This struct is a dumb wrapper type, meant only to indicate the
/// integer's meaning.
pub struct PgDate(pub i32);

/// Time is represented in Postgres as a 64 bit signed integer representing the number of
/// microseconds since midnight. This struct is a dumb wrapper type, meant only to indicate the
/// integer's meaning.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, AsExpression, FromSqlRow)]
#[sql_type = "Time"]
pub struct PgTime(pub i64);

/// Intervals in Postgres are separated into 3 parts. A 64 bit integer representing time in
/// microseconds, a 32 bit integer representing number of days, and a 32 bit integer
/// representing number of months. This struct is a dumb wrapper type, meant only to indicate the
/// meaning of these parts.
#[derive(Debug, Clone, Copy, PartialEq, Eq, AsExpression, FromSqlRow)]
#[sql_type = "Interval"]
pub struct PgInterval {
    /// The number of whole microseconds
    pub microseconds: i64,
    /// The number of whole days
    pub days: i32,
    /// The number of whole months
    pub months: i32,
}

impl PgInterval {
    /// Constructs a new `PgInterval`
    ///
    /// No conversion occurs on the arguments. It is valid to provide a number
    /// of microseconds greater than the longest possible day, or a number of
    /// days greater than the longest possible month, as it is impossible to say
    /// how many months are in "40 days" without knowing a precise date.
    pub fn new(microseconds: i64, days: i32, months: i32) -> Self {
        PgInterval { microseconds, days, months }
    }

    /// Equivalent to `new(microseconds, 0, 0)`
    pub fn from_microseconds(microseconds: i64) -> Self {
        Self::new(microseconds, 0, 0)
    }

    /// Equivalent to `new(0, days, 0)`
    pub fn from_days(days: i32) -> Self {
        Self::new(0, days, 0)
    }

    /// Equivalent to `new(0, 0, months)`
    pub fn from_months(months: i32) -> Self {
        Self::new(0, 0, months)
    }
}

impl ToSql<sql_types::Timestamp, Pg> for PgTimestamp {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        ToSql::<sql_types::BigInt, Pg>::to_sql(&self.0, out)
    }
}

impl FromSql<sql_types::Timestamp, Pg> for PgTimestamp {
    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
        FromSql::<sql_types::BigInt, Pg>::from_sql(bytes).map(PgTimestamp)
    }
}

impl ToSql<sql_types::Timestamptz, Pg> for PgTimestamp {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        ToSql::<sql_types::Timestamp, Pg>::to_sql(self, out)
    }
}

impl FromSql<sql_types::Timestamptz, Pg> for PgTimestamp {
    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
        FromSql::<sql_types::Timestamp, Pg>::from_sql(bytes)
    }
}

impl ToSql<sql_types::Date, Pg> for PgDate {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        ToSql::<sql_types::Integer, Pg>::to_sql(&self.0, out)
    }
}

impl FromSql<sql_types::Date, Pg> for PgDate {
    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
        FromSql::<sql_types::Integer, Pg>::from_sql(bytes).map(PgDate)
    }
}

impl ToSql<sql_types::Time, Pg> for PgTime {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        ToSql::<sql_types::BigInt, Pg>::to_sql(&self.0, out)
    }
}

impl FromSql<sql_types::Time, Pg> for PgTime {
    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
        FromSql::<sql_types::BigInt, Pg>::from_sql(bytes).map(PgTime)
    }
}

impl ToSql<sql_types::Interval, Pg> for PgInterval {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        ToSql::<sql_types::BigInt, Pg>::to_sql(&self.microseconds, out)?;
        ToSql::<sql_types::Integer, Pg>::to_sql(&self.days, out)?;
        ToSql::<sql_types::Integer, Pg>::to_sql(&self.months, out)?;
        Ok(IsNull::No)
    }
}

impl FromSql<sql_types::Interval, Pg> for PgInterval {
    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
        Ok(PgInterval {
            microseconds: FromSql::<sql_types::BigInt, Pg>::from_sql(value.subslice(0..8))?,
            days: FromSql::<sql_types::Integer, Pg>::from_sql(value.subslice(8..12))?,
            months: FromSql::<sql_types::Integer, Pg>::from_sql(value.subslice(12..16))?,
        })
    }
}

impl Add<PgInterval> for PgInterval {
    type Output = PgInterval;

    fn add(self, other: PgInterval) -> Self::Output {
        PgInterval {
            microseconds: self.microseconds + other.microseconds,
            days: self.days + other.days,
            months: self.months + other.months,
        }
    }
}
<commit_msg>fix fmt error<commit_after>use std::io::Write;
use std::ops::Add;

use crate::deserialize::{self, FromSql, FromSqlRow};
use crate::expression::AsExpression;
use crate::pg::{Pg, PgValue};
use crate::serialize::{self, IsNull, Output, ToSql};
use crate::sql_types::{self, Date, Interval, Time, Timestamp, Timestamptz};

#[cfg(feature = "chrono")]
mod chrono;
#[cfg(feature = "quickcheck")]
mod quickcheck_impls;
mod std_time;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, AsExpression, FromSqlRow)]
#[sql_type = "Timestamp"]
#[sql_type = "Timestamptz"]
/// Timestamps are represented in Postgres as a 64 bit signed integer representing the number of
/// microseconds since January 1st 2000. This struct is a dumb wrapper type, meant only to indicate
/// the integer's meaning.
pub struct PgTimestamp(pub i64);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, AsExpression, FromSqlRow)]
#[sql_type = "Date"]
/// Dates are represented in Postgres as a 32 bit signed integer representing the number of julian
/// days since January 1st 2000. This struct is a dumb wrapper type, meant only to indicate the
/// integer's meaning.
pub struct PgDate(pub i32);

/// Time is represented in Postgres as a 64 bit signed integer representing the number of
/// microseconds since midnight. This struct is a dumb wrapper type, meant only to indicate the
/// integer's meaning.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, AsExpression, FromSqlRow)]
#[sql_type = "Time"]
pub struct PgTime(pub i64);

/// Intervals in Postgres are separated into 3 parts. A 64 bit integer representing time in
/// microseconds, a 32 bit integer representing number of days, and a 32 bit integer
/// representing number of months. This struct is a dumb wrapper type, meant only to indicate the
/// meaning of these parts.
#[derive(Debug, Clone, Copy, PartialEq, Eq, AsExpression, FromSqlRow)]
#[sql_type = "Interval"]
pub struct PgInterval {
    /// The number of whole microseconds
    pub microseconds: i64,
    /// The number of whole days
    pub days: i32,
    /// The number of whole months
    pub months: i32,
}

impl PgInterval {
    /// Constructs a new `PgInterval`
    ///
    /// No conversion occurs on the arguments. It is valid to provide a number
    /// of microseconds greater than the longest possible day, or a number of
    /// days greater than the longest possible month, as it is impossible to say
    /// how many months are in "40 days" without knowing a precise date.
    pub fn new(microseconds: i64, days: i32, months: i32) -> Self {
        PgInterval {
            microseconds,
            days,
            months,
        }
    }

    /// Equivalent to `new(microseconds, 0, 0)`
    pub fn from_microseconds(microseconds: i64) -> Self {
        Self::new(microseconds, 0, 0)
    }

    /// Equivalent to `new(0, days, 0)`
    pub fn from_days(days: i32) -> Self {
        Self::new(0, days, 0)
    }

    /// Equivalent to `new(0, 0, months)`
    pub fn from_months(months: i32) -> Self {
        Self::new(0, 0, months)
    }
}

impl ToSql<sql_types::Timestamp, Pg> for PgTimestamp {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        ToSql::<sql_types::BigInt, Pg>::to_sql(&self.0, out)
    }
}

impl FromSql<sql_types::Timestamp, Pg> for PgTimestamp {
    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
        FromSql::<sql_types::BigInt, Pg>::from_sql(bytes).map(PgTimestamp)
    }
}

impl ToSql<sql_types::Timestamptz, Pg> for PgTimestamp {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        ToSql::<sql_types::Timestamp, Pg>::to_sql(self, out)
    }
}

impl FromSql<sql_types::Timestamptz, Pg> for PgTimestamp {
    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
        FromSql::<sql_types::Timestamp, Pg>::from_sql(bytes)
    }
}

impl ToSql<sql_types::Date, Pg> for PgDate {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        ToSql::<sql_types::Integer, Pg>::to_sql(&self.0, out)
    }
}

impl FromSql<sql_types::Date, Pg> for PgDate {
    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
        FromSql::<sql_types::Integer, Pg>::from_sql(bytes).map(PgDate)
    }
}

impl ToSql<sql_types::Time, Pg> for PgTime {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        ToSql::<sql_types::BigInt, Pg>::to_sql(&self.0, out)
    }
}

impl FromSql<sql_types::Time, Pg> for PgTime {
    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
        FromSql::<sql_types::BigInt, Pg>::from_sql(bytes).map(PgTime)
    }
}

impl ToSql<sql_types::Interval, Pg> for PgInterval {
    fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
        ToSql::<sql_types::BigInt, Pg>::to_sql(&self.microseconds, out)?;
        ToSql::<sql_types::Integer, Pg>::to_sql(&self.days, out)?;
        ToSql::<sql_types::Integer, Pg>::to_sql(&self.months, out)?;
        Ok(IsNull::No)
    }
}

impl FromSql<sql_types::Interval, Pg> for PgInterval {
    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
        Ok(PgInterval {
            microseconds: FromSql::<sql_types::BigInt, Pg>::from_sql(value.subslice(0..8))?,
            days: FromSql::<sql_types::Integer, Pg>::from_sql(value.subslice(8..12))?,
            months: FromSql::<sql_types::Integer, Pg>::from_sql(value.subslice(12..16))?,
        })
    }
}

impl Add<PgInterval> for PgInterval {
    type Output = PgInterval;

    fn add(self, other: PgInterval) -> Self::Output {
        PgInterval {
            microseconds: self.microseconds + other.microseconds,
            days: self.days + other.days,
            months: self.months + other.months,
        }
    }
}
<|endoftext|>


<commit_before>use ffi::*;
use ffi::types::*;
use std::ptr::null_mut;

mod ffi;

fn main() {
    unsafe {
        run()
    }
}

macro_rules! check {
    ($name: ident ( $($arg: expr),* )) => {
        check($name( $($arg),* ), stringify!($name))
    }
}

unsafe fn run() {
    let display = GetDisplay(DEFAULT_DISPLAY as *mut _);
    assert!(!display.is_null());

    check!(Initialize(display, null_mut(), null_mut()));

    let mut num_config = -1;
    check!(GetConfigs(display, null_mut(), 0, &mut num_config));
    println!("Got {} configs", num_config);
    assert!(num_config >= 0);

    let mut configs = Vec::with_capacity(num_config as usize);
    let mut num_config2 = -1;
    check!(GetConfigs(display, configs.as_mut_ptr(), num_config, &mut num_config2));
    assert_eq!(num_config, num_config2);
    configs.set_len(num_config as usize);

    for (i, &config) in configs.iter().enumerate() {
        println!("Config #{}", i + 1);

        macro_rules! to_pairs {
            ($($name: ident)*) => {
                 &[ $( (stringify!($name), $name) ),* ]
            }
        }
        // https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglGetConfigAttrib.xhtml#description
        for &(attr_name, attr) in to_pairs! [
            ALPHA_SIZE
            ALPHA_MASK_SIZE
            BIND_TO_TEXTURE_RGB
            BIND_TO_TEXTURE_RGBA
            BLUE_SIZE
            BUFFER_SIZE
            COLOR_BUFFER_TYPE
            CONFIG_CAVEAT
            CONFIG_ID
            CONFORMANT
            DEPTH_SIZE
            GREEN_SIZE
            LEVEL
            LUMINANCE_SIZE
            MAX_PBUFFER_WIDTH
            MAX_PBUFFER_HEIGHT
            MAX_PBUFFER_PIXELS
            MAX_SWAP_INTERVAL
            MIN_SWAP_INTERVAL
            NATIVE_RENDERABLE
            NATIVE_VISUAL_ID
            NATIVE_VISUAL_TYPE
            RED_SIZE
            RENDERABLE_TYPE
            SAMPLE_BUFFERS
            SAMPLES
            STENCIL_SIZE
            SURFACE_TYPE
            TRANSPARENT_TYPE
            TRANSPARENT_RED_VALUE
            TRANSPARENT_GREEN_VALUE
            TRANSPARENT_BLUE_VALUE
        ] {
            let mut value = -1;
            check!(GetConfigAttrib(display, config, attr as i32, &mut value));
            println!("    {} = {}", attr_name, value)
        }
    }
}

unsafe fn check(result: EGLBoolean, function_name: &str) {
    check_error();
    assert_eq!(result, TRUE, "{} failed", function_name);
}

unsafe fn check_error() {
    let status = GetError();
    if status != SUCCESS as i32 {
        panic!("Error: 0x{:x}", status);
    }
}
<commit_msg>egl-configs: print hex too<commit_after>use ffi::*;
use ffi::types::*;
use std::ptr::null_mut;

mod ffi;

fn main() {
    unsafe {
        run()
    }
}

macro_rules! check {
    ($name: ident ( $($arg: expr),* )) => {
        check($name( $($arg),* ), stringify!($name))
    }
}

unsafe fn run() {
    let display = GetDisplay(DEFAULT_DISPLAY as *mut _);
    assert!(!display.is_null());

    check!(Initialize(display, null_mut(), null_mut()));

    let mut num_config = -1;
    check!(GetConfigs(display, null_mut(), 0, &mut num_config));
    println!("Got {} configs", num_config);
    assert!(num_config >= 0);

    let mut configs = Vec::with_capacity(num_config as usize);
    let mut num_config2 = -1;
    check!(GetConfigs(display, configs.as_mut_ptr(), num_config, &mut num_config2));
    assert_eq!(num_config, num_config2);
    configs.set_len(num_config as usize);

    for (i, &config) in configs.iter().enumerate() {
        println!("Config #{}", i + 1);

        macro_rules! to_pairs {
            ($($name: ident)*) => {
                 &[ $( (stringify!($name), $name) ),* ]
            }
        }
        // https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglGetConfigAttrib.xhtml#description
        for &(attr_name, attr) in to_pairs! [
            ALPHA_SIZE
            ALPHA_MASK_SIZE
            BIND_TO_TEXTURE_RGB
            BIND_TO_TEXTURE_RGBA
            BLUE_SIZE
            BUFFER_SIZE
            COLOR_BUFFER_TYPE
            CONFIG_CAVEAT
            CONFIG_ID
            CONFORMANT
            DEPTH_SIZE
            GREEN_SIZE
            LEVEL
            LUMINANCE_SIZE
            MAX_PBUFFER_WIDTH
            MAX_PBUFFER_HEIGHT
            MAX_PBUFFER_PIXELS
            MAX_SWAP_INTERVAL
            MIN_SWAP_INTERVAL
            NATIVE_RENDERABLE
            NATIVE_VISUAL_ID
            NATIVE_VISUAL_TYPE
            RED_SIZE
            RENDERABLE_TYPE
            SAMPLE_BUFFERS
            SAMPLES
            STENCIL_SIZE
            SURFACE_TYPE
            TRANSPARENT_TYPE
            TRANSPARENT_RED_VALUE
            TRANSPARENT_GREEN_VALUE
            TRANSPARENT_BLUE_VALUE
        ] {
            let mut value = -1;
            check!(GetConfigAttrib(display, config, attr as i32, &mut value));
            if value < 10 {
                println!("    {}\t = {}", attr_name, value)
            } else {
                println!("    {}\t= {} = 0x{:x}", attr_name, value, value)
            }
        }
    }
}

unsafe fn check(result: EGLBoolean, function_name: &str) {
    check_error();
    assert_eq!(result, TRUE, "{} failed", function_name);
}

unsafe fn check_error() {
    let status = GetError();
    if status != SUCCESS as i32 {
        panic!("Error: 0x{:x}", status);
    }
}
<|endoftext|>


<commit_before>use std::{run, str};

fn main() {
    test_output_multi_files_print_all_chars();
    test_stdin_squeeze();
    test_stdin_number_non_blank();
}

fn test_output_multi_files_print_all_chars() {
    let prog = run::process_output("build/cat",
                                   [~"cat/fixtures/alpha.txt", ~"cat/fixtures/256.txt",
                                    ~"-A", ~"-n"]);
    let out = str::from_utf8_owned(prog.output);
    assert_eq!(out,
               ~"     1\tabcde$\n     2\tfghij$\n     3\tklmno$\n     4\tpqrst$\n     5\tuvwxyz$\n     6\t^@^A^B^C^D^E^F^G^H^I$\n     7\t^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\\^]^^^_ !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~^?M-^@M-^AM-^BM-^CM-^DM-^EM-^FM-^GM-^HM-^IM-^JM-^KM-^LM-^MM-^NM-^OM-^PM-^QM-^RM-^SM-^TM-^UM-^VM-^WM-^XM-^YM-^ZM-^[M-^\\M-^]M-^^M-^_M- M-!M-\"M-#M-$M-%M-&M-\'M-(M-)M-*M-+M-,M--M-.M-/M-0M-1M-2M-3M-4M-5M-6M-7M-8M-9M-:M-;M-<M-=M->M-?M-@M-AM-BM-CM-DM-EM-FM-GM-HM-IM-JM-KM-LM-MM-NM-OM-PM-QM-RM-SM-TM-UM-VM-WM-XM-YM-ZM-[M-\\M-]M-^M-_M-`M-aM-bM-cM-dM-eM-fM-gM-hM-iM-jM-kM-lM-mM-nM-oM-pM-qM-rM-sM-tM-uM-vM-wM-xM-yM-zM-{M-|M-}M-~M-^?");
}

fn test_stdin_squeeze() {
    let mut prog = run::Process::new("build/cat", [~"-A"], run::ProcessOptions::new());

    prog.input().write(bytes!("\x00\x01\x02"));
    prog.close_input();

    let out = str::from_utf8_owned(prog.finish_with_output().output);
    assert_eq!(out, ~"^@^A^B");
}

fn test_stdin_number_non_blank() {
    let mut prog = run::Process::new("build/cat", [~"-b", ~"-"], run::ProcessOptions::new());

    prog.input().write(bytes!("\na\nb\n\n\nc"));
    prog.close_input();

    let out = str::from_utf8_owned(prog.finish_with_output().output);
    assert_eq!(out, ~"\n     1\ta\n     2\tb\n\n\n     3\tc");
}
<commit_msg>fix cat tests<commit_after>use std::{run, str};

#[test]
fn test_output_multi_files_print_all_chars() {
    let prog = run::process_output("build/cat",
                                   [~"cat/fixtures/alpha.txt", ~"cat/fixtures/256.txt",
                                    ~"-A", ~"-n"]).unwrap();
    let out = str::from_utf8_owned(prog.output);
    assert_eq!(out,
               ~"     1\tabcde$\n     2\tfghij$\n     3\tklmno$\n     4\tpqrst$\n     5\tuvwxyz$\n     6\t^@^A^B^C^D^E^F^G^H^I$\n     7\t^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\\^]^^^_ !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~^?M-^@M-^AM-^BM-^CM-^DM-^EM-^FM-^GM-^HM-^IM-^JM-^KM-^LM-^MM-^NM-^OM-^PM-^QM-^RM-^SM-^TM-^UM-^VM-^WM-^XM-^YM-^ZM-^[M-^\\M-^]M-^^M-^_M- M-!M-\"M-#M-$M-%M-&M-\'M-(M-)M-*M-+M-,M--M-.M-/M-0M-1M-2M-3M-4M-5M-6M-7M-8M-9M-:M-;M-<M-=M->M-?M-@M-AM-BM-CM-DM-EM-FM-GM-HM-IM-JM-KM-LM-MM-NM-OM-PM-QM-RM-SM-TM-UM-VM-WM-XM-YM-ZM-[M-\\M-]M-^M-_M-`M-aM-bM-cM-dM-eM-fM-gM-hM-iM-jM-kM-lM-mM-nM-oM-pM-qM-rM-sM-tM-uM-vM-wM-xM-yM-zM-{M-|M-}M-~M-^?");
}

#[test]
fn test_stdin_squeeze() {
    let mut prog = run::Process::new("build/cat", [~"-A"], run::ProcessOptions::new()).unwrap();

    prog.input().write(bytes!("\x00\x01\x02"));
    prog.close_input();

    let out = str::from_utf8_owned(prog.finish_with_output().output);
    assert_eq!(out, ~"^@^A^B");
}

#[test]
fn test_stdin_number_non_blank() {
    let mut prog = run::Process::new("build/cat", [~"-b", ~"-"], run::ProcessOptions::new()).unwrap();

    prog.input().write(bytes!("\na\nb\n\n\nc"));
    prog.close_input();

    let out = str::from_utf8_owned(prog.finish_with_output().output);
    assert_eq!(out, ~"\n     1\ta\n     2\tb\n\n\n     3\tc");
}
<|endoftext|>


<commit_before>fn main() {
    dbg!(encode("broood"));
    dbg!(encode("bananaaa"));
    dbg!(encode("hiphophiphop"));
}

fn get_symbols() -> Vec<u8> {
    (b'a'..b'z').collect()
}

fn encode(input: &str) -> Vec<usize> {
    input
        .as_bytes()
        .iter()
        .fold((Vec::new(), get_symbols()), |(mut o, mut s), x| {
            let i = s.iter().position(|c| c == x).unwrap();
            let c = s.remove(i);
            s.insert(0, c);
            o.push(i);
            (o, s)
        })
        .0
}
<commit_msg>add test<commit_after>fn main() {
    let examples = vec!["broood", "bananaaa", "hiphophiphop"];
    for example in examples {
        let encoded = encode(example);
        println!("{} encodes to {:?}", example, encoded);
    }
}

fn get_symbols() -> Vec<u8> {
    (b'a'..b'z').collect()
}

fn encode(input: &str) -> Vec<usize> {
    input
        .as_bytes()
        .iter()
        .fold((Vec::new(), get_symbols()), |(mut o, mut s), x| {
            let i = s.iter().position(|c| c == x).unwrap();
            let c = s.remove(i);
            s.insert(0, c);
            o.push(i);
            (o, s)
        })
        .0
}

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

    #[test]
    fn correct_encode() {
        let encoded = encode("broood");
        assert_eq!(encoded, vec![1,17,15,0,0,5]);
    }
}
<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::fmt;
use crate::model::channel::Message;
use crate::client::Context;
use crate::framework::standard::{Args, CommandOptions};
use futures::future::BoxFuture;

/// This type describes why a check has failed and occurs on
/// [`CheckResult::Failure`].
///
/// **Note**:
/// The bot-developer is supposed to process this `enum` as the framework is not.
/// It solely serves as a way to inform a user about why a check
/// has failed and for the developer to log given failure (e.g. bugs or statstics)
/// occurring in [`Check`]s.
///
/// [`Check`]: struct.Check.html
/// [`CheckResult::Failure`]: enum.CheckResult.html#variant.Failure
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum Reason {
    /// No information on the failure.
    Unknown,
    /// Information dedicated to the user.
    User(String),
    /// Information purely for logging purposes.
    Log(String),
    /// Information for the user but also for logging purposes.
    UserAndLog { user: String, log: String },
}

/// Returned from [`Check`]s.
/// If `Success`, the [`Check`] is considered as passed.
/// If `Failure`, the [`Check`] is considered as failed and can return further
/// information on the cause via [`Reason`].
///
/// [`Check`]: struct.Check.html
/// [`Reason`]: enum.Reason.html
#[derive(Clone, Debug)]
pub enum CheckResult {
   Success,
   Failure(Reason),
}

impl CheckResult {
    /// Creates a new [`CheckResult::Failure`] with [`Reason::User`].
    ///
    /// [`CheckResult::Failure`]: enum.CheckResult.html#variant.Failure
    /// [`Reason::User`]: enum.Reason.html#variant.User
    pub fn new_user<D>(d: D) -> Self
        where D: fmt::Display {
        CheckResult::Failure(Reason::User(d.to_string()))
    }

    /// Creates a new [`CheckResult::Failure`] with [`Reason::Log`].
    ///
    /// [`CheckResult::Failure`]: enum.CheckResult.html#variant.Failure
    /// [`Reason::Log`]: enum.Reason.html#variant.Log
    pub fn new_log<D>(d: D) -> Self
        where D: fmt::Display {
        CheckResult::Failure(Reason::Log(d.to_string()))
    }

    /// Creates a new [`CheckResult::Failure`] with [`Reason::Unknown`].
    ///
    /// [`CheckResult::Failure`]: enum.CheckResult.html#variant.Failure
    /// [`Reason::Unknown`]: enum.Reason.html#variant.Unknown
    pub fn new_unknown() -> Self {
        CheckResult::Failure(Reason::Unknown)
    }

    /// Creates a new [`CheckResult::Failure`] with [`Reason::UserAndLog`].
    ///
    /// [`CheckResult::Failure`]: enum.CheckResult.html#variant.Failure
    /// [`Reason::UserAndLog`]: enum.Reason.html#variant.UserAndLog
    pub fn new_user_and_log<D>(user: D, log: D) -> Self
        where D: fmt::Display {
        CheckResult::Failure(Reason::UserAndLog {
            user: user.to_string(),
            log: log.to_string(),
        })
    }

    /// Returns `true` if [`CheckResult`] is [`CheckResult::Success`] and
    /// `false` if not.
    ///
    /// [`CheckResult`]: enum.CheckResult.html
    /// [`CheckResult::Success`]: enum.CheckResult.html#variant.Success
    pub fn is_success(&self) -> bool {
        if let CheckResult::Success = self {
            return true;
        }

        false
    }
}

impl From<bool> for CheckResult {
    fn from(succeeded: bool) -> Self {
        if succeeded {
            CheckResult::Success
        } else {
            CheckResult::Failure(Reason::Unknown)
        }
    }
}

impl From<Reason> for CheckResult {
    fn from(reason: Reason) -> Self {
        CheckResult::Failure(reason)
    }
}

pub type CheckFunction = for<'fut> fn(
    &'fut Context,
    &'fut Message,
    &'fut mut Args,
    &'fut CommandOptions,
) -> BoxFuture<'fut, CheckResult>;

/// A check can be part of a command or group and will be executed to
/// determine whether a user is permitted to use related item.
///
/// Additionally, a check may hold additional settings.
pub struct Check {
    /// Name listed in help-system.
    pub name: &'static str,
    /// Function that will be executed.
    pub function: CheckFunction,
    /// Whether a check should be evaluated in the help-system.
    /// `false` will ignore check and won't fail execution.
    pub check_in_help: bool,
    /// Whether a check shall be listed in the help-system.
    /// `false` won't affect whether the check will be evaluated help,
    /// solely `check_in_help` sets this.
    pub display_in_help: bool,
}

impl Debug for Check {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Check")
            .field("name", &self.name)
            .field("function", &"<fn>")
            .field("check_in_help", &self.check_in_help)
            .field("display_in_help", &self.display_in_help)
            .finish()
    }
}

impl PartialEq for Check {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name
    }
}
<commit_msg>Fix typo in check-docs.<commit_after>use std::fmt::Debug;
use std::fmt;
use crate::model::channel::Message;
use crate::client::Context;
use crate::framework::standard::{Args, CommandOptions};
use futures::future::BoxFuture;

/// This type describes why a check has failed and occurs on
/// [`CheckResult::Failure`].
///
/// **Note**:
/// The bot-developer is supposed to process this `enum` as the framework is not.
/// It solely serves as a way to inform a user about why a check
/// has failed and for the developer to log given failure (e.g. bugs or statistics)
/// occurring in [`Check`]s.
///
/// [`Check`]: struct.Check.html
/// [`CheckResult::Failure`]: enum.CheckResult.html#variant.Failure
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum Reason {
    /// No information on the failure.
    Unknown,
    /// Information dedicated to the user.
    User(String),
    /// Information purely for logging purposes.
    Log(String),
    /// Information for the user but also for logging purposes.
    UserAndLog { user: String, log: String },
}

/// Returned from [`Check`]s.
/// If `Success`, the [`Check`] is considered as passed.
/// If `Failure`, the [`Check`] is considered as failed and can return further
/// information on the cause via [`Reason`].
///
/// [`Check`]: struct.Check.html
/// [`Reason`]: enum.Reason.html
#[derive(Clone, Debug)]
pub enum CheckResult {
   Success,
   Failure(Reason),
}

impl CheckResult {
    /// Creates a new [`CheckResult::Failure`] with [`Reason::User`].
    ///
    /// [`CheckResult::Failure`]: enum.CheckResult.html#variant.Failure
    /// [`Reason::User`]: enum.Reason.html#variant.User
    pub fn new_user<D>(d: D) -> Self
        where D: fmt::Display {
        CheckResult::Failure(Reason::User(d.to_string()))
    }

    /// Creates a new [`CheckResult::Failure`] with [`Reason::Log`].
    ///
    /// [`CheckResult::Failure`]: enum.CheckResult.html#variant.Failure
    /// [`Reason::Log`]: enum.Reason.html#variant.Log
    pub fn new_log<D>(d: D) -> Self
        where D: fmt::Display {
        CheckResult::Failure(Reason::Log(d.to_string()))
    }

    /// Creates a new [`CheckResult::Failure`] with [`Reason::Unknown`].
    ///
    /// [`CheckResult::Failure`]: enum.CheckResult.html#variant.Failure
    /// [`Reason::Unknown`]: enum.Reason.html#variant.Unknown
    pub fn new_unknown() -> Self {
        CheckResult::Failure(Reason::Unknown)
    }

    /// Creates a new [`CheckResult::Failure`] with [`Reason::UserAndLog`].
    ///
    /// [`CheckResult::Failure`]: enum.CheckResult.html#variant.Failure
    /// [`Reason::UserAndLog`]: enum.Reason.html#variant.UserAndLog
    pub fn new_user_and_log<D>(user: D, log: D) -> Self
        where D: fmt::Display {
        CheckResult::Failure(Reason::UserAndLog {
            user: user.to_string(),
            log: log.to_string(),
        })
    }

    /// Returns `true` if [`CheckResult`] is [`CheckResult::Success`] and
    /// `false` if not.
    ///
    /// [`CheckResult`]: enum.CheckResult.html
    /// [`CheckResult::Success`]: enum.CheckResult.html#variant.Success
    pub fn is_success(&self) -> bool {
        if let CheckResult::Success = self {
            return true;
        }

        false
    }
}

impl From<bool> for CheckResult {
    fn from(succeeded: bool) -> Self {
        if succeeded {
            CheckResult::Success
        } else {
            CheckResult::Failure(Reason::Unknown)
        }
    }
}

impl From<Reason> for CheckResult {
    fn from(reason: Reason) -> Self {
        CheckResult::Failure(reason)
    }
}

pub type CheckFunction = for<'fut> fn(
    &'fut Context,
    &'fut Message,
    &'fut mut Args,
    &'fut CommandOptions,
) -> BoxFuture<'fut, CheckResult>;

/// A check can be part of a command or group and will be executed to
/// determine whether a user is permitted to use related item.
///
/// Additionally, a check may hold additional settings.
pub struct Check {
    /// Name listed in help-system.
    pub name: &'static str,
    /// Function that will be executed.
    pub function: CheckFunction,
    /// Whether a check should be evaluated in the help-system.
    /// `false` will ignore check and won't fail execution.
    pub check_in_help: bool,
    /// Whether a check shall be listed in the help-system.
    /// `false` won't affect whether the check will be evaluated help,
    /// solely `check_in_help` sets this.
    pub display_in_help: bool,
}

impl Debug for Check {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Check")
            .field("name", &self.name)
            .field("function", &"<fn>")
            .field("check_in_help", &self.check_in_help)
            .field("display_in_help", &self.display_in_help)
            .finish()
    }
}

impl PartialEq for Check {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name
    }
}
<|endoftext|>


<commit_before>
use std::collections::HashMap;
use std::num::Wrapping;
use std::rc::Weak;
use std::sync::mpsc::{Sender, Receiver, TryRecvError};
use std::sync::mpsc;
use std::thread;
use std::thread::JoinHandle;
use std::time::Duration;

use serialport as sp;
use base64;

use serial_support::common::*;
use serial_support::messages::*;

/// Convenience type for a listener
/// that accepts weak refs of Senders of Serial Reponses
/// This is how the manager will communicate
/// results back to the websockets
type SubscReceiver = Receiver<Sender<SerialResponse>>;

/// Struct for containing Port information
pub struct open_port<'a> {
  /// The opened serial port
  port: &'a sp::SerialPort,
  /// Handle that controls writes to port
  write_handle: String,
  /// Send channel used to send responses to
  /// all clients who opened the port
  clients: &'a Vec<Sender<SerialResponse>>,
}

/// Manages tracking and reading/writing from serial
/// ports
struct SerialPortManager<'a> {
  /// Maintains list of ports
  open_ports: &'a mut HashMap<String, open_port<'a>>,
  /// Receiver for serial requests
  receiver: Receiver<SerialRequest>,
  /// Receiver for response subscription requests
  subsc_receiver: SubscReceiver,
}

impl<'a> SerialPortManager<'a> {
  fn open_port(&self, port: String) {
    // Check if port is already open

    // If not, open it
    let spSettings = sp::SerialPortSettings {
      baud_rate: sp::BaudRate::Baud115200,
      data_bits: sp::DataBits::Eight,
      flow_control: sp::FlowControl::None,
      parity: sp::Parity::None,
      stop_bits: sp::StopBits::One,
      timeout: Duration::from_millis(1),
    };

  }

  fn add_sender(&self, port: String, sender: Sender<SerialResponse>) {}

  fn release_write_lock(&self, handle: String, port: Option<String>) {}

  fn add_write_lock(&self, handle: String, port: String) {}

  fn write_port(&self, handle: String, port: String, data: String, base64: bool) {}

  fn close_port(&self, port: String) {}

  /// Handles and dispatches SerialRequest sent by
  /// the channel
  fn handle_serial_request(&self, msg: SerialRequest) {
    match msg {
      SerialRequest::Open { port } => self.open_port(port),
      SerialRequest::WriteLock { handle, port } => self.add_write_lock(handle, port),
      SerialRequest::ReleaseWriteLock { handle, port } => self.release_write_lock(handle, port),
      SerialRequest::Write {
        handle,
        port,
        data,
        base64,
      } => self.write_port(handle, port, data, base64.unwrap_or(false)),
      SerialRequest::Close { port } => self.close_port(port),
    }
  }

  /// Fire up the port manager
  ///
  /// TODO Right now this is spinning a thread between reading
  /// subscription requests, reading serial port data
  /// etc. This will cause high cpu usage
  ///
  /// TODO Once this is working, refactor to avoid
  /// thread spinning?
  ///
  fn run(&self) {

    let mut shutdown = false;
    let sleep_dur = Duration::from_millis(50);
    let mut serial_buf: Vec<u8> = vec![0; 4096];

    while !shutdown {
      // Sleep for a little bit to avoid pegging cpu
      thread::sleep(sleep_dur);

      // Handle serial operation requests
      match self.receiver.try_recv(){
        Err(e) => {
          match e {
            TryRecvError::Empty => {
              // nothing to do
            }
            TryRecvError::Disconnected => {
              // Remote end hung up, time to shutdown
              info!("Shutting down SerialPortManager");
            }
          }
        }
        Ok(req) => self.handle_serial_request(req)
      }

      /*
      // Check for new data on each port
      for port_name in self.open_ports.keys() {
        let open_port = self.open_ports.get(port_name).unwrap();
        // If we have data, send it back
        // Read needs to borrow &mut self, so wrap port in RC?
        let result = match open_port.port.read(serial_buf.as_mut_slice()){
          Ok(bytes_read) => {
              let bytes = &serial_buf[0..bytes_read];
              match String::from_utf8(bytes.to_vec()) {
                Err(_)=>SerialResponse::Read{
                  port:port_name.to_string(),
                  data: base64::encode(bytes),
                  base64: Some(true)
                },
                Ok(s) =>SerialResponse::Read{
                  port:port_name.to_string(),
                  data: s,
                  base64: Some(false)
                }
              }
            },
          Err(_) => SerialResponse::Error{
              kind: ErrorType::ReadError,
              msg: "Error reading serial port '{}'".to_string(),
              detail: None,
              port: Some(port_name.to_string()),
              handle:None
            }
        };
        */
        // open_port.clients.each
        // for client in open_port.clients{
        //   client.send(result.clone());
        // }
      // }

      // Check for Subscribe requests
      match self.subsc_receiver.try_recv() {
        Err(e) => {
          match e {
            TryRecvError::Empty => {
              // nothing to do
            }
            TryRecvError::Disconnected => {
              // Remote end hung up, time to shutdown
              shutdown = true;
              info!("Shutting down SerialPortManager");
            }
          }
        }
        Ok(subs) => {

        }
      }
    }
  }
}

// TODO How to spawn and fire it up
// TODO Document that closing subscription sender will result in
// portmanager shutdown.
// fn spawnManager() -> {}
<commit_msg>Lifetimes straightened out for now, base skeleton almost done<commit_after>

use std::collections::HashMap;
use std::sync::mpsc::{Sender, Receiver, TryRecvError};
use std::thread;
use std::time::Duration;

use serialport as sp;
use base64;

use serial_support::messages::*;

/// Convenience type for a listener
/// that accepts weak refs of Senders of Serial Reponses
/// This is how the manager will communicate
/// results back to the websockets
type SubscReceiver = Receiver<Sender<SerialRequest>>;

/// Struct for containing Port information
pub struct OpenPort<'a> {
  /// The opened serial port
  port: &'a mut sp::SerialPort,
  /// Handle that controls writes to port
  write_handle: String,
  /// Send channel used to send responses to
  /// all clients who opened the port
  clients: &'a mut Vec<Sender<SerialResponse>>,
}

/// Manages tracking and reading/writing from serial
/// ports
struct SerialPortManager<'a> {
  /// Maintains list of ports
  open_ports: &'a mut HashMap<String, OpenPort<'a>>,
  /// Receiver for serial requests
  receiver: Receiver<SerialRequest>,
  /// Receiver for response subscription requests
  subsc_receiver: SubscReceiver,
}

impl<'a> SerialPortManager<'a> {
  fn open_port(&self, port: String) {
    // Check if port is already open

    // If not, open it
    let sp_settings = sp::SerialPortSettings {
      baud_rate: sp::BaudRate::Baud115200,
      data_bits: sp::DataBits::Eight,
      flow_control: sp::FlowControl::None,
      parity: sp::Parity::None,
      stop_bits: sp::StopBits::One,
      timeout: Duration::from_millis(1),
    };

  }

  fn add_sender(&self, port: String, sender: Sender<SerialResponse>) {}

  fn release_write_lock(&self, handle: String, port: Option<String>) {}

  fn add_write_lock(&self, handle: String, port: String) {}

  fn write_port(&self, handle: String, port: String, data: String, base64: bool) {}

  fn close_port(&self, port: String) {}

  /// Handles and dispatches SerialRequest sent by
  /// the channel
  fn handle_serial_request(&self, msg: SerialRequest) {
    match msg {
      SerialRequest::Open { port } => self.open_port(port),
      SerialRequest::WriteLock { handle, port } => self.add_write_lock(handle, port),
      SerialRequest::ReleaseWriteLock { handle, port } => self.release_write_lock(handle, port),
      SerialRequest::Write {
        handle,
        port,
        data,
        base64,
      } => self.write_port(handle, port, data, base64.unwrap_or(false)),
      SerialRequest::Close { port } => self.close_port(port),
    }
  }

  /// Fire up the port manager
  ///
  /// TODO Right now this is spinning a thread between reading
  /// subscription requests, reading serial port data
  /// etc. This will cause high cpu usage
  ///
  /// TODO Once this is working, refactor to avoid
  /// thread spinning?
  ///
  fn run(self) {

    let mut shutdown = false;
    // Check about 30 times a second
    let sleep_dur = Duration::from_millis(33);
    let mut serial_buf: Vec<u8> = vec![0; 4096];

    while !shutdown {
      // Sleep for a little bit to avoid pegging cpu
      thread::sleep(sleep_dur);

      // Handle serial operation requests
      match self.receiver.try_recv() {
        Err(e) => {
          match e {
            TryRecvError::Empty => {
              // nothing to do
            }
            TryRecvError::Disconnected => {
              // Remote end hung up, time to shutdown
              info!("Shutting down SerialPortManager");
            }
          }
        }
        Ok(req) => self.handle_serial_request(req),
      }

      // Check for new data on each port
      for (port_name, open_port) in self.open_ports.iter_mut() {
        // If we have data, send it back
        // Read needs to borrow &mut self, so wrap port in RC?
        let result = match open_port.port.read(serial_buf.as_mut_slice()) {
          Ok(bytes_read) => {
            // We got some data
            let bytes = &serial_buf[0..bytes_read];
            // Try and parse the bytes as utf-8
            match String::from_utf8(bytes.to_vec()) {
              // We need to send as binary
              Err(_) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: base64::encode(bytes),
                  base64: Some(true),
                }
              }
              Ok(s) => {
                SerialResponse::Read {
                  port: port_name.to_string(),
                  data: s,
                  base64: Some(false),
                }
              }
            }
          }
          Err(_) => {
            // We failed to read the port, send error
            SerialResponse::Error {
              kind: ErrorType::ReadError,
              msg: "Error reading serial port '{}'".to_string(),
              detail: None,
              port: Some(port_name.to_string()),
              handle: None,
            }
          }
        };

        // Send report, retain only live connections
        open_port
          .clients
          .retain(|c| {
            c.send(result.clone())
              .map(|_| true)
              .map_err(|_| {
                         warn!("Connection closed.");
                         false
                       })
              .unwrap()
          });
      }

      // Check for Subscribe requests
      match self.subsc_receiver.try_recv() {
        Err(e) => {
          match e {
            TryRecvError::Empty => {
              // nothing to do
            }
            TryRecvError::Disconnected => {
              // Remote end hung up, time to shutdown
              shutdown = true;
              info!("Shutting down SerialPortManager");
            }
          }
        }
        Ok(sub) => {

          // We got some new subscribe requests
          // match sub {
          //   SerialRequest::Open{port} => {}
          //   SerialRequest::WriteLock{port, handle} => {}
          //   SerialRequest::ReleaseWriteLock{handle, port} => {}
          //   SerialRequest::Write{handle, port, data, base64} => {}
          //   SerialRequest::Close{port} => {}
          // }
        }
      }
    }
  }
}

// TODO How to spawn and fire it up
// TODO Document that closing subscription sender will result in
// portmanager shutdown.
// fn spawnManager() -> {}
<|endoftext|>


<commit_before><commit_msg>Cleanup survey backend<commit_after><|endoftext|>


<commit_before>use aes_ctr::stream_cipher::generic_array::GenericArray;
use aes_ctr::stream_cipher::{NewStreamCipher, SyncStreamCipher};
use aes_ctr::Aes128Ctr;
use base64;
use futures::channel::mpsc;
use futures::{Stream, StreamExt};
use hmac::{Hmac, Mac};
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response, StatusCode};
use sha1::{Digest, Sha1};

use std::borrow::Cow;
use std::net::{Ipv4Addr, SocketAddr};
use std::task::{Context, Poll};

#[cfg(feature = "with-dns-sd")]
use dns_sd::DNSService;

#[cfg(not(feature = "with-dns-sd"))]
use libmdns;

use num_bigint::BigUint;
use rand;
use std::collections::BTreeMap;
use std::io;
use std::pin::Pin;
use std::sync::Arc;
use url;

use librespot_core::authentication::Credentials;
use librespot_core::config::ConnectConfig;
use librespot_core::diffie_hellman::{DH_GENERATOR, DH_PRIME};
use librespot_core::util;

type HmacSha1 = Hmac<Sha1>;

#[derive(Clone)]
struct Discovery(Arc<DiscoveryInner>);
struct DiscoveryInner {
    config: ConnectConfig,
    device_id: String,
    private_key: BigUint,
    public_key: BigUint,
    tx: mpsc::UnboundedSender<Credentials>,
}

impl Discovery {
    fn new(
        config: ConnectConfig,
        device_id: String,
    ) -> (Discovery, mpsc::UnboundedReceiver<Credentials>) {
        let (tx, rx) = mpsc::unbounded();

        let key_data = util::rand_vec(&mut rand::thread_rng(), 95);
        let private_key = BigUint::from_bytes_be(&key_data);
        let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME);

        let discovery = Discovery(Arc::new(DiscoveryInner {
            config: config,
            device_id: device_id,
            private_key: private_key,
            public_key: public_key,
            tx: tx,
        }));

        (discovery, rx)
    }

    fn handle_get_info(&self, _: BTreeMap<Cow<'_, str>, Cow<'_, str>>) -> Response<hyper::Body> {
        let public_key = self.0.public_key.to_bytes_be();
        let public_key = base64::encode(&public_key);

        let result = json!({
            "status": 101,
            "statusString": "ERROR-OK",
            "spotifyError": 0,
            "version": "2.7.1",
            "deviceID": (self.0.device_id),
            "remoteName": (self.0.config.name),
            "activeUser": "",
            "publicKey": (public_key),
            "deviceType": (self.0.config.device_type.to_string().to_uppercase()),
            "libraryVersion": "0.1.0",
            "accountReq": "PREMIUM",
            "brandDisplayName": "librespot",
            "modelDisplayName": "librespot",
            "resolverVersion": "0",
            "groupStatus": "NONE",
            "voiceSupport": "NO",
        });

        let body = result.to_string();
        Response::new(Body::from(body))
    }

    fn handle_add_user(
        &self,
        params: BTreeMap<Cow<'_, str>, Cow<'_, str>>,
    ) -> Response<hyper::Body> {
        let username = params.get("userName").unwrap().as_ref();
        let encrypted_blob = params.get("blob").unwrap();
        let client_key = params.get("clientKey").unwrap();

        let encrypted_blob = base64::decode(encrypted_blob.as_bytes()).unwrap();

        let client_key = base64::decode(client_key.as_bytes()).unwrap();
        let client_key = BigUint::from_bytes_be(&client_key);

        let shared_key = util::powm(&client_key, &self.0.private_key, &DH_PRIME);

        let iv = &encrypted_blob[0..16];
        let encrypted = &encrypted_blob[16..encrypted_blob.len() - 20];
        let cksum = &encrypted_blob[encrypted_blob.len() - 20..encrypted_blob.len()];

        let base_key = Sha1::digest(&shared_key.to_bytes_be());
        let base_key = &base_key[..16];

        let checksum_key = {
            let mut h = HmacSha1::new_varkey(base_key).expect("HMAC can take key of any size");
            h.input(b"checksum");
            h.result().code()
        };

        let encryption_key = {
            let mut h = HmacSha1::new_varkey(&base_key).expect("HMAC can take key of any size");
            h.input(b"encryption");
            h.result().code()
        };

        let mut h = HmacSha1::new_varkey(&checksum_key).expect("HMAC can take key of any size");
        h.input(encrypted);
        if let Err(_) = h.verify(cksum) {
            warn!("Login error for user {:?}: MAC mismatch", username);
            let result = json!({
                "status": 102,
                "spotifyError": 1,
                "statusString": "ERROR-MAC"
            });

            let body = result.to_string();
            return Response::new(Body::from(body));
        }

        let decrypted = {
            let mut data = encrypted.to_vec();
            let mut cipher = Aes128Ctr::new(
                &GenericArray::from_slice(&encryption_key[0..16]),
                &GenericArray::from_slice(iv),
            );
            cipher.apply_keystream(&mut data);
            String::from_utf8(data).unwrap()
        };

        let credentials =
            Credentials::with_blob(username.to_string(), &decrypted, &self.0.device_id);

        self.0.tx.unbounded_send(credentials).unwrap();

        let result = json!({
            "status": 101,
            "spotifyError": 0,
            "statusString": "ERROR-OK"
        });

        let body = result.to_string();
        Response::new(Body::from(body))
    }

    fn not_found(&self) -> Response<hyper::Body> {
        let mut res = Response::default();
        *res.status_mut() = StatusCode::NOT_FOUND;
        res
    }

    async fn call(self, request: Request<Body>) -> hyper::Result<Response<Body>> {
        let mut params = BTreeMap::new();

        let (parts, body) = request.into_parts();

        if let Some(query) = parts.uri.query() {
            let query_params = url::form_urlencoded::parse(query.as_bytes());
            params.extend(query_params);
        }

        if parts.method != Method::GET {
            debug!("{:?} {:?} {:?}", parts.method, parts.uri.path(), params);
        }

        let body = hyper::body::to_bytes(body).await?;

        params.extend(url::form_urlencoded::parse(&body));

        Ok(
            match (parts.method, params.get("action").map(AsRef::as_ref)) {
                (Method::GET, Some("getInfo")) => self.handle_get_info(params),
                (Method::POST, Some("addUser")) => self.handle_add_user(params),
                _ => self.not_found(),
            },
        )
    }
}

#[cfg(feature = "with-dns-sd")]
pub struct DiscoveryStream {
    credentials: mpsc::UnboundedReceiver<Credentials>,
    _svc: DNSService,
}

#[cfg(not(feature = "with-dns-sd"))]
pub struct DiscoveryStream {
    credentials: mpsc::UnboundedReceiver<Credentials>,
    _svc: libmdns::Service,
}

pub fn discovery(
    config: ConnectConfig,
    device_id: String,
    port: u16,
) -> io::Result<DiscoveryStream> {
    let (discovery, creds_rx) = Discovery::new(config.clone(), device_id);

    let address = SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), port);

    let make_service = make_service_fn(move |_| {
        let discovery = discovery.clone();
        async move { Ok::<_, hyper::Error>(service_fn(move |request| discovery.clone().call(request))) }
    });

    let server = hyper::Server::bind(&address).serve(make_service);

    let s_port = server.local_addr().port();
    debug!("Zeroconf server listening on 0.0.0.0:{}", s_port);

    tokio::spawn(server);

    #[cfg(feature = "with-dns-sd")]
    let svc = DNSService::register(
        Some(&*config.name),
        "_spotify-connect._tcp",
        None,
        None,
        s_port,
        &["VERSION=1.0", "CPath=/"],
    )
    .unwrap();

    #[cfg(not(feature = "with-dns-sd"))]
    let responder = libmdns::Responder::spawn(&tokio::runtime::Handle::current())?;

    #[cfg(not(feature = "with-dns-sd"))]
    let svc = responder.register(
        "_spotify-connect._tcp".to_owned(),
        config.name,
        s_port,
        &["VERSION=1.0", "CPath=/"],
    );

    Ok(DiscoveryStream {
        credentials: creds_rx,
        _svc: svc,
    })
}

impl Stream for DiscoveryStream {
    type Item = Credentials;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        self.credentials.poll_next_unpin(cx)
    }
}
<commit_msg>Add shutdown to discovery server<commit_after>use aes_ctr::stream_cipher::generic_array::GenericArray;
use aes_ctr::stream_cipher::{NewStreamCipher, SyncStreamCipher};
use aes_ctr::Aes128Ctr;
use base64;
use futures::channel::{mpsc, oneshot};
use futures::{Stream, StreamExt};
use hmac::{Hmac, Mac};
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response, StatusCode};
use sha1::{Digest, Sha1};

use std::borrow::Cow;
use std::convert::Infallible;
use std::net::{Ipv4Addr, SocketAddr};
use std::task::{Context, Poll};

#[cfg(feature = "with-dns-sd")]
use dns_sd::DNSService;

#[cfg(not(feature = "with-dns-sd"))]
use libmdns;

use num_bigint::BigUint;
use rand;
use std::collections::BTreeMap;
use std::io;
use std::pin::Pin;
use std::sync::Arc;
use url;

use librespot_core::authentication::Credentials;
use librespot_core::config::ConnectConfig;
use librespot_core::diffie_hellman::{DH_GENERATOR, DH_PRIME};
use librespot_core::util;

type HmacSha1 = Hmac<Sha1>;

#[derive(Clone)]
struct Discovery(Arc<DiscoveryInner>);
struct DiscoveryInner {
    config: ConnectConfig,
    device_id: String,
    private_key: BigUint,
    public_key: BigUint,
    tx: mpsc::UnboundedSender<Credentials>,
}

impl Discovery {
    fn new(
        config: ConnectConfig,
        device_id: String,
    ) -> (Discovery, mpsc::UnboundedReceiver<Credentials>) {
        let (tx, rx) = mpsc::unbounded();

        let key_data = util::rand_vec(&mut rand::thread_rng(), 95);
        let private_key = BigUint::from_bytes_be(&key_data);
        let public_key = util::powm(&DH_GENERATOR, &private_key, &DH_PRIME);

        let discovery = Discovery(Arc::new(DiscoveryInner {
            config: config,
            device_id: device_id,
            private_key: private_key,
            public_key: public_key,
            tx: tx,
        }));

        (discovery, rx)
    }

    fn handle_get_info(&self, _: BTreeMap<Cow<'_, str>, Cow<'_, str>>) -> Response<hyper::Body> {
        let public_key = self.0.public_key.to_bytes_be();
        let public_key = base64::encode(&public_key);

        let result = json!({
            "status": 101,
            "statusString": "ERROR-OK",
            "spotifyError": 0,
            "version": "2.7.1",
            "deviceID": (self.0.device_id),
            "remoteName": (self.0.config.name),
            "activeUser": "",
            "publicKey": (public_key),
            "deviceType": (self.0.config.device_type.to_string().to_uppercase()),
            "libraryVersion": "0.1.0",
            "accountReq": "PREMIUM",
            "brandDisplayName": "librespot",
            "modelDisplayName": "librespot",
            "resolverVersion": "0",
            "groupStatus": "NONE",
            "voiceSupport": "NO",
        });

        let body = result.to_string();
        Response::new(Body::from(body))
    }

    fn handle_add_user(
        &self,
        params: BTreeMap<Cow<'_, str>, Cow<'_, str>>,
    ) -> Response<hyper::Body> {
        let username = params.get("userName").unwrap().as_ref();
        let encrypted_blob = params.get("blob").unwrap();
        let client_key = params.get("clientKey").unwrap();

        let encrypted_blob = base64::decode(encrypted_blob.as_bytes()).unwrap();

        let client_key = base64::decode(client_key.as_bytes()).unwrap();
        let client_key = BigUint::from_bytes_be(&client_key);

        let shared_key = util::powm(&client_key, &self.0.private_key, &DH_PRIME);

        let iv = &encrypted_blob[0..16];
        let encrypted = &encrypted_blob[16..encrypted_blob.len() - 20];
        let cksum = &encrypted_blob[encrypted_blob.len() - 20..encrypted_blob.len()];

        let base_key = Sha1::digest(&shared_key.to_bytes_be());
        let base_key = &base_key[..16];

        let checksum_key = {
            let mut h = HmacSha1::new_varkey(base_key).expect("HMAC can take key of any size");
            h.input(b"checksum");
            h.result().code()
        };

        let encryption_key = {
            let mut h = HmacSha1::new_varkey(&base_key).expect("HMAC can take key of any size");
            h.input(b"encryption");
            h.result().code()
        };

        let mut h = HmacSha1::new_varkey(&checksum_key).expect("HMAC can take key of any size");
        h.input(encrypted);
        if let Err(_) = h.verify(cksum) {
            warn!("Login error for user {:?}: MAC mismatch", username);
            let result = json!({
                "status": 102,
                "spotifyError": 1,
                "statusString": "ERROR-MAC"
            });

            let body = result.to_string();
            return Response::new(Body::from(body));
        }

        let decrypted = {
            let mut data = encrypted.to_vec();
            let mut cipher = Aes128Ctr::new(
                &GenericArray::from_slice(&encryption_key[0..16]),
                &GenericArray::from_slice(iv),
            );
            cipher.apply_keystream(&mut data);
            String::from_utf8(data).unwrap()
        };

        let credentials =
            Credentials::with_blob(username.to_string(), &decrypted, &self.0.device_id);

        self.0.tx.unbounded_send(credentials).unwrap();

        let result = json!({
            "status": 101,
            "spotifyError": 0,
            "statusString": "ERROR-OK"
        });

        let body = result.to_string();
        Response::new(Body::from(body))
    }

    fn not_found(&self) -> Response<hyper::Body> {
        let mut res = Response::default();
        *res.status_mut() = StatusCode::NOT_FOUND;
        res
    }

    async fn call(self, request: Request<Body>) -> hyper::Result<Response<Body>> {
        let mut params = BTreeMap::new();

        let (parts, body) = request.into_parts();

        if let Some(query) = parts.uri.query() {
            let query_params = url::form_urlencoded::parse(query.as_bytes());
            params.extend(query_params);
        }

        if parts.method != Method::GET {
            debug!("{:?} {:?} {:?}", parts.method, parts.uri.path(), params);
        }

        let body = hyper::body::to_bytes(body).await?;

        params.extend(url::form_urlencoded::parse(&body));

        Ok(
            match (parts.method, params.get("action").map(AsRef::as_ref)) {
                (Method::GET, Some("getInfo")) => self.handle_get_info(params),
                (Method::POST, Some("addUser")) => self.handle_add_user(params),
                _ => self.not_found(),
            },
        )
    }
}

#[cfg(feature = "with-dns-sd")]
pub struct DiscoveryStream {
    credentials: mpsc::UnboundedReceiver<Credentials>,
    _svc: DNSService,
    _close_tx: oneshot::Sender<Infallible>,
}

#[cfg(not(feature = "with-dns-sd"))]
pub struct DiscoveryStream {
    credentials: mpsc::UnboundedReceiver<Credentials>,
    _svc: libmdns::Service,
    _close_tx: oneshot::Sender<Infallible>,
}

pub fn discovery(
    config: ConnectConfig,
    device_id: String,
    port: u16,
) -> io::Result<DiscoveryStream> {
    let (discovery, creds_rx) = Discovery::new(config.clone(), device_id);
    let (close_tx, close_rx) = oneshot::channel();

    let address = SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), port);

    let make_service = make_service_fn(move |_| {
        let discovery = discovery.clone();
        async move { Ok::<_, hyper::Error>(service_fn(move |request| discovery.clone().call(request))) }
    });

    let server = hyper::Server::bind(&address).serve(make_service);

    let s_port = server.local_addr().port();
    debug!("Zeroconf server listening on 0.0.0.0:{}", s_port);

    tokio::spawn(server.with_graceful_shutdown(async {
        close_rx.await.unwrap_err();
        debug!("Shutting down discovery server");
    }));

    #[cfg(feature = "with-dns-sd")]
    let svc = DNSService::register(
        Some(&*config.name),
        "_spotify-connect._tcp",
        None,
        None,
        s_port,
        &["VERSION=1.0", "CPath=/"],
    )
    .unwrap();

    #[cfg(not(feature = "with-dns-sd"))]
    let responder = libmdns::Responder::spawn(&tokio::runtime::Handle::current())?;

    #[cfg(not(feature = "with-dns-sd"))]
    let svc = responder.register(
        "_spotify-connect._tcp".to_owned(),
        config.name,
        s_port,
        &["VERSION=1.0", "CPath=/"],
    );

    Ok(DiscoveryStream {
        credentials: creds_rx,
        _svc: svc,
        _close_tx: close_tx,
    })
}

impl Stream for DiscoveryStream {
    type Item = Credentials;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        self.credentials.poll_next_unpin(cx)
    }
}
<|endoftext|>


<commit_before>use std::{
    sync::Arc,
    hash::{Hasher, Hash},
};

use salsa;
use rustc_hash::FxHashSet;

use crate::{FileId, FileResolverImp, CrateGraph, symbol_index::SymbolIndex};

salsa::query_group! {
    pub(crate) trait FilesDatabase: salsa::Database {
        fn file_text(file_id: FileId) -> Arc<String> {
            type FileTextQuery;
            storage input;
        }
        fn file_source_root(file_id: FileId) -> SourceRootId {
            type FileSourceRootQuery;
            storage input;
        }
        fn source_root(id: SourceRootId) -> Arc<SourceRoot> {
            type SourceRootQuery;
            storage input;
        }
        fn libraries() -> Arc<Vec<SourceRootId>> {
            type LibrarieseQuery;
            storage input;
        }
        fn library_symbols(id: SourceRootId) -> Arc<SymbolIndex> {
            type LibrarySymbolsQuery;
            storage input;
        }
        fn crate_graph() -> Arc<CrateGraph> {
            type CrateGraphQuery;
            storage input;
        }
    }
}

#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub(crate) struct SourceRootId(pub(crate) u32);

#[derive(Clone, Default, Debug, Eq)]
pub(crate) struct SourceRoot {
    pub(crate) file_resolver: FileResolverImp,
    pub(crate) files: FxHashSet<FileId>,
}

impl PartialEq for SourceRoot {
    fn eq(&self, other: &SourceRoot) -> bool {
        self.file_resolver == other.file_resolver
    }
}

impl Hash for SourceRoot {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.file_resolver.hash(hasher);
    }
}

pub(crate) const WORKSPACE: SourceRootId = SourceRootId(0);
<commit_msg>Remove unneded Hash<commit_after>use std::{
    sync::Arc,
};

use salsa;
use rustc_hash::FxHashSet;

use crate::{FileId, FileResolverImp, CrateGraph, symbol_index::SymbolIndex};

salsa::query_group! {
    pub(crate) trait FilesDatabase: salsa::Database {
        fn file_text(file_id: FileId) -> Arc<String> {
            type FileTextQuery;
            storage input;
        }
        fn file_source_root(file_id: FileId) -> SourceRootId {
            type FileSourceRootQuery;
            storage input;
        }
        fn source_root(id: SourceRootId) -> Arc<SourceRoot> {
            type SourceRootQuery;
            storage input;
        }
        fn libraries() -> Arc<Vec<SourceRootId>> {
            type LibrarieseQuery;
            storage input;
        }
        fn library_symbols(id: SourceRootId) -> Arc<SymbolIndex> {
            type LibrarySymbolsQuery;
            storage input;
        }
        fn crate_graph() -> Arc<CrateGraph> {
            type CrateGraphQuery;
            storage input;
        }
    }
}

#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub(crate) struct SourceRootId(pub(crate) u32);

#[derive(Clone, Default, Debug, PartialEq, Eq)]
pub(crate) struct SourceRoot {
    pub(crate) file_resolver: FileResolverImp,
    pub(crate) files: FxHashSet<FileId>,
}

pub(crate) const WORKSPACE: SourceRootId = SourceRootId(0);
<|endoftext|>