<commit_before>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use tikv::storage::CF_LOCK;
use rocksdb::DBStatisticsTickerType;

use super::util::*;
use super::cluster::{Cluster, Simulator};
use super::server::new_server_cluster;

fn test_compact_lock_cf<T: Simulator>(cluster: &mut Cluster<T>) {
    // set lock_cf_compact_interval.
    cluster.cfg.raft_store.lock_cf_compact_interval = 1000;
    // set lock_cf_compact_threshold.
    cluster.cfg.raft_store.lock_cf_compact_threshold = 100;
    cluster.run();

    for i in 1..9 {
        let (k, v) = (format!("k{}", i), format!("value{}", i));
        cluster.must_put_cf(CF_LOCK, k.as_bytes(), v.as_bytes());
    }

    // wait for reach the lock_cf_compact_interval, but not reach
    // lock_cf_compact_threshold, so there is no compaction.
    sleep_ms(2000);

    for engine in cluster.engines.values() {
        let compact_write_bytes =
            engine.get_statistics_ticker_count(DBStatisticsTickerType::CompactWriteBytes);
        assert_eq!(compact_write_bytes, 0);
    }

    for i in 10..999 {
        let (k, v) = (format!("k{}", i), format!("value{}", i));
        cluster.must_put_cf(CF_LOCK, k.as_bytes(), v.as_bytes());
    }

    // wait for reach the lock_cf_compact_interval, and reach
    // lock_cf_compact_threshold, fire compaction.
    sleep_ms(2000);

    for engine in cluster.engines.values() {
        let compact_write_bytes =
            engine.get_statistics_ticker_count(DBStatisticsTickerType::CompactWriteBytes);
        assert!(compact_write_bytes > 0);
    }
}

#[test]
fn test_server_compact_lock_cf() {
    let count = 1;
    let mut cluster = new_server_cluster(0, count);
    test_compact_lock_cf(&mut cluster);
}
<commit_msg>tests: use a smaller interval (#1678)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use tikv::storage::CF_LOCK;
use rocksdb::DBStatisticsTickerType;

use super::util::*;
use super::cluster::{Cluster, Simulator};
use super::server::new_server_cluster;

fn test_compact_lock_cf<T: Simulator>(cluster: &mut Cluster<T>) {
    let interval = 500;
    // set lock_cf_compact_interval.
    cluster.cfg.raft_store.lock_cf_compact_interval = interval;
    // set lock_cf_compact_threshold.
    cluster.cfg.raft_store.lock_cf_compact_threshold = 100;
    cluster.run();

    for i in 1..9 {
        let (k, v) = (format!("k{}", i), format!("value{}", i));
        cluster.must_put_cf(CF_LOCK, k.as_bytes(), v.as_bytes());
    }

    // wait for reach the lock_cf_compact_interval, but not reach
    // lock_cf_compact_threshold, so there is no compaction.
    sleep_ms(interval * 2);

    for engine in cluster.engines.values() {
        let compact_write_bytes =
            engine.get_statistics_ticker_count(DBStatisticsTickerType::CompactWriteBytes);
        assert_eq!(compact_write_bytes, 0);
    }

    for i in 10..999 {
        let (k, v) = (format!("k{}", i), format!("value{}", i));
        cluster.must_put_cf(CF_LOCK, k.as_bytes(), v.as_bytes());
    }

    // wait for reach the lock_cf_compact_interval, and reach
    // lock_cf_compact_threshold, fire compaction.
    sleep_ms(interval * 2);

    for engine in cluster.engines.values() {
        let compact_write_bytes =
            engine.get_statistics_ticker_count(DBStatisticsTickerType::CompactWriteBytes);
        assert!(compact_write_bytes > 0);
    }
}

#[test]
fn test_server_compact_lock_cf() {
    let count = 1;
    let mut cluster = new_server_cluster(0, count);
    test_compact_lock_cf(&mut cluster);
}
<|endoftext|>


<commit_before>use crate::SyntaxKind;

#[derive(Clone, Copy)]
pub(crate) struct TokenSet(u128);

impl TokenSet {
    pub(crate) const fn empty() -> TokenSet {
        TokenSet(0)
    }

    pub(crate) const fn singleton(kind: SyntaxKind) -> TokenSet {
        TokenSet(mask(kind))
    }

    pub(crate) const fn union(self, other: TokenSet) -> TokenSet {
        TokenSet(self.0 | other.0)
    }

    pub(crate) fn contains(&self, kind: SyntaxKind) -> bool {
        self.0 & mask(kind) != 0
    }
}

const fn mask(kind: SyntaxKind) -> u128 {
    1u128 << (kind as usize)
}

#[macro_export]
macro_rules! token_set {
    ($($t:ident),*) => { TokenSet::empty()$(.union(TokenSet::singleton($t)))* };
    ($($t:ident),* ,) => { token_set!($($t),*) };
}

#[test]
fn token_set_works_for_tokens() {
    use crate::SyntaxKind::*;
    let ts = token_set! { EOF, SHEBANG };
    assert!(ts.contains(EOF));
    assert!(ts.contains(SHEBANG));
    assert!(!ts.contains(PLUS));
}
<commit_msg>minor<commit_after>use crate::SyntaxKind;

#[derive(Clone, Copy)]
pub(crate) struct TokenSet(u128);

impl TokenSet {
    pub(crate) const fn empty() -> TokenSet {
        TokenSet(0)
    }

    pub(crate) const fn singleton(kind: SyntaxKind) -> TokenSet {
        TokenSet(mask(kind))
    }

    pub(crate) const fn union(self, other: TokenSet) -> TokenSet {
        TokenSet(self.0 | other.0)
    }

    pub(crate) fn contains(&self, kind: SyntaxKind) -> bool {
        self.0 & mask(kind) != 0
    }
}

const fn mask(kind: SyntaxKind) -> u128 {
    1u128 << (kind as usize)
}

#[macro_export]
macro_rules! token_set {
    ($($t:ident),*) => { TokenSet::empty()$(.union(TokenSet::singleton($t)))* };
    ($($t:ident),* ,) => { token_set!($($t),*) };
}

#[test]
fn token_set_works_for_tokens() {
    use crate::SyntaxKind::*;
    let ts = token_set![EOF, SHEBANG];
    assert!(ts.contains(EOF));
    assert!(ts.contains(SHEBANG));
    assert!(!ts.contains(PLUS));
}
<|endoftext|>


<commit_before>// vim: tw=80
//! A trait with a constructor method that returns Box<Self>
#![deny(warnings)]

use mockall::*;

#[automock]
pub trait A {
    fn new() -> Box<Self>;
}

#[test]
fn returning() {
    let ctx = MockA::new_context();
    ctx.expect().returning(|| Box::new(MockA::default()));
    let _a: Box<MockA> = <MockA as A>::new();
}
<commit_msg>Clippy: fix the new box_default lint<commit_after>// vim: tw=80
//! A trait with a constructor method that returns Box<Self>
#![deny(warnings)]

use mockall::*;

#[automock]
pub trait A {
    fn new() -> Box<Self>;
}

#[test]
fn returning() {
    let ctx = MockA::new_context();
    ctx.expect().returning(Box::default);
    let _a: Box<MockA> = <MockA as A>::new();
}
<|endoftext|>


<commit_before>use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, Ty, TypeFoldable};
use rustc::mir::{Location, Body, Promoted};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
use rustc_index::vec::IndexVec;

/// Replaces all free regions appearing in the MIR with fresh
/// inference variables, returning the number of variables created.
pub fn renumber_mir<'tcx>(
    infcx: &InferCtxt<'_, 'tcx>,
    body: &mut Body<'tcx>,
    promoted: &mut IndexVec<Promoted, Body<'tcx>>,
) {
    debug!("renumber_mir()");
    debug!("renumber_mir: body.arg_count={:?}", body.arg_count);

    let mut visitor = NLLVisitor { infcx };

    for body in promoted.iter_mut() {
        visitor.visit_body(body);
    }

    visitor.visit_body(body);
}

/// Replaces all regions appearing in `value` with fresh inference
/// variables.
pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: &T) -> T
where
    T: TypeFoldable<'tcx>,
{
    debug!("renumber_regions(value={:?})", value);

    infcx
        .tcx
        .fold_regions(value, &mut false, |_region, _depth| {
            let origin = NLLRegionVariableOrigin::Existential { from_forall: false };
            infcx.next_nll_region_var(origin)
        })
}

struct NLLVisitor<'a, 'tcx> {
    infcx: &'a InferCtxt<'a, 'tcx>,
}

impl<'a, 'tcx> NLLVisitor<'a, 'tcx> {
    fn renumber_regions<T>(&mut self, value: &T) -> T
    where
        T: TypeFoldable<'tcx>,
    {
        renumber_regions(self.infcx, value)
    }
}

impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> {
    fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
        debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context);

        *ty = self.renumber_regions(ty);

        debug!("visit_ty: ty={:?}", ty);
    }

    fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
        debug!("visit_substs(substs={:?}, location={:?})", substs, location);

        *substs = self.renumber_regions(&{ *substs });

        debug!("visit_substs: substs={:?}", substs);
    }

    fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) {
        debug!("visit_region(region={:?}, location={:?})", region, location);

        let old_region = *region;
        *region = self.renumber_regions(&old_region);

        debug!("visit_region: region={:?}", region);
    }

    fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) {
        *constant = self.renumber_regions(&*constant);
    }
}
<commit_msg>Prepare renumber MutVisitor to have projections interned<commit_after>use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, Ty, TypeFoldable};
use rustc::mir::{Body, Location, Place, PlaceElem, Promoted};
use rustc::mir::visit::{MutVisitor, PlaceContext, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
use rustc_index::vec::IndexVec;

/// Replaces all free regions appearing in the MIR with fresh
/// inference variables, returning the number of variables created.
pub fn renumber_mir<'tcx>(
    infcx: &InferCtxt<'_, 'tcx>,
    body: &mut Body<'tcx>,
    promoted: &mut IndexVec<Promoted, Body<'tcx>>,
) {
    debug!("renumber_mir()");
    debug!("renumber_mir: body.arg_count={:?}", body.arg_count);

    let mut visitor = NLLVisitor { infcx };

    for body in promoted.iter_mut() {
        visitor.visit_body(body);
    }

    visitor.visit_body(body);
}

/// Replaces all regions appearing in `value` with fresh inference
/// variables.
pub fn renumber_regions<'tcx, T>(infcx: &InferCtxt<'_, 'tcx>, value: &T) -> T
where
    T: TypeFoldable<'tcx>,
{
    debug!("renumber_regions(value={:?})", value);

    infcx
        .tcx
        .fold_regions(value, &mut false, |_region, _depth| {
            let origin = NLLRegionVariableOrigin::Existential { from_forall: false };
            infcx.next_nll_region_var(origin)
        })
}

struct NLLVisitor<'a, 'tcx> {
    infcx: &'a InferCtxt<'a, 'tcx>,
}

impl<'a, 'tcx> NLLVisitor<'a, 'tcx> {
    fn renumber_regions<T>(&mut self, value: &T) -> T
    where
        T: TypeFoldable<'tcx>,
    {
        renumber_regions(self.infcx, value)
    }
}

impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> {
    fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
        debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context);

        *ty = self.renumber_regions(ty);

        debug!("visit_ty: ty={:?}", ty);
    }

    fn visit_place(
        &mut self,
        place: &mut Place<'tcx>,
        context: PlaceContext,
        location: Location,
    ) {
        self.visit_place_base(&mut place.base, context, location);

        let new_projection: Vec<_> = place.projection.iter().map(|elem|
            if let PlaceElem::Field(field, ty) = elem {
                PlaceElem::Field(*field, self.renumber_regions(ty))
            } else {
                elem.clone()
            }
        ).collect();

        place.projection = new_projection.into_boxed_slice();
    }

    fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
        debug!("visit_substs(substs={:?}, location={:?})", substs, location);

        *substs = self.renumber_regions(&{ *substs });

        debug!("visit_substs: substs={:?}", substs);
    }

    fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) {
        debug!("visit_region(region={:?}, location={:?})", region, location);

        let old_region = *region;
        *region = self.renumber_regions(&old_region);

        debug!("visit_region: region={:?}", region);
    }

    fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) {
        *constant = self.renumber_regions(&*constant);
    }
}
<|endoftext|>


<commit_before>use codespan_reporting::diagnostic::{Diagnostic, Label};
use codespan_reporting::files::SimpleFile;
use codespan_reporting::term::termcolor::StandardStream;
use codespan_reporting::term::{self, ColorArg};
use std::ops::Range;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(name = "emit")]
pub struct Opts {
    #[structopt(long = "color",
        parse(try_from_str),
        default_value = "auto",
        possible_values = ColorArg::VARIANTS,
        case_insensitive = true
    )]
    color: ColorArg,
}

fn main() -> anyhow::Result<()> {
    let file = SimpleFile::new(
        "main.rs",
        unindent::unindent(
            r#"
                fn main() {
                    let foo: i32 = "hello, world";
                    foo += 1;
                }
            "#,
        ),
    );

    let errors = [
        Error::MismatchType(
            Item::new(20..23, "i32"),
            Item::new(31..45, "\"hello, world\""),
        ),
        Error::MutatingImmutable(Item::new(20..23, "foo"), Item::new(51..59, "foo += 1")),
    ];

    // Map all errors into `Diagnostic`
    let diagnostics: Vec<Diagnostic<()>> = errors.iter().map(Error::report).collect();

    let opts = Opts::from_args();
    let writer = StandardStream::stderr(opts.color.into());
    let config = codespan_reporting::term::Config::default();
    for diagnostic in &diagnostics {
        term::emit(&mut writer.lock(), &config, &file, &diagnostic)?;
    }

    Ok(())
}

/// An error enum that represent all possible errors within your program
enum Error {
    MismatchType(Item, Item),
    MutatingImmutable(Item, Item),
}

impl Error {
    fn report(&self) -> Diagnostic<()> {
        match self {
            Error::MismatchType(left, right) => Diagnostic::error()
                .with_code("E0308")
                .with_message("mismatch types")
                .with_labels(vec![
                    Label::primary((), right.range.clone()).with_message(format!(
                        "Expected `{}`, found: `{}`",
                        left.content, right.content
                    )),
                    Label::secondary((), left.range.clone()).with_message("expected due to this"),
                ]),
            Error::MutatingImmutable(original, mutating) => Diagnostic::error()
                .with_code("E0384")
                .with_message(format!(
                    "cannot mutate immutable variable `{}`",
                    original.content
                ))
                .with_labels(vec![
                    Label::secondary((), original.range.clone()).with_message(unindent::unindent(
                        &format!(
                            r#"
                                    first assignment to `{0}`
                                    help: make this binding mutable: `mut {0}`
                                "#,
                            original.content
                        ),
                    )),
                    Label::primary((), mutating.range.clone())
                        .with_message("cannot assign twice to immutable variable"),
                ]),
        }
    }
}

/// Representing a single error point in `Error` enum
/// In a more complex program it could also contain `FileId` to handle error that occurs inside multiple files
struct Item {
    range: Range<usize>,
    content: String,
}

impl Item {
    fn new(range: Range<usize>, content: impl Into<String>) -> Item {
        let content = content.into();
        Item { range, content }
    }
}
<commit_msg>Grammar<commit_after>use codespan_reporting::diagnostic::{Diagnostic, Label};
use codespan_reporting::files::SimpleFile;
use codespan_reporting::term::termcolor::StandardStream;
use codespan_reporting::term::{self, ColorArg};
use std::ops::Range;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
#[structopt(name = "emit")]
pub struct Opts {
    #[structopt(long = "color",
        parse(try_from_str),
        default_value = "auto",
        possible_values = ColorArg::VARIANTS,
        case_insensitive = true
    )]
    color: ColorArg,
}

fn main() -> anyhow::Result<()> {
    let file = SimpleFile::new(
        "main.rs",
        unindent::unindent(
            r#"
                fn main() {
                    let foo: i32 = "hello, world";
                    foo += 1;
                }
            "#,
        ),
    );

    let errors = [
        Error::MismatchType(
            Item::new(20..23, "i32"),
            Item::new(31..45, "\"hello, world\""),
        ),
        Error::MutatingImmutable(Item::new(20..23, "foo"), Item::new(51..59, "foo += 1")),
    ];

    // Map all errors into `Diagnostic`
    let diagnostics: Vec<Diagnostic<()>> = errors.iter().map(Error::report).collect();

    let opts = Opts::from_args();
    let writer = StandardStream::stderr(opts.color.into());
    let config = codespan_reporting::term::Config::default();
    for diagnostic in &diagnostics {
        term::emit(&mut writer.lock(), &config, &file, &diagnostic)?;
    }

    Ok(())
}

/// An error enum that represent all possible errors within your program
enum Error {
    MismatchType(Item, Item),
    MutatingImmutable(Item, Item),
}

impl Error {
    fn report(&self) -> Diagnostic<()> {
        match self {
            Error::MismatchType(left, right) => Diagnostic::error()
                .with_code("E0308")
                .with_message("mismatch types")
                .with_labels(vec![
                    Label::primary((), right.range.clone()).with_message(format!(
                        "Expected `{}`, found: `{}`",
                        left.content, right.content
                    )),
                    Label::secondary((), left.range.clone()).with_message("expected due to this"),
                ]),
            Error::MutatingImmutable(original, mutating) => Diagnostic::error()
                .with_code("E0384")
                .with_message(format!(
                    "cannot mutate immutable variable `{}`",
                    original.content
                ))
                .with_labels(vec![
                    Label::secondary((), original.range.clone()).with_message(unindent::unindent(
                        &format!(
                            r#"
                                    first assignment to `{0}`
                                    help: make this binding mutable: `mut {0}`
                                "#,
                            original.content
                        ),
                    )),
                    Label::primary((), mutating.range.clone())
                        .with_message("cannot assign twice to immutable variable"),
                ]),
        }
    }
}

/// An item in the source code to be used in the `Error` enum.
/// In a more complex program it could also contain a `files::FileId` to handle errors that occur inside multiple files.
struct Item {
    range: Range<usize>,
    content: String,
}

impl Item {
    fn new(range: Range<usize>, content: impl Into<String>) -> Item {
        let content = content.into();
        Item { range, content }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#[test]
fn simple_raw_data_struct() {
    let data: &[::Word] = &[
        capnp_word!(0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00),
        capnp_word!(0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef)];

    let reader = ::private::layout::PointerReader::get_root_unchecked(data.as_ptr())
        .get_struct(::std::ptr::null()).unwrap();

    assert_eq!(0xefcdab8967452301u64, reader.get_data_field::<u64>(0));
    assert_eq!(0, reader.get_data_field::<u64>(1));
    assert_eq!(0x67452301u32, reader.get_data_field::<u32>(0));
    assert_eq!(0xefcdab89u32, reader.get_data_field::<u32>(1));
    assert_eq!(0, reader.get_data_field::<u32>(2));
    assert_eq!(0x2301u16, reader.get_data_field::<u16>(0));
    // TODO the rest of uints.

    // Bits.
    assert_eq!(reader.get_bool_field(0), true);
    assert_eq!(reader.get_bool_field(1), false);
    assert_eq!(reader.get_bool_field(2), false);
    assert_eq!(reader.get_bool_field(3), false);
    assert_eq!(reader.get_bool_field(4), false);
    assert_eq!(reader.get_bool_field(5), false);
    assert_eq!(reader.get_bool_field(6), false);
    assert_eq!(reader.get_bool_field(7), false);

    assert_eq!(reader.get_bool_field(8),  true);
    assert_eq!(reader.get_bool_field(9),  true);
    assert_eq!(reader.get_bool_field(10), false);
    assert_eq!(reader.get_bool_field(11), false);
    assert_eq!(reader.get_bool_field(12), false);
    assert_eq!(reader.get_bool_field(13), true);
    assert_eq!(reader.get_bool_field(14), false);
    assert_eq!(reader.get_bool_field(15), false);

    assert_eq!(reader.get_bool_field(63), true);
    assert_eq!(reader.get_bool_field(64), false);
}

#[test]
fn bool_list() {
    use private::layout::PrimitiveElement;
    use traits::FromPointerReader;

    // [true, false, true, false,
    //  true, true, true, false,
    //  false, true]

    let data: &[::Word] = &[
        capnp_word!(0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00),
        capnp_word!(0x75, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)];

    let pointer_reader =
        ::private::layout::PointerReader::get_root_unchecked(data.as_ptr());

    let reader = pointer_reader.get_list(::private::layout::ElementSize::Bit, ::std::ptr::null()).unwrap();

    assert_eq!(reader.len(), 10);
    assert_eq!(bool::get(&reader, 0), true);
    assert_eq!(bool::get(&reader, 1), false);
    assert_eq!(bool::get(&reader, 2), true);
    assert_eq!(bool::get(&reader, 3), false);
    assert_eq!(bool::get(&reader, 4), true);
    assert_eq!(bool::get(&reader, 5), true);
    assert_eq!(bool::get(&reader, 6), true);
    assert_eq!(bool::get(&reader, 7), false);
    assert_eq!(bool::get(&reader, 8), false);
    assert_eq!(bool::get(&reader, 9), true);

    let reader = ::primitive_list::Reader::<bool>::get_from_pointer(&pointer_reader).unwrap();

    assert_eq!(reader.len(), 10);
    assert_eq!(reader.get(0), true);
    assert_eq!(reader.get(1), false);
    assert_eq!(reader.get(2), true);
    assert_eq!(reader.get(3), false);
    assert_eq!(reader.get(4), true);
    assert_eq!(reader.get(5), true);
    assert_eq!(reader.get(6), true);
    assert_eq!(reader.get(7), false);
    assert_eq!(reader.get(8), false);
    assert_eq!(reader.get(9), true);
}
<commit_msg>add some total_size() tests<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use Word;

#[test]
fn simple_raw_data_struct() {
    let data: &[Word] = &[
        capnp_word!(0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00),
        capnp_word!(0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef)];

    let reader = ::private::layout::PointerReader::get_root_unchecked(data.as_ptr())
        .get_struct(::std::ptr::null()).unwrap();

    assert_eq!(0xefcdab8967452301u64, reader.get_data_field::<u64>(0));
    assert_eq!(0, reader.get_data_field::<u64>(1));
    assert_eq!(0x67452301u32, reader.get_data_field::<u32>(0));
    assert_eq!(0xefcdab89u32, reader.get_data_field::<u32>(1));
    assert_eq!(0, reader.get_data_field::<u32>(2));
    assert_eq!(0x2301u16, reader.get_data_field::<u16>(0));
    // TODO the rest of uints.

    // Bits.
    assert_eq!(reader.get_bool_field(0), true);
    assert_eq!(reader.get_bool_field(1), false);
    assert_eq!(reader.get_bool_field(2), false);
    assert_eq!(reader.get_bool_field(3), false);
    assert_eq!(reader.get_bool_field(4), false);
    assert_eq!(reader.get_bool_field(5), false);
    assert_eq!(reader.get_bool_field(6), false);
    assert_eq!(reader.get_bool_field(7), false);

    assert_eq!(reader.get_bool_field(8),  true);
    assert_eq!(reader.get_bool_field(9),  true);
    assert_eq!(reader.get_bool_field(10), false);
    assert_eq!(reader.get_bool_field(11), false);
    assert_eq!(reader.get_bool_field(12), false);
    assert_eq!(reader.get_bool_field(13), true);
    assert_eq!(reader.get_bool_field(14), false);
    assert_eq!(reader.get_bool_field(15), false);

    assert_eq!(reader.get_bool_field(63), true);
    assert_eq!(reader.get_bool_field(64), false);
}

#[test]
fn bool_list() {
    use private::layout::PrimitiveElement;
    use traits::FromPointerReader;

    // [true, false, true, false,
    //  true, true, true, false,
    //  false, true]

    let data: &[Word] = &[
        capnp_word!(0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00),
        capnp_word!(0x75, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)];

    let pointer_reader =
        ::private::layout::PointerReader::get_root_unchecked(data.as_ptr());

    let reader = pointer_reader.get_list(::private::layout::ElementSize::Bit, ::std::ptr::null()).unwrap();

    assert_eq!(reader.len(), 10);
    assert_eq!(bool::get(&reader, 0), true);
    assert_eq!(bool::get(&reader, 1), false);
    assert_eq!(bool::get(&reader, 2), true);
    assert_eq!(bool::get(&reader, 3), false);
    assert_eq!(bool::get(&reader, 4), true);
    assert_eq!(bool::get(&reader, 5), true);
    assert_eq!(bool::get(&reader, 6), true);
    assert_eq!(bool::get(&reader, 7), false);
    assert_eq!(bool::get(&reader, 8), false);
    assert_eq!(bool::get(&reader, 9), true);

    let reader = ::primitive_list::Reader::<bool>::get_from_pointer(&pointer_reader).unwrap();

    assert_eq!(reader.len(), 10);
    assert_eq!(reader.get(0), true);
    assert_eq!(reader.get(1), false);
    assert_eq!(reader.get(2), true);
    assert_eq!(reader.get(3), false);
    assert_eq!(reader.get(4), true);
    assert_eq!(reader.get(5), true);
    assert_eq!(reader.get(6), true);
    assert_eq!(reader.get(7), false);
    assert_eq!(reader.get(8), false);
    assert_eq!(reader.get(9), true);
}

#[test]
fn struct_size() {
    use traits::FromPointerReader;

    let data: &[Word] = &[
        capnp_word!(0x00, 0x00, 0x00, 0x00, 0x2, 0x00, 0x01, 0x00),
        capnp_word!(0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
        capnp_word!(0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
        capnp_word!(0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
    ];

    let pointer_reader =
        ::private::layout::PointerReader::get_root_unchecked(data.as_ptr());

    assert_eq!(pointer_reader.total_size().unwrap().word_count, 3);
}

#[test]
fn struct_list_size() {
    use traits::FromPointerReader;

    let data: &[Word] = &[
        capnp_word!(0x01, 0, 0, 0, 0x1f, 0, 0, 0), // inline-composite list. 4 words long.
        capnp_word!(0x4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00), // 1 element long
        capnp_word!(0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
        capnp_word!(0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
        capnp_word!(0x0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
    ];

    // The list pointer claims that the list consumes four words, but the struct
    // tag says there is only one element and it has a size of one word.
    // So there is an inconsistency! total_size() should report the value computed from
    // the struct tag, because that's what is relevent when the data is copied.

    let pointer_reader =
        ::private::layout::PointerReader::get_root_unchecked(data.as_ptr());

    assert_eq!(pointer_reader.total_size().unwrap().word_count, 2);
}
<|endoftext|>


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

// NOTE: See dep_test/cpp_compat_test.cpp for a comparison

use super::BOOL_VALUES;
use super::DOUBLE_VALUES;
use super::INT64_VALUES;
use crate::simplejson_protocol::SimpleJsonProtocolDeserializer;
use crate::simplejson_protocol::{self};
use crate::thrift_protocol::MessageType;
use crate::ttype::TType;
use crate::Deserialize;
use crate::ProtocolWriter;
use crate::SimpleJsonProtocol;
use serde_json::json;

#[test]
fn write_bool_list() {
    let thetype = TType::Bool;
    let thelen = BOOL_VALUES.len();

    // Write
    let buf = serialize!(SimpleJsonProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &BOOL_VALUES {
            p.write_list_value_begin();
            p.write_bool(*v);
        }

        p.write_list_end();
    });

    let v: serde_json::Result<serde_json::Value> = serde_json::from_slice(&buf);
    assert!(v.is_ok());
    assert_eq!(buf, "[false,true,false,false,true]");
}

#[test]
fn write_string_list() {
    let string_values = vec![
        String::from(""),
        String::from("a"),
        String::from("st[uf]f"),
        String::from("st,u:ff with spaces"),
        String::from("stuff\twith\nescape\\characters'...\"lots{of}fun</xml>"),
        String::from("UNICODE\u{1F60A}UH OH"),
    ];
    let thetype = TType::String;
    let thelen = string_values.len();

    let buf = serialize!(SimpleJsonProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &string_values {
            p.write_list_value_begin();
            p.write_string(v);
        }
        p.write_list_end();
    });

    let v: serde_json::Result<serde_json::Value> = serde_json::from_slice(&buf);
    assert!(v.is_ok());
    // String in the json should be escaped
    // But unicode is left alone
    //
    // See cpp_compat_test.cpp for a comparison
    assert_eq!(
        buf,
        "[\"\",\"a\",\"st[uf]f\",\"st,\
               u:ff with spaces\",\"stuff\\twith\\nescape\\\\characters'...\\\"lots{of}fun\
               </xml>\",\"UNICODE\u{1F60A}UH OH\"]"
    );
}

#[test]
fn write_i64_list() {
    let thetype = TType::I64;
    let thelen = INT64_VALUES.len();

    let buf = serialize!(SimpleJsonProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &INT64_VALUES {
            p.write_list_value_begin();
            p.write_i64(*v);
        }
        p.write_list_end();
    });

    let v: serde_json::Result<serde_json::Value> = serde_json::from_slice(&buf);
    assert!(v.is_ok());
    assert_eq!(
        buf,
        "[459,0,1,-1,-128,127,32767,2147483647,\
               -2147483535,34359738481,-35184372088719,\
               -9223372036854775808,9223372036854775807]"
    );
}

#[test]
fn write_f64_list() {
    let thetype = TType::Double;
    let thelen = DOUBLE_VALUES.len();

    let buf = serialize!(SimpleJsonProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &DOUBLE_VALUES {
            p.write_list_value_begin();
            p.write_double(*v);
        }
        p.write_list_end();
    });

    // json can't handle infinity or nan
    let v: serde_json::Result<serde_json::Value> = serde_json::from_slice(&buf);
    assert!(v.is_err());

    let buf2 = serialize!(SimpleJsonProtocol, |p| {
        p.write_list_begin(thetype, thelen - 2);

        for v in &DOUBLE_VALUES {
            if v >= &::std::f64::INFINITY || v <= &::std::f64::NEG_INFINITY || v.is_nan() {
                continue;
            }
            p.write_list_value_begin();
            p.write_double(*v);
        }
        p.write_list_end();
    });

    let v: serde_json::Result<serde_json::Value> = serde_json::from_slice(&buf2);
    assert!(v.is_ok());
    assert_eq!(
        buf2,
        "[459.3,0.0,-1.0,1.0,0.5,0.3333,3.14159,\
        1.537e-38,1.673e25,6.02214179e23,-6.02214179e23]"
    );
}

#[test]
fn write_binary() {
    let buf = serialize!(SimpleJsonProtocol, |p| {
        // "1234"
        p.write_binary(&[49u8, 50u8, 51u8, 52u8]);
    });

    // the \ isnt escaped
    assert_eq!(buf, "\"MTIzNA\"");
}

#[test]
fn write_message() {
    let msg_name = String::from("hello_message");
    let msg_type = MessageType::Call;
    let seq_id = 10;

    let buf = serialize!(SimpleJsonProtocol, |p| {
        p.write_message_begin(&msg_name, msg_type, seq_id);
        p.write_message_end();
    });

    let v: serde_json::Result<serde_json::Value> = serde_json::from_slice(&buf);
    assert!(v.is_ok());
    assert_eq!(buf, "[\"hello_message\",1,10]");
}

#[test]
fn read_json_value() {
    let json: &[u8] = br#" {
        "void" : null ,
        "bool" : true ,
        "double" : 1.0 ,
        "utf8" : "..." ,
        "spaces" : " spaces ",
        "list" : [ null , 1 ] ,
        "struct" : { "" : null , "x" : false }
    } "#;
    let mut de = SimpleJsonProtocolDeserializer::new(json);
    let actual = serde_json::Value::read(&mut de).unwrap();
    let expected = json!({
        "void": null,
        "bool": true,
        "double": 1.0,
        "utf8": "...",
        "spaces": " spaces ",
        "list": [null, 1],
        "struct": {"": null, "x": false},
    });
    assert_eq!(actual, expected);
}

#[test]
fn fail_to_read_json_value() {
    let json: &[u8] = br#" [null,] "#;
    let mut de = SimpleJsonProtocolDeserializer::new(json);
    let err = serde_json::Value::read(&mut de).unwrap_err();
    assert_eq!("Found trailing comma", err.to_string());
}

#[test]
fn test_trailing() {
    let json: &[u8] = br#" "..." null "#;
    match simplejson_protocol::deserialize(json) {
        Ok(ok) => {
            let _: String = ok;
            panic!("trailing data is supposed to cause deserialization failure");
        }
        Err(err) => assert_eq!(
            "Unexpected trailing data after the end of a value",
            err.to_string(),
        ),
    }
}

#[test]
fn fail_to_read_object() {
    let json: &[u8] = br#" { "#;
    let mut de = SimpleJsonProtocolDeserializer::new(json);
    let err = serde_json::Value::read(&mut de).unwrap_err();
    assert_eq!(
        "Expected the following chars: \"}\", not enough bytes remaining",
        err.to_string()
    );
}
<commit_msg>Remove ::{self}<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// NOTE: See dep_test/cpp_compat_test.cpp for a comparison

use super::BOOL_VALUES;
use super::DOUBLE_VALUES;
use super::INT64_VALUES;
use crate::simplejson_protocol;
use crate::simplejson_protocol::SimpleJsonProtocolDeserializer;
use crate::thrift_protocol::MessageType;
use crate::ttype::TType;
use crate::Deserialize;
use crate::ProtocolWriter;
use crate::SimpleJsonProtocol;
use serde_json::json;

#[test]
fn write_bool_list() {
    let thetype = TType::Bool;
    let thelen = BOOL_VALUES.len();

    // Write
    let buf = serialize!(SimpleJsonProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &BOOL_VALUES {
            p.write_list_value_begin();
            p.write_bool(*v);
        }

        p.write_list_end();
    });

    let v: serde_json::Result<serde_json::Value> = serde_json::from_slice(&buf);
    assert!(v.is_ok());
    assert_eq!(buf, "[false,true,false,false,true]");
}

#[test]
fn write_string_list() {
    let string_values = vec![
        String::from(""),
        String::from("a"),
        String::from("st[uf]f"),
        String::from("st,u:ff with spaces"),
        String::from("stuff\twith\nescape\\characters'...\"lots{of}fun</xml>"),
        String::from("UNICODE\u{1F60A}UH OH"),
    ];
    let thetype = TType::String;
    let thelen = string_values.len();

    let buf = serialize!(SimpleJsonProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &string_values {
            p.write_list_value_begin();
            p.write_string(v);
        }
        p.write_list_end();
    });

    let v: serde_json::Result<serde_json::Value> = serde_json::from_slice(&buf);
    assert!(v.is_ok());
    // String in the json should be escaped
    // But unicode is left alone
    //
    // See cpp_compat_test.cpp for a comparison
    assert_eq!(
        buf,
        "[\"\",\"a\",\"st[uf]f\",\"st,\
               u:ff with spaces\",\"stuff\\twith\\nescape\\\\characters'...\\\"lots{of}fun\
               </xml>\",\"UNICODE\u{1F60A}UH OH\"]"
    );
}

#[test]
fn write_i64_list() {
    let thetype = TType::I64;
    let thelen = INT64_VALUES.len();

    let buf = serialize!(SimpleJsonProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &INT64_VALUES {
            p.write_list_value_begin();
            p.write_i64(*v);
        }
        p.write_list_end();
    });

    let v: serde_json::Result<serde_json::Value> = serde_json::from_slice(&buf);
    assert!(v.is_ok());
    assert_eq!(
        buf,
        "[459,0,1,-1,-128,127,32767,2147483647,\
               -2147483535,34359738481,-35184372088719,\
               -9223372036854775808,9223372036854775807]"
    );
}

#[test]
fn write_f64_list() {
    let thetype = TType::Double;
    let thelen = DOUBLE_VALUES.len();

    let buf = serialize!(SimpleJsonProtocol, |p| {
        p.write_list_begin(thetype, thelen);

        for v in &DOUBLE_VALUES {
            p.write_list_value_begin();
            p.write_double(*v);
        }
        p.write_list_end();
    });

    // json can't handle infinity or nan
    let v: serde_json::Result<serde_json::Value> = serde_json::from_slice(&buf);
    assert!(v.is_err());

    let buf2 = serialize!(SimpleJsonProtocol, |p| {
        p.write_list_begin(thetype, thelen - 2);

        for v in &DOUBLE_VALUES {
            if v >= &::std::f64::INFINITY || v <= &::std::f64::NEG_INFINITY || v.is_nan() {
                continue;
            }
            p.write_list_value_begin();
            p.write_double(*v);
        }
        p.write_list_end();
    });

    let v: serde_json::Result<serde_json::Value> = serde_json::from_slice(&buf2);
    assert!(v.is_ok());
    assert_eq!(
        buf2,
        "[459.3,0.0,-1.0,1.0,0.5,0.3333,3.14159,\
        1.537e-38,1.673e25,6.02214179e23,-6.02214179e23]"
    );
}

#[test]
fn write_binary() {
    let buf = serialize!(SimpleJsonProtocol, |p| {
        // "1234"
        p.write_binary(&[49u8, 50u8, 51u8, 52u8]);
    });

    // the \ isnt escaped
    assert_eq!(buf, "\"MTIzNA\"");
}

#[test]
fn write_message() {
    let msg_name = String::from("hello_message");
    let msg_type = MessageType::Call;
    let seq_id = 10;

    let buf = serialize!(SimpleJsonProtocol, |p| {
        p.write_message_begin(&msg_name, msg_type, seq_id);
        p.write_message_end();
    });

    let v: serde_json::Result<serde_json::Value> = serde_json::from_slice(&buf);
    assert!(v.is_ok());
    assert_eq!(buf, "[\"hello_message\",1,10]");
}

#[test]
fn read_json_value() {
    let json: &[u8] = br#" {
        "void" : null ,
        "bool" : true ,
        "double" : 1.0 ,
        "utf8" : "..." ,
        "spaces" : " spaces ",
        "list" : [ null , 1 ] ,
        "struct" : { "" : null , "x" : false }
    } "#;
    let mut de = SimpleJsonProtocolDeserializer::new(json);
    let actual = serde_json::Value::read(&mut de).unwrap();
    let expected = json!({
        "void": null,
        "bool": true,
        "double": 1.0,
        "utf8": "...",
        "spaces": " spaces ",
        "list": [null, 1],
        "struct": {"": null, "x": false},
    });
    assert_eq!(actual, expected);
}

#[test]
fn fail_to_read_json_value() {
    let json: &[u8] = br#" [null,] "#;
    let mut de = SimpleJsonProtocolDeserializer::new(json);
    let err = serde_json::Value::read(&mut de).unwrap_err();
    assert_eq!("Found trailing comma", err.to_string());
}

#[test]
fn test_trailing() {
    let json: &[u8] = br#" "..." null "#;
    match simplejson_protocol::deserialize(json) {
        Ok(ok) => {
            let _: String = ok;
            panic!("trailing data is supposed to cause deserialization failure");
        }
        Err(err) => assert_eq!(
            "Unexpected trailing data after the end of a value",
            err.to_string(),
        ),
    }
}

#[test]
fn fail_to_read_object() {
    let json: &[u8] = br#" { "#;
    let mut de = SimpleJsonProtocolDeserializer::new(json);
    let err = serde_json::Value::read(&mut de).unwrap_err();
    assert_eq!(
        "Expected the following chars: \"}\", not enough bytes remaining",
        err.to_string()
    );
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;

use std::env;
use std::fs::File;
use std::io::Read;
use std::io::{self, stdout, stderr, Write, Stderr};
use std::iter;
use std::process::exit;

use std::ops::{Add, AddAssign};

use coreutils::extra::{OptionalExt, WriteExt};

static MAN_PAGE: &'static str = r#"
    NAME
        wc - count words, bytes and lines of a file or byte stream.
    SYNOPSIS
        wc [-h | --help] [-c | --bytes] [-w | --words] [-l | --lines] [FILE 1] [FILE 2]...
    DESCRIPTION
        This utility will dump word count, line count, and byte count of a file or byte stream. If multiple files are given, it will print a total count. If no file name is given, 'wc' reads from stdin until EOF.

        Flags can be arbitrarily combined into a single flag, for example, '-c -w' (count bytes and count words) can be reduced to '-cw'.

        If no flags are given, 'wc' defaults to '-cwl'.
    OPTIONS
        -h
        --help
            Print this manual page.
        -c
        --bytes
            Count bytes.
        -w
        --words
            Count words (i.e. contiguous strings seperated by whitespaces).
        -l
        --lines
            Count lines (seperated by NL).
    AUTHOR
        This program was written mainly by Alice Maz.
"#;

#[derive(Copy, Clone, Default)]
struct Counter {
    lines: u64,
    words: u64,
    bytes: u64,
}

impl Counter {
    #[inline]
    fn new<T: std::io::Read>(input: T) -> Self {
        let mut line_count = 0;
        let mut word_count = 0;
        let mut byte_count = 0;
        let mut got_space = true;

        for byte_result in input.bytes() {
            if let Ok(byte) = byte_result {
                if byte == b'\n' {
                    line_count += 1;
                }

                if is_whitespace(byte) {
                    got_space = true;
                } else if got_space {
                    got_space = false;
                    word_count += 1;
                }

                byte_count += 1;
            }
        }

        Counter { lines: line_count, words: word_count, bytes: byte_count }
    }
}

impl Add for Counter {
    type Output = Counter;

    fn add(self, other: Self) -> Self {
        Counter {
            lines: self.lines + other.lines,
            words: self.words + other.words,
            bytes: self.bytes + other.bytes
        }
    }
}

impl AddAssign for Counter {
    fn add_assign(&mut self, _rhs: Self) {
        self.lines += _rhs.lines;
        self.words += _rhs.words;
        self.bytes += _rhs.bytes;
    }
}

#[derive(Copy, Clone, Default)]
struct Flags {
    count_lines: bool,
    count_words: bool,
    count_bytes: bool,
}

impl Flags {
    fn print_count<'a, W: Write>(self, count: Counter, file: &'a str, stdout: &mut W, stderr: &mut Stderr) {
        stdout.write(b"    ").try(&mut *stderr);

        if self.count_lines {
            stdout.write(count.lines.to_string().as_bytes()).try(&mut *stderr);
            stdout.write(b" ").try(&mut *stderr);
        }
        if self.count_words {
            stdout.write(count.words.to_string().as_bytes()).try(&mut *stderr);
            stdout.write(b" ").try(&mut *stderr);
        }
        if self.count_bytes {
            stdout.write(count.bytes.to_string().as_bytes()).try(&mut *stderr);
            stdout.write(b" ").try(&mut *stderr);
        }

        stdout.writeln(file.as_bytes()).try(&mut *stderr);
    }

    fn default_to(&mut self) {
        // Defaults to behavior of -lwc
        if !(self.count_lines || self.count_words || self.count_bytes) {
            self.count_lines = true;
            self.count_words = true;
            self.count_bytes = true;
        }
    }
}

fn main() {
    let mut opts = Flags::default();
    let mut first_file = String::new();
    let mut args = env::args().skip(1);
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();

    loop { // To avoid consumption of the iter, we use loop.
        let arg = if let Some(x) = args.next() { x } else { break };

        // TODO add -m, maybe add -L

        if arg.starts_with("-") {
            match arg.as_str() {
                "--lines" | "-l" => opts.count_lines = true,
                "--words" | "-w" => opts.count_words = true,
                "--bytes" | "-c" => opts.count_bytes = true,
                "--help"  | "-h" => {
                    stdout.writeln(MAN_PAGE.as_bytes()).try(&mut stderr);
                    return;
                },
                _ => {
                    stderr.write(b"error: unknown flag, ").try(&mut stderr);
                    stderr.write(arg.as_bytes()).try(&mut stderr);
                    stderr.flush().try(&mut stderr);
                    exit(1);
                },
            }
        } else { // This is a file name
            first_file = arg;
            break;
        }
    }

    opts.default_to();

    if first_file == "" {
        let stdin = io::stdin();
        let stdin = stdin.lock();

        opts.print_count(Counter::new(stdin), "stdin", &mut stdout, &mut stderr);
    } else {
        let mut total_count = Counter::default();
        let single_file = args.len() == 1;

        for path in iter::once(first_file).chain(args) {
            //TODO would be easy to use stdin for - but
            //that is probably something the shell should handle?
            //unix it's all just fds so it's whatever dunno here tho
            //(also - is specific to sh/bash fwiw).

            let file = File::open(&path).try(&mut stderr);
            let file_count = Counter::new(file);
            total_count += file_count;

            opts.print_count(file_count, &path, &mut stdout, &mut stderr);
        }

        if single_file {
            opts.print_count(total_count, "total", &mut stdout, &mut stderr);
        }
    }
}

fn is_whitespace(byte: u8) -> bool {
    //FIXME this works like iswspace w/ default C locale
    //but not good enough for en_US.UTF8 among others

    byte == b'\n' // newline
    || byte == b'\t' // tab
    || byte == b'\r' // cr
    || byte == 0xc // formfeed
    || byte == 0xb // vtab
    || byte == b' ' // space
}
<commit_msg>Apply fixes<commit_after>#![deny(warnings)]

extern crate coreutils;

use std::env;
use std::fs::File;
use std::io::{self, stdout, stderr, Read, Write, Stderr};
use std::iter;
use std::ops::{Add, AddAssign};
use std::process::exit;

use coreutils::extra::{OptionalExt, WriteExt};

static MAN_PAGE: &'static str = r#"
    NAME
        wc - count words, bytes and lines of a file or byte stream.
    SYNOPSIS
        wc [-h | --help] [-c | --bytes] [-w | --words] [-l | --lines] [FILE 1] [FILE 2]...
    DESCRIPTION
        This utility will dump word count, line count, and byte count of a file or byte stream. If multiple files are given, it will print a total count. If no file name is given, 'wc' reads from stdin until EOF.

        Flags can be arbitrarily combined into a single flag, for example, '-c -w' (count bytes and count words) can be reduced to '-cw'.

        If no flags are given, 'wc' defaults to '-cwl'.
    OPTIONS
        -h
        --help
            Print this manual page.
        -c
        --bytes
            Count bytes.
        -w
        --words
            Count words (i.e. contiguous strings seperated by whitespaces).
        -l
        --lines
            Count lines (seperated by NL).
    AUTHOR
        This program was written mainly by Alice Maz.
"#;

#[derive(Copy, Clone, Default)]
struct Counter {
    lines: u64,
    words: u64,
    bytes: u64,
}

impl Counter {
    #[inline]
    fn new<T: Read>(input: T) -> Self {
        let mut line_count = 0;
        let mut word_count = 0;
        let mut byte_count = 0;
        let mut got_space = true;

        for byte_result in input.bytes() {
            if let Ok(byte) = byte_result {
                if byte == b'\n' {
                    line_count += 1;
                }

                if is_whitespace(byte) {
                    got_space = true;
                } else if got_space {
                    got_space = false;
                    word_count += 1;
                }

                byte_count += 1;
            }
        }

        Counter { lines: line_count, words: word_count, bytes: byte_count }
    }
}

impl Add for Counter {
    type Output = Counter;

    fn add(self, other: Self) -> Self {
        Counter {
            lines: self.lines + other.lines,
            words: self.words + other.words,
            bytes: self.bytes + other.bytes
        }
    }
}

impl AddAssign for Counter {
    fn add_assign(&mut self, _rhs: Self) {
        self.lines += _rhs.lines;
        self.words += _rhs.words;
        self.bytes += _rhs.bytes;
    }
}

#[derive(Copy, Clone, Default)]
struct Flags {
    count_lines: bool,
    count_words: bool,
    count_bytes: bool,
}

impl Flags {
    fn print_count<'a, W: Write>(self, count: Counter, file: &'a str, stdout: &mut W, stderr: &mut Stderr) {
        stdout.write(b"    ").try(&mut *stderr);

        if self.count_lines {
            stdout.write(count.lines.to_string().as_bytes()).try(&mut *stderr);
            stdout.write(b" ").try(&mut *stderr);
        }
        if self.count_words {
            stdout.write(count.words.to_string().as_bytes()).try(&mut *stderr);
            stdout.write(b" ").try(&mut *stderr);
        }
        if self.count_bytes {
            stdout.write(count.bytes.to_string().as_bytes()).try(&mut *stderr);
            stdout.write(b" ").try(&mut *stderr);
        }

        stdout.writeln(file.as_bytes()).try(&mut *stderr);
    }

    fn default_to(&mut self) {
        // Defaults to behavior of -lwc
        if !(self.count_lines || self.count_words || self.count_bytes) {
            self.count_lines = true;
            self.count_words = true;
            self.count_bytes = true;
        }
    }
}

fn main() {
    let mut opts = Flags::default();
    let mut first_file = String::new();
    let mut args = env::args().skip(1);
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();

    loop { // To avoid consumption of the iter, we use loop.
        let arg = if let Some(x) = args.next() { x } else { break };

        // TODO add -m, maybe add -L

        if arg.starts_with("-") {
            match arg.as_str() {
                "--lines" | "-l" => opts.count_lines = true,
                "--words" | "-w" => opts.count_words = true,
                "--bytes" | "-c" => opts.count_bytes = true,
                "--help"  | "-h" => {
                    stdout.writeln(MAN_PAGE.as_bytes()).try(&mut stderr);
                    return;
                },
                _ => {
                    stderr.write(b"error: unknown flag, ").try(&mut stderr);
                    stderr.write(arg.as_bytes()).try(&mut stderr);
                    stderr.flush().try(&mut stderr);
                    exit(1);
                },
            }
        } else { // This is a file name
            first_file = arg;
            break;
        }
    }

    opts.default_to();

    if first_file == "" {
        let stdin = io::stdin();
        let stdin = stdin.lock();

        opts.print_count(Counter::new(stdin), "stdin", &mut stdout, &mut stderr);
    } else {
        let mut total_count = Counter::default();
        let single_file = args.len() == 1;

        for path in iter::once(first_file).chain(args) {
            //TODO would be easy to use stdin for - but
            //that is probably something the shell should handle?
            //unix it's all just fds so it's whatever dunno here tho
            //(also - is specific to sh/bash fwiw).

            let file = File::open(&path).try(&mut stderr);
            let file_count = Counter::new(file);
            total_count += file_count;

            opts.print_count(file_count, &path, &mut stdout, &mut stderr);
        }

        if single_file {
            opts.print_count(total_count, "total", &mut stdout, &mut stderr);
        }
    }
}

fn is_whitespace(byte: u8) -> bool {
    //FIXME this works like iswspace w/ default C locale
    //but not good enough for en_US.UTF8 among others

    byte == b'\n' // newline
    || byte == b'\t' // tab
    || byte == b'\r' // cr
    || byte == 0xc // formfeed
    || byte == 0xb // vtab
    || byte == b' ' // space
}
<|endoftext|>


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

use irc;
use matrix;
use irc::protocol::{Command,Message};
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;

const CLIENT: Token = Token(0);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::events::RoomID, Room>,
    seen_events: Vec<matrix::events::EventID>,
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!()
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                self.handle_matrix(e)
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::events::RoomID,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::events::UserID>,
    pending_events: Vec<matrix::events::RoomEvent>
}

impl Room {
    fn new(id: matrix::events::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![],
            pending_events: vec![]
        }
    }

    fn run_pending<F>(&mut self, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        while let Some(evt) = self.pending_events.pop() {
            self.handle_with_alias(evt, callback);
        }
    }

    fn handle_with_alias<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        if self.canonical_alias != None {
            match evt {
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Leave) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Part,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(_, _) => (),
                matrix::events::RoomEvent::Message(user, text) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Privmsg,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(text)
                    });
                },
                matrix::events::RoomEvent::Topic(user, topic) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Topic,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(topic.clone())
                    });
                },
                matrix::events::RoomEvent::CanonicalAlias(_) => unreachable!(),
                _ => {
                    warn!("Unhandled event {:?}", evt)
                }
            }
        } else {
            self.pending_events.push(evt);
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                let was_empty = self.canonical_alias == None;
                self.canonical_alias = Some(name.clone());
                if was_empty {
                    self.run_pending(&mut callback);
                }
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases(aliases) => {
                let is_empty = self.canonical_alias == None;
                if is_empty {
                    self.canonical_alias = Some(aliases[0].clone());
                    self.run_pending(&mut callback);
                }
            },
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => (),
            matrix::events::RoomEvent::Name(_, _) => (),
            matrix::events::RoomEvent::Avatar(_, _) => (),
            matrix::events::RoomEvent::Unknown(unknown_type, json) => {
                warn!("Unknown room event {}", unknown_type);
                trace!("raw event: {:?}", json);
            }
            _ => self.handle_with_alias(evt, &mut callback)
        };
    }
}

impl Bridge {
    pub fn room_from_matrix(&mut self, id: &matrix::events::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!()
        }
    }

    pub fn room_from_irc(&mut self, id: &String) -> Option<&mut Room> {
        let mut room_id: Option<matrix::events::RoomID> = None;
        for (_, r) in self.rooms.iter_mut() {
            if let Some(ref alias) = r.canonical_alias {
                if alias == id {
                    room_id = Some(r.id.clone())
                }
            }
        }
        match room_id {
            Some(id) => Some(self.room_from_matrix(&id)),
            None => None
        }
    }

    pub fn new(client: irc::streams::Client, url: &str) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(url),
            rooms: HashMap::new(),
            seen_events: vec![]
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.stream().get_ref(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) {
        let duplicate = match evt.id {
            Some(ref id) =>
                self.seen_events.contains(id),
            _ => false
        };
        if !duplicate {
            let mut messages: Vec<irc::protocol::Message> = vec![];
            {
                let append_msg = |msg: irc::protocol::Message| {
                    messages.push(msg);
                };
                match evt.data {
                    matrix::events::EventData::Room(room_id, room_event) => {
                        self.room_from_matrix(&room_id).handle_event(room_event, append_msg);
                    },
                    matrix::events::EventData::Typing(_) => (),
                    _ => warn!("Unhandled {}", evt.data.type_str())
                }
            }
            match evt.id {
                Some(id) =>
                    self.seen_events.push(id),
                None => ()
            };
            for ref msg in messages {
                self.client.send(msg).unwrap();
            }
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) ->
        thread::JoinHandle<matrix::client::Result> {
        let poll = self.matrix.poll_async();
        thread::spawn(move|| {
            poll.send().and_then(|evts| {
                for evt in evts {
                    channel.send(Event::Matrix(evt)).unwrap();
                };
                channel.send(Event::EndPoll).unwrap();
                Ok(())
            })
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) ->
        matrix::client::Result {
        self.matrix.sync().and_then(|events| {
            for e in events {
                self.handle_matrix(e);
            }
            self.poll_matrix(channel);
            Ok(())
        })
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            let nickname = match message.suffix {
                                None => message.args[0].clone(),
                                Some(n) => n
                            };
                            self.client.set_nickname(nickname)
                        },
                        Command::User => {
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim())
                                        .and_then(|_| {
                                            self.start_matrix(events.channel())
                                        })
                                        .and_then(|_| {
                                            self.client.welcome(username.trim()).unwrap();
                                            debug!("Logged in a user");
                                            Ok(())
                                        }).expect("Could not login!");
                                },
                                _ => panic!("Username and/or password missing")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]).expect("Could not send JOIN");
                        },
                        Command::Ping => {
                            self.client.pong().expect("Could not send PONG");
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let room_id = match self.room_from_irc(&message.args[0]) {
                                None => return (),
                                Some(room) => room.id.clone()
                            };
                            let evt = {
                                let id = self.matrix.uid.clone().unwrap();
                                matrix::events::EventData::Room(
                                    room_id,
                                    matrix::events::RoomEvent::Message(
                                        id, message.suffix.unwrap()))
                            };
                            self.seen_events.push(self.matrix.send(evt).expect("Could not send event"));
                        },
                        _ =>
                            warn!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<commit_msg>bridge: handle matrix errors gracefully instead of exploding<commit_after>/*
 * Copyright 2015-2016 Torrie Fischer <tdfischer@hackerbots.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use irc;
use matrix;
use irc::protocol::{Command,Message};
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;
use std::io;

const CLIENT: Token = Token(0);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::events::RoomID, Room>,
    seen_events: Vec<matrix::events::EventID>,
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!()
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                match self.handle_matrix(e) {
                    Err(err) => warn!("Could not handle matrix event: {:?}", err),
                    _ => ()
                }
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::events::RoomID,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::events::UserID>,
    pending_events: Vec<matrix::events::RoomEvent>
}

impl Room {
    fn new(id: matrix::events::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![],
            pending_events: vec![]
        }
    }

    fn run_pending<F>(&mut self, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        while let Some(evt) = self.pending_events.pop() {
            self.handle_with_alias(evt, callback);
        }
    }

    fn handle_with_alias<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        if self.canonical_alias != None {
            match evt {
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Leave) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Part,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(_, _) => (),
                matrix::events::RoomEvent::Message(user, text) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Privmsg,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(text)
                    });
                },
                matrix::events::RoomEvent::Topic(user, topic) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Topic,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(topic.clone())
                    });
                },
                matrix::events::RoomEvent::CanonicalAlias(_) => unreachable!(),
                _ => {
                    warn!("Unhandled event {:?}", evt)
                }
            }
        } else {
            self.pending_events.push(evt);
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                let was_empty = self.canonical_alias == None;
                self.canonical_alias = Some(name.clone());
                if was_empty {
                    self.run_pending(&mut callback);
                }
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases(aliases) => {
                let is_empty = self.canonical_alias == None;
                if is_empty {
                    self.canonical_alias = Some(aliases[0].clone());
                    self.run_pending(&mut callback);
                }
            },
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => (),
            matrix::events::RoomEvent::Name(_, _) => (),
            matrix::events::RoomEvent::Avatar(_, _) => (),
            matrix::events::RoomEvent::Unknown(unknown_type, json) => {
                warn!("Unknown room event {}", unknown_type);
                trace!("raw event: {:?}", json);
            }
            _ => self.handle_with_alias(evt, &mut callback)
        };
    }
}

impl Bridge {
    pub fn room_from_matrix(&mut self, id: &matrix::events::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!()
        }
    }

    pub fn room_from_irc(&mut self, id: &String) -> Option<&mut Room> {
        let mut room_id: Option<matrix::events::RoomID> = None;
        for (_, r) in self.rooms.iter_mut() {
            if let Some(ref alias) = r.canonical_alias {
                if alias == id {
                    room_id = Some(r.id.clone())
                }
            }
        }
        match room_id {
            Some(id) => Some(self.room_from_matrix(&id)),
            None => None
        }
    }

    pub fn new(client: irc::streams::Client, url: &str) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(url),
            rooms: HashMap::new(),
            seen_events: vec![]
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.stream().get_ref(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) -> io::Result<usize> {
        let duplicate = match evt.id {
            Some(ref id) =>
                self.seen_events.contains(id),
            _ => false
        };
        if !duplicate {
            let mut messages: Vec<irc::protocol::Message> = vec![];
            {
                let append_msg = |msg: irc::protocol::Message| {
                    messages.push(msg);
                };
                match evt.data {
                    matrix::events::EventData::Room(room_id, room_event) => {
                        self.room_from_matrix(&room_id).handle_event(room_event, append_msg);
                    },
                    matrix::events::EventData::Typing(_) => (),
                    _ => warn!("Unhandled {}", evt.data.type_str())
                }
            }
            match evt.id {
                Some(id) =>
                    self.seen_events.push(id),
                None => ()
            };
            let mut res: Option<io::Result<usize>> = None;
            for ref msg in messages {
                res = Some(match res {
                    None => self.client.send(msg),
                    Some(r) => r.and(self.client.send(msg))
                })
            }
            match res {
                None => Ok(0),
                Some(e) => e
            }
        } else {
            Ok(0)
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) ->
        thread::JoinHandle<matrix::client::Result> {
        let poll = self.matrix.poll_async();
        thread::spawn(move|| {
            poll.send().and_then(|evts| {
                for evt in evts {
                    channel.send(Event::Matrix(evt)).unwrap();
                };
                channel.send(Event::EndPoll).unwrap();
                Ok(())
            })
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) ->
        matrix::client::Result {
        self.matrix.sync().and_then(|events| {
            for e in events {
                match self.handle_matrix(e) {
                    // FIXME: Return error
                    Err(err) => warn!("Could not handle matrix event: {:?}", err),
                    _ => ()
                }
            }
            self.poll_matrix(channel);
            Ok(())
        })
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            let nickname = match message.suffix {
                                None => message.args[0].clone(),
                                Some(n) => n
                            };
                            self.client.set_nickname(nickname)
                        },
                        Command::User => {
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim())
                                        .and_then(|_| {
                                            self.start_matrix(events.channel())
                                        })
                                        .and_then(|_| {
                                            self.client.welcome(username.trim()).unwrap();
                                            debug!("Logged in a user");
                                            Ok(())
                                        }).expect("Could not login!");
                                },
                                _ => panic!("Username and/or password missing")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]).expect("Could not send JOIN");
                        },
                        Command::Ping => {
                            self.client.pong().expect("Could not send PONG");
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let room_id = match self.room_from_irc(&message.args[0]) {
                                None => return (),
                                Some(room) => room.id.clone()
                            };
                            let evt = {
                                let id = self.matrix.uid.clone().unwrap();
                                matrix::events::EventData::Room(
                                    room_id,
                                    matrix::events::RoomEvent::Message(
                                        id, message.suffix.unwrap()))
                            };
                            self.seen_events.push(self.matrix.send(evt).expect("Could not send event"));
                        },
                        _ =>
                            warn!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<|endoftext|>