<commit_before>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// 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 topology::{self, State, Worker};
use state_machine::StateMachine;
use error::{BldrResult, BldrError};
use pkg::Package;
use topology::standalone;
use config::Config;

pub fn run(package: Package, config: &Config) -> BldrResult<()> {
    let mut worker = try!(Worker::new(package, String::from("leader"), config));
    let mut sm: StateMachine<State, Worker, BldrError> = StateMachine::new(State::Init);
    sm.add_dispatch(State::Init, state_init);
    sm.add_dispatch(State::RestoreDataset, state_restore_dataset);
    sm.add_dispatch(State::DetermineViability, state_determine_viability);
    sm.add_dispatch(State::StartElection, state_start_election);
    sm.add_dispatch(State::InElection, state_in_election);
    sm.add_dispatch(State::BecomeLeader, state_become_leader);
    sm.add_dispatch(State::BecomeFollower, state_become_follower);
    sm.add_dispatch(State::Leader, state_leader);
    sm.add_dispatch(State::Follower, state_follower);
    topology::run_internal(&mut sm, &mut worker)
}

fn state_init(worker: &mut Worker) -> Result<(State, u32), BldrError> {
    if worker.census.dataset_initialized() {
        Ok((State::RestoreDataset, 0))
    } else {
        Ok((State::DetermineViability, 0))
    }
}

fn state_restore_dataset(worker: &mut Worker) -> BldrResult<(State, u32)> {
    println!("   {}: Restoring the dataset from a peer", worker.preamble());
    let ce = try!(worker.census.me_mut());
    ce.data_init(Some(true));
    Ok((State::DetermineViability, 0))
}

fn state_determine_viability(worker: &mut Worker) -> BldrResult<(State, u32)> {
    println!("   {}: Determining viability as a leader", worker.preamble());
    worker.census.in_event = true;
    {
        let mut ce = try!(worker.census.me_mut());
        ce.follower(None);
        ce.leader(None);
    }
    if worker.census.has_leader() {
        Ok((State::BecomeFollower, 0))
    } else {
        Ok((State::StartElection, 0))
    }
}

fn state_start_election(worker: &mut Worker) -> BldrResult<(State, u32)> {
    println!("   {}: Starting an election", worker.preamble());
    {
        let mut ce = try!(worker.census.me_mut());
        ce.election = Some(true);
    }
    let candidate = worker.census.determine_vote().candidate_string();
    println!("   {}: My candidate is {:?}", worker.preamble(), candidate);
    let mut ce = try!(worker.census.me_mut());
    ce.vote(Some(candidate));
    Ok((State::InElection, 0))
}

fn state_in_election(worker: &mut Worker) -> BldrResult<(State, u32)> {
    let preamble = worker.preamble();
    let candidate = worker.census.determine_vote().candidate_string();
    {
        let mut ce = try!(worker.census.me_mut());
        match ce.vote {
            Some(ref c) if *c == candidate => {},
            Some(_) => {
                println!("   {}: Switching my vote to {}", preamble, candidate);
                ce.vote(Some(candidate));
            },
            None => {
                println!("   {}: Switching my vote to {}", preamble, candidate);
                ce.vote(Some(candidate));
            }
        }
    }

    match worker.census.voting_finished() {
        Some(winner) => {
            let me = try!(worker.census.me());
            if me == winner {
                println!("   {}: The votes are in! I won! I will serve with humility.", worker.preamble());
                Ok((State::BecomeLeader, 0))
            } else {
                println!("   {}: The votes are in! I lost! I will serve with grace.", worker.preamble());
                Ok((State::BecomeFollower, 0))
            }
        },
        None => Ok((State::InElection, 10))
    }
}

fn state_become_leader(worker: &mut Worker) -> BldrResult<(State, u32)> {
    if worker.census.has_leader() == false {
        {
            let mut ce = try!(worker.census.me_mut());
            ce.leader = Some(true);
        }
    }

    if worker.census.has_all_followers() {
        println!("   {}: Starting my term as leader", worker.preamble());
        Ok((State::Leader, 0))
    } else {
        println!("   {}: Waiting for all my followers to agree", worker.preamble());
        Ok((State::BecomeLeader, 0))
    }
}

fn state_become_follower(worker: &mut Worker) -> BldrResult<(State, u32)> {
    println!("   {}: Becoming a follower", worker.preamble());
    {
        let mut ce = try!(worker.census.me_mut());
        if ce.follower.is_none() {
            ce.follower(Some(true));
        }
    }

    if worker.census.has_leader() {
        println!("   {}: Becoming a follower for real", worker.preamble());
        Ok((State::Follower, 0))
    } else {
        println!("   {}: Waiting for a leader", worker.preamble());
        Ok((State::BecomeFollower, 0))
    }
}

fn state_leader(worker: &mut Worker) -> BldrResult<(State, u32)> {
    {
        let me = try!(worker.census.me_mut());
        if me.election.is_some() {
            me.election(None)
        }
        if me.vote.is_some() {
            me.vote(None)
        }
    }

    if worker.census.in_event {
        worker.census.in_event = false;
    }

    if worker.supervisor_thread.is_none() {
        try!(standalone::state_starting(worker));
    }

    Ok((State::Leader, 0))
}

fn state_follower(worker: &mut Worker) -> BldrResult<(State, u32)> {
    {
        let me = try!(worker.census.me_mut());
        if me.election.is_some() {
            me.election(None);
        }
        if me.vote.is_some() {
            me.vote(None);
        }
    }

    if worker.census.in_event {
        worker.census.in_event = false;
    }

    if worker.supervisor_thread.is_none() {
        try!(standalone::state_starting(worker));
    }

    if ! worker.census.has_leader() {
        Ok((State::DetermineViability, 0))
    } else {
        Ok((State::Follower, 0))
    }
}
<commit_msg>Fixes race condition on initial leader start<commit_after>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// 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 topology::{self, State, Worker};
use state_machine::StateMachine;
use error::{BldrResult, BldrError};
use pkg::Package;
use topology::standalone;
use config::Config;

pub fn run(package: Package, config: &Config) -> BldrResult<()> {
    let mut worker = try!(Worker::new(package, String::from("leader"), config));
    let mut sm: StateMachine<State, Worker, BldrError> = StateMachine::new(State::Init);
    sm.add_dispatch(State::Init, state_init);
    sm.add_dispatch(State::RestoreDataset, state_restore_dataset);
    sm.add_dispatch(State::DetermineViability, state_determine_viability);
    sm.add_dispatch(State::StartElection, state_start_election);
    sm.add_dispatch(State::InElection, state_in_election);
    sm.add_dispatch(State::BecomeLeader, state_become_leader);
    sm.add_dispatch(State::BecomeFollower, state_become_follower);
    sm.add_dispatch(State::Leader, state_leader);
    sm.add_dispatch(State::Follower, state_follower);
    topology::run_internal(&mut sm, &mut worker)
}

fn state_init(worker: &mut Worker) -> Result<(State, u32), BldrError> {
    if worker.census.dataset_initialized() {
        Ok((State::RestoreDataset, 0))
    } else {
        Ok((State::DetermineViability, 0))
    }
}

fn state_restore_dataset(worker: &mut Worker) -> BldrResult<(State, u32)> {
    println!("   {}: Restoring the dataset from a peer", worker.preamble());
    let ce = try!(worker.census.me_mut());
    ce.data_init(Some(true));
    Ok((State::DetermineViability, 0))
}

fn state_determine_viability(worker: &mut Worker) -> BldrResult<(State, u32)> {
    println!("   {}: Determining viability as a leader", worker.preamble());
    worker.census.in_event = true;
    {
        let mut ce = try!(worker.census.me_mut());
        ce.follower(None);
        ce.leader(None);
    }
    if worker.census.has_leader() {
        Ok((State::BecomeFollower, 0))
    } else {
        Ok((State::StartElection, 0))
    }
}

fn state_start_election(worker: &mut Worker) -> BldrResult<(State, u32)> {
    println!("   {}: Starting an election", worker.preamble());
    {
        let mut ce = try!(worker.census.me_mut());
        ce.election = Some(true);
    }
    let candidate = worker.census.determine_vote().candidate_string();
    println!("   {}: My candidate is {:?}", worker.preamble(), candidate);
    let mut ce = try!(worker.census.me_mut());
    ce.vote(Some(candidate));
    Ok((State::InElection, 0))
}

fn state_in_election(worker: &mut Worker) -> BldrResult<(State, u32)> {
    let preamble = worker.preamble();
    let candidate = worker.census.determine_vote().candidate_string();
    {
        let mut ce = try!(worker.census.me_mut());
        match ce.vote {
            Some(ref c) if *c == candidate => {},
            Some(_) => {
                println!("   {}: Switching my vote to {}", preamble, candidate);
                ce.vote(Some(candidate));
            },
            None => {
                println!("   {}: Switching my vote to {}", preamble, candidate);
                ce.vote(Some(candidate));
            }
        }
    }

    if let Some(leader_ce) = worker.census.get_leader() {
        println!("   {}: {} has already been elected; becoming a follower", preamble, leader_ce.candidate_string());
        return Ok((State::BecomeFollower, 0));
    }

    match worker.census.voting_finished() {
        Some(winner) => {
            let me = try!(worker.census.me());
            if me == winner {
                println!("   {}: The votes are in! I won! I will serve with humility.", worker.preamble());
                Ok((State::BecomeLeader, 0))
            } else {
                println!("   {}: The votes are in! I lost! I will serve with grace.", worker.preamble());
                Ok((State::BecomeFollower, 0))
            }
        },
        None => Ok((State::InElection, 10))
    }
}

fn state_become_leader(worker: &mut Worker) -> BldrResult<(State, u32)> {
    if worker.census.has_leader() == false {
        {
            let mut ce = try!(worker.census.me_mut());
            ce.leader = Some(true);
        }
    }

    if worker.census.has_all_followers() {
        println!("   {}: Starting my term as leader", worker.preamble());
        Ok((State::Leader, 0))
    } else {
        println!("   {}: Waiting for all my followers to agree", worker.preamble());
        Ok((State::BecomeLeader, 0))
    }
}

fn state_become_follower(worker: &mut Worker) -> BldrResult<(State, u32)> {
    println!("   {}: Becoming a follower", worker.preamble());
    {
        let mut ce = try!(worker.census.me_mut());
        if ce.follower.is_none() {
            ce.follower(Some(true));
        }
    }

    if worker.census.has_leader() {
        println!("   {}: Becoming a follower for real", worker.preamble());
        Ok((State::Follower, 0))
    } else {
        println!("   {}: Waiting for a leader", worker.preamble());
        Ok((State::BecomeFollower, 0))
    }
}

fn state_leader(worker: &mut Worker) -> BldrResult<(State, u32)> {
    {
        let me = try!(worker.census.me_mut());
        if me.election.is_some() {
            me.election(None)
        }
        if me.vote.is_some() {
            me.vote(None)
        }
    }

    if worker.census.in_event {
        worker.census.in_event = false;
    }

    if worker.supervisor_thread.is_none() {
        try!(standalone::state_starting(worker));
    }

    Ok((State::Leader, 0))
}

fn state_follower(worker: &mut Worker) -> BldrResult<(State, u32)> {
    {
        let me = try!(worker.census.me_mut());
        if me.election.is_some() {
            me.election(None);
        }
        if me.vote.is_some() {
            me.vote(None);
        }
    }

    if worker.census.in_event {
        worker.census.in_event = false;
    }

    if worker.supervisor_thread.is_none() {
        try!(standalone::state_starting(worker));
    }

    if ! worker.census.has_leader() {
        Ok((State::DetermineViability, 0))
    } else {
        Ok((State::Follower, 0))
    }
}
<|endoftext|>


<commit_before>use std::ffi::{OsString, OsStr};

use ops::{self, Compilation};
use util::{self, CargoResult, CargoTestError, ProcessError};
use core::Workspace;

pub struct TestOptions<'a> {
    pub compile_opts: ops::CompileOptions<'a>,
    pub no_run: bool,
    pub no_fail_fast: bool,
    pub only_doc: bool,
}

pub fn run_tests(ws: &Workspace,
                 options: &TestOptions,
                 test_args: &[String]) -> CargoResult<Option<CargoTestError>> {
    let compilation = compile_tests(ws, options)?;

    if options.no_run {
        return Ok(None)
    }
    let mut errors = if options.only_doc {
        run_doc_tests(options, test_args, &compilation)?
    } else {
        run_unit_tests(options, test_args, &compilation)?
    };

    // If we have an error and want to fail fast, return
    if !errors.is_empty() && !options.no_fail_fast {
        return Ok(Some(CargoTestError::new(errors)))
    }

    // If a specific test was requested or we're not running any tests at all,
    // don't run any doc tests.
    if let ops::CompileFilter::Only { .. } = options.compile_opts.filter {
        match errors.len() {
            0 => return Ok(None),
            _ => return Ok(Some(CargoTestError::new(errors)))
        }
    }

    errors.extend(run_doc_tests(options, test_args, &compilation)?);
    if errors.is_empty() {
        Ok(None)
    } else {
        Ok(Some(CargoTestError::new(errors)))
    }
}

pub fn run_benches(ws: &Workspace,
                   options: &TestOptions,
                   args: &[String]) -> CargoResult<Option<CargoTestError>> {
    let mut args = args.to_vec();
    args.push("--bench".to_string());
    let compilation = compile_tests(ws, options)?;

    if options.no_run {
        return Ok(None)
    }
    let errors = run_unit_tests(options, &args, &compilation)?;
    match errors.len() {
        0 => Ok(None),
        _ => Ok(Some(CargoTestError::new(errors))),
    }
}

fn compile_tests<'a>(ws: &Workspace<'a>,
                     options: &TestOptions<'a>)
                     -> CargoResult<Compilation<'a>> {
    let mut compilation = ops::compile(ws, &options.compile_opts)?;
    compilation.tests.sort_by(|a, b| {
        (a.0.package_id(), &a.1).cmp(&(b.0.package_id(), &b.1))
    });
    Ok(compilation)
}

/// Run the unit and integration tests of a project.
fn run_unit_tests(options: &TestOptions,
                  test_args: &[String],
                  compilation: &Compilation)
                  -> CargoResult<Vec<ProcessError>> {
    let config = options.compile_opts.config;
    let cwd = options.compile_opts.config.cwd();

    let mut errors = Vec::new();

    for &(ref pkg, _, ref exe) in &compilation.tests {
        let to_display = match util::without_prefix(exe, &cwd) {
            Some(path) => path,
            None => &**exe,
        };
        let mut cmd = compilation.target_process(exe, pkg)?;
        cmd.args(test_args);
        config.shell().concise(|shell| {
            shell.status("Running", to_display.display().to_string())
        })?;
        config.shell().verbose(|shell| {
            shell.status("Running", cmd.to_string())
        })?;

        if let Err(e) = cmd.exec() {
            errors.push(e);
            if !options.no_fail_fast {
                break
            }
        }
    }
    Ok(errors)
}

fn run_doc_tests(options: &TestOptions,
                 test_args: &[String],
                 compilation: &Compilation)
                 -> CargoResult<Vec<ProcessError>> {
    let mut errors = Vec::new();
    let config = options.compile_opts.config;

    // We don't build/rust doctests if target != host
    if config.rustc()?.host != compilation.target {
        return Ok(errors);
    }

    let libs = compilation.to_doc_test.iter().map(|package| {
        (package, package.targets().iter().filter(|t| t.doctested())
                         .map(|t| (t.src_path(), t.name(), t.crate_name())))
    });

    for (package, tests) in libs {
        for (lib, name, crate_name) in tests {
            config.shell().status("Doc-tests", name)?;
            let mut p = compilation.rustdoc_process(package)?;
            p.arg("--test").arg(lib)
             .arg("--crate-name").arg(&crate_name);

            for &rust_dep in &[&compilation.deps_output] {
                let mut arg = OsString::from("dependency=");
                arg.push(rust_dep);
                p.arg("-L").arg(arg);
            }
            for native_dep in compilation.native_dirs.iter() {
                p.arg("-L").arg(native_dep);
            }

            if test_args.len() > 0 {
                p.arg("--test-args").arg(&test_args.join(" "));
            }

            if let Some(cfgs) = compilation.cfgs.get(&package.package_id()) {
                for cfg in cfgs.iter() {
                    p.arg("--cfg").arg(cfg);
                }
            }

            for (_, libs) in compilation.libraries.iter() {
                for &(ref target, ref lib) in libs.iter() {
                    // Note that we can *only* doctest rlib outputs here.  A
                    // staticlib output cannot be linked by the compiler (it just
                    // doesn't do that). A dylib output, however, can be linked by
                    // the compiler, but will always fail. Currently all dylibs are
                    // built as "static dylibs" where the standard library is
                    // statically linked into the dylib. The doc tests fail,
                    // however, for now as they try to link the standard library
                    // dynamically as well, causing problems. As a result we only
                    // pass `--extern` for rlib deps and skip out on all other
                    // artifacts.
                    if lib.extension() != Some(OsStr::new("rlib")) &&
                       !target.for_host() {
                        continue
                    }
                    let mut arg = OsString::from(target.crate_name());
                    arg.push("=");
                    arg.push(lib);
                    p.arg("--extern").arg(&arg);
                }
            }

            config.shell().verbose(|shell| {
                shell.status("Running", p.to_string())
            })?;
            if let Err(e) = p.exec() {
                errors.push(e);
                if !options.no_fail_fast {
                    return Ok(errors);
                }
            }
        }
    }
    Ok(errors)
}
<commit_msg>Auto merge of #3692 - malbarbo:test-args, r=alexcrichton<commit_after>use std::ffi::{OsString, OsStr};

use ops::{self, Compilation};
use util::{self, CargoResult, CargoTestError, ProcessError};
use core::Workspace;

pub struct TestOptions<'a> {
    pub compile_opts: ops::CompileOptions<'a>,
    pub no_run: bool,
    pub no_fail_fast: bool,
    pub only_doc: bool,
}

pub fn run_tests(ws: &Workspace,
                 options: &TestOptions,
                 test_args: &[String]) -> CargoResult<Option<CargoTestError>> {
    let compilation = compile_tests(ws, options)?;

    if options.no_run {
        return Ok(None)
    }
    let mut errors = if options.only_doc {
        run_doc_tests(options, test_args, &compilation)?
    } else {
        run_unit_tests(options, test_args, &compilation)?
    };

    // If we have an error and want to fail fast, return
    if !errors.is_empty() && !options.no_fail_fast {
        return Ok(Some(CargoTestError::new(errors)))
    }

    // If a specific test was requested or we're not running any tests at all,
    // don't run any doc tests.
    if let ops::CompileFilter::Only { .. } = options.compile_opts.filter {
        match errors.len() {
            0 => return Ok(None),
            _ => return Ok(Some(CargoTestError::new(errors)))
        }
    }

    errors.extend(run_doc_tests(options, test_args, &compilation)?);
    if errors.is_empty() {
        Ok(None)
    } else {
        Ok(Some(CargoTestError::new(errors)))
    }
}

pub fn run_benches(ws: &Workspace,
                   options: &TestOptions,
                   args: &[String]) -> CargoResult<Option<CargoTestError>> {
    let mut args = args.to_vec();
    args.push("--bench".to_string());
    let compilation = compile_tests(ws, options)?;

    if options.no_run {
        return Ok(None)
    }
    let errors = run_unit_tests(options, &args, &compilation)?;
    match errors.len() {
        0 => Ok(None),
        _ => Ok(Some(CargoTestError::new(errors))),
    }
}

fn compile_tests<'a>(ws: &Workspace<'a>,
                     options: &TestOptions<'a>)
                     -> CargoResult<Compilation<'a>> {
    let mut compilation = ops::compile(ws, &options.compile_opts)?;
    compilation.tests.sort_by(|a, b| {
        (a.0.package_id(), &a.1).cmp(&(b.0.package_id(), &b.1))
    });
    Ok(compilation)
}

/// Run the unit and integration tests of a project.
fn run_unit_tests(options: &TestOptions,
                  test_args: &[String],
                  compilation: &Compilation)
                  -> CargoResult<Vec<ProcessError>> {
    let config = options.compile_opts.config;
    let cwd = options.compile_opts.config.cwd();

    let mut errors = Vec::new();

    for &(ref pkg, _, ref exe) in &compilation.tests {
        let to_display = match util::without_prefix(exe, &cwd) {
            Some(path) => path,
            None => &**exe,
        };
        let mut cmd = compilation.target_process(exe, pkg)?;
        cmd.args(test_args);
        config.shell().concise(|shell| {
            shell.status("Running", to_display.display().to_string())
        })?;
        config.shell().verbose(|shell| {
            shell.status("Running", cmd.to_string())
        })?;

        if let Err(e) = cmd.exec() {
            errors.push(e);
            if !options.no_fail_fast {
                break
            }
        }
    }
    Ok(errors)
}

fn run_doc_tests(options: &TestOptions,
                 test_args: &[String],
                 compilation: &Compilation)
                 -> CargoResult<Vec<ProcessError>> {
    let mut errors = Vec::new();
    let config = options.compile_opts.config;

    // We don't build/rust doctests if target != host
    if config.rustc()?.host != compilation.target {
        return Ok(errors);
    }

    let libs = compilation.to_doc_test.iter().map(|package| {
        (package, package.targets().iter().filter(|t| t.doctested())
                         .map(|t| (t.src_path(), t.name(), t.crate_name())))
    });

    for (package, tests) in libs {
        for (lib, name, crate_name) in tests {
            config.shell().status("Doc-tests", name)?;
            let mut p = compilation.rustdoc_process(package)?;
            p.arg("--test").arg(lib)
             .arg("--crate-name").arg(&crate_name);

            for &rust_dep in &[&compilation.deps_output] {
                let mut arg = OsString::from("dependency=");
                arg.push(rust_dep);
                p.arg("-L").arg(arg);
            }
            for native_dep in compilation.native_dirs.iter() {
                p.arg("-L").arg(native_dep);
            }

            for arg in test_args {
                p.arg("--test-args").arg(arg);
            }

            if let Some(cfgs) = compilation.cfgs.get(&package.package_id()) {
                for cfg in cfgs.iter() {
                    p.arg("--cfg").arg(cfg);
                }
            }

            for (_, libs) in compilation.libraries.iter() {
                for &(ref target, ref lib) in libs.iter() {
                    // Note that we can *only* doctest rlib outputs here.  A
                    // staticlib output cannot be linked by the compiler (it just
                    // doesn't do that). A dylib output, however, can be linked by
                    // the compiler, but will always fail. Currently all dylibs are
                    // built as "static dylibs" where the standard library is
                    // statically linked into the dylib. The doc tests fail,
                    // however, for now as they try to link the standard library
                    // dynamically as well, causing problems. As a result we only
                    // pass `--extern` for rlib deps and skip out on all other
                    // artifacts.
                    if lib.extension() != Some(OsStr::new("rlib")) &&
                       !target.for_host() {
                        continue
                    }
                    let mut arg = OsString::from(target.crate_name());
                    arg.push("=");
                    arg.push(lib);
                    p.arg("--extern").arg(&arg);
                }
            }

            config.shell().verbose(|shell| {
                shell.status("Running", p.to_string())
            })?;
            if let Err(e) = p.exec() {
                errors.push(e);
                if !options.no_fail_fast {
                    return Ok(errors);
                }
            }
        }
    }
    Ok(errors)
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.
 */

#![crate_name="thrift-client"]
#![crate_type="bin"]

#[allow(dead_code)]
struct ThriftBinaryProtocol {
    x: i32,
}

impl ThriftBinaryProtocol {

    fn new() -> ThriftBinaryProtocol {
        ThriftBinaryProtocol { x: 0 }
    }

    fn write_message_begin(&self, name: &str, message_type: i32, seq_id: i32) -> i32 {
        println!("Protocol: message begin");

        // TODO: strict write
        let mut wsize: i32 = 0;
        wsize += self.write_string(name);
        wsize += self.write_byte(message_type as i8);
        wsize += self.write_i32(seq_id);
        wsize
    }

    fn write_string(&self, s: &str) -> i32 {
        println!("Protocol: {}", s);
        s.len() as i32
    }

    fn write_byte(&self, b: i8) -> i32 {
        println!("Protocol: {}", b);
        1
    }

    fn write_i32(&self, i: i32) -> i32 {
        println!("Protocol: {}", i);
        4
    }

    fn write_message_end(&self) {
        println!("Protocol: end");
    }
}

#[allow(dead_code)]
struct CalculatorPingArgs {
    dummy: i32  // TODO
}

impl CalculatorPingArgs {

    fn new() -> CalculatorPingArgs {
        CalculatorPingArgs { dummy: 1 }
    }

    fn write(&self, oprot: &ThriftBinaryProtocol) {
        println!("CalculatorPingArgs::write");
    }
}

#[allow(dead_code)]
struct CalculatorClient {
    oprotocol: ThriftBinaryProtocol,
    iprotocol: ThriftBinaryProtocol,
}

impl CalculatorClient {

    fn new(protocol: ThriftBinaryProtocol) -> CalculatorClient {
        CalculatorClient { oprotocol: protocol, iprotocol: protocol }
    }

    fn ping(&self) {
        self.send_ping();
        self.receive_ping();
    }

    fn send_ping(&self) {
        let cseqid: i32 = 0;
        let T_CALL = 0; // TODO
        self.oprotocol.write_message_begin("ping", T_CALL, cseqid);

        let args = CalculatorPingArgs::new();
        args.write(&self.oprotocol);

        self.oprotocol.write_message_end();
        // TODO:
//        self.oprotocol.get_transport().write_end();
//        self.oprotocol.get_transport().flush();
    }

    fn receive_ping(&self) {
        // TODO
    }
}

pub fn main() {
    //let socket = ThriftSocket::new("localhost", 9090);
    //let transport = ThriftBufferedTransport::new(socket);

    let protocol = ThriftBinaryProtocol::new( /*transport*/);
    let client = CalculatorClient::new(protocol);

    //transport.open();

    client.ping();

    println!("PASS")
}
<commit_msg>Cleaned up rust_client slightly<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.
 */

#![crate_name="thrift-client"]
#![crate_type="bin"]

// TODO: move to TProtocol
#[allow(dead_code)]
#[allow(non_camel_case_types)]
enum MessageType {
    T_CALL = 1,
    T_REPLY = 2,
    T_EXCEPTION = 3,
    T_ONEWAY = 4,
}

#[allow(dead_code)]
struct ThriftBinaryProtocol {
    x: i32,
}

impl ThriftBinaryProtocol {

    fn new() -> ThriftBinaryProtocol {
        ThriftBinaryProtocol { x: 0 }
    }

    fn write_message_begin(&self, name: &str, message_type: MessageType, seq_id: i32) -> i32 {
        println!("Protocol: message begin");

        // TODO: strict write
        let mut wsize: i32 = 0;
        wsize += self.write_string(name);
        wsize += self.write_byte(message_type as i8);
        wsize += self.write_i32(seq_id);
        wsize
    }

    fn write_string(&self, s: &str) -> i32 {
        println!("Protocol: {}", s);
        s.len() as i32
    }

    fn write_byte(&self, b: i8) -> i32 {
        println!("Protocol: {}", b);
        1
    }

    fn write_i32(&self, i: i32) -> i32 {
        println!("Protocol: {}", i);
        4
    }

    fn write_message_end(&self) -> i32 {
        println!("Protocol: end");
        0
    }
}

#[allow(dead_code)]
struct CalculatorPingArgs;

impl CalculatorPingArgs {

    #[allow(unused_variables)]
    fn write(&self, oprot: &ThriftBinaryProtocol) {
        println!("CalculatorPingArgs::write");
    }
}

#[allow(dead_code)]
struct CalculatorClient<'a> {
    oprotocol: &'a ThriftBinaryProtocol,
    iprotocol: &'a ThriftBinaryProtocol,
}

impl<'a> CalculatorClient<'a> {

    fn new(protocol: &ThriftBinaryProtocol) -> CalculatorClient {
        CalculatorClient { oprotocol: protocol, iprotocol: protocol }
    }

    fn ping(&self) {
        self.send_ping();
        self.receive_ping();
    }

    fn send_ping(&self) {
        let cseqid: i32 = 0;
        self.oprotocol.write_message_begin("ping", MessageType::T_CALL, cseqid);

        let args = CalculatorPingArgs;
        args.write(self.oprotocol);

        self.oprotocol.write_message_end();
        // TODO:
//        self.oprotocol.get_transport().write_end();
//        self.oprotocol.get_transport().flush();
    }

    fn receive_ping(&self) {
        // TODO
    }
}

pub fn main() {
    //let socket = ThriftSocket::new("localhost", 9090);
    //let transport = ThriftBufferedTransport::new(socket);

    let protocol = ThriftBinaryProtocol::new( /*transport*/);
    let client = CalculatorClient::new(&protocol);

    //transport.open();

    client.ping();

    println!("PASS")
}
<|endoftext|>


<commit_before>// Copyright 2018 The Exonum Team
//
// 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.

//! An implementation of `Error` type.

/// The error type for I/O operations with storage.
#[derive(Fail, Debug, Clone)]
#[fail(display = "{}", message)]
pub struct Error {
    message: String,
}

impl Error {
    /// Creates a new storage error with an information message about the reason.
    ///
    /// # Examples
    ///
    /// ```
    /// use exonum::storage::Error;
    ///
    /// let error = Error::new("Oh no!");
    /// ```
    pub fn new<T: Into<String>>(message: T) -> Error {
        Error {
            message: message.into(),
        }
    }
}
<commit_msg>Make storage error constructor private (pub crate) (#689)<commit_after>// Copyright 2018 The Exonum Team
//
// 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.

//! An implementation of `Error` type.

/// The error type for I/O operations with storage.
#[derive(Fail, Debug, Clone)]
#[fail(display = "{}", message)]
pub struct Error {
    message: String,
}

impl Error {
    /// Creates a new storage error with an information message about the reason.
    pub(crate) fn new<T: Into<String>>(message: T) -> Error {
        Error {
            message: message.into(),
        }
    }
}
<|endoftext|>


<commit_before>extern mod extra;
extern mod std;

use std::hashmap::HashMap;

use extra::json::List;
use extra::json::Number;
use extra::json::Object;
use extra::json::String;
use extra::json::from_str;
use extra::json::Json;
use JsonError = extra::json::Error;

fn emptyObjectExample() {
    let o:~HashMap<~str, Json> = match from_str("{}") {
        Ok(Object(o)) => {
            o
        },
        Ok(_) => {
            fail!("Expected an object after parsing");
        },
        Err(e) => {
            println(fmt!("ERROR: %?", e));
            fail!("What, no parsing?");
        }
    };
    let mut counter = 0;
    for o.iter().advance() |k| {
        counter += 1;
    }
    println(fmt!("0 = %?", counter));
}

fn simpleObjectWithANumber() {
    match from_str("{\"foo\": 33}") {
        Ok(Object(o)) => {
            let map: ~HashMap<~str, Json> = o;
            println(fmt!("true = %?\n", map.contains_key(&~"foo")));
            if (map.contains_key(&~"foo")) {
                let foo = match map.find(&~"foo") {
                    Some( & Number(value)) =>  {
                            value
                    },
                    Some(_) => fail!("foo was wrong type"),
                    None => fail!("No element")
                };
                println(fmt!("33 = %?\n", foo))
            } else {
                println("No key foo")
            }
        },
        Ok(_) => {
            println(fmt!("Unexpected JSON value"));
        },
        Err(e) => {
            println(fmt!("ERROR: %?\n", e));
        }
    }
}

fn listObjects() {
  let j:Result<Json,JsonError> = from_str("[{\"bar\":\"baz\", \"biz\":123}]");
  let l:List = match j {
    Ok(List(l)) => l,
    Ok(_) => fail!("Expected a list at the top level"),
    Err(e) => fail!(fmt!("Error: %?", e))
  };
  println(fmt!("item = %?", l.iter().advance(|i|{
    let item:Json = copy *i;
    match item {
        Object(o) => {
            println(fmt!("true = %?", o.contains_key(&~"bar")));
            //let barItem = ;
            let baz = match copy *o.get(&~"bar") {
                String(abaz) => abaz,
                _ => fail!("Expected bar property")
            };
            println(fmt!("bar = %?", baz));

            println(fmt!("true = %?", o.contains_key(&~"biz")));
            //let barItem = ;
            let biz = match *o.get_copy(&~"biz") {
                Number(abiz) => abiz,
                _ => fail!("Expected biz property")
            };
            println(fmt!("biz = %?", biz));

        },
        _ => {
            fail!("Should be a list of objects, no?");
        }
    }
    true
  })));

}

fn main() {
    emptyObjectExample();
    simpleObjectWithANumber();
    listObjects();
}<commit_msg>Finished list of objects<commit_after>extern mod extra;
extern mod std;

use std::hashmap::HashMap;

use extra::json::List;
use extra::json::Number;
use extra::json::Object;
use extra::json::String;
use extra::json::from_str;
use extra::json::Json;
use JsonError = extra::json::Error;

fn emptyObjectExample() {
    let o:~HashMap<~str, Json> = match from_str("{}") {
        Ok(Object(o)) => {
            o
        },
        Ok(_) => {
            fail!("Expected an object after parsing");
        },
        Err(e) => {
            println(fmt!("ERROR: %?", e));
            fail!("What, no parsing?");
        }
    };
    let mut counter = 0;
    for o.iter().advance() |k| {
        counter += 1;
    }
    println(fmt!("0 = %?", counter));
}

fn simpleObjectWithANumber() {
    match from_str("{\"foo\": 33}") {
        Ok(Object(o)) => {
            let map: ~HashMap<~str, Json> = o;
            println(fmt!("true = %?\n", map.contains_key(&~"foo")));
            if (map.contains_key(&~"foo")) {
                let foo = match map.find(&~"foo") {
                    Some( & Number(value)) =>  {
                            value
                    },
                    Some(_) => fail!("foo was wrong type"),
                    None => fail!("No element")
                };
                println(fmt!("33 = %?\n", foo))
            } else {
                println("No key foo")
            }
        },
        Ok(_) => {
            println(fmt!("Unexpected JSON value"));
        },
        Err(e) => {
            println(fmt!("ERROR: %?\n", e));
        }
    }
}

fn listObjects() {
  let j:Result<Json,JsonError> = from_str("[{\"bar\":\"baz\", \"biz\":123}]");
  let l:List = match j {
    Ok(List(l)) => l,
    Ok(_) => fail!("Expected a list at the top level"),
    Err(e) => fail!(fmt!("Error: %?", e))
  };
  println(fmt!("item = %?", l.iter().advance(|i|{
    let item:Json = copy *i;
    match item {
        Object(o) => {
            println(fmt!("true = %?", o.contains_key(&~"bar")));
            //let barItem = ;
            let baz = match copy *o.get(&~"bar") {
                String(abaz) => abaz,
                _ => fail!("Expected bar property")
            };
            println(fmt!("bar = %?", baz));

            println(fmt!("true = %?", o.contains_key(&~"biz")));
            //let barItem = ;
            let biz = match copy *o.get(&~"biz") {
                Number(abiz) => abiz,
                _ => fail!("Expected biz property")
            };
            println(fmt!("biz = %?", biz));
        },
        _ => {
            fail!("Should be a list of objects, no?");
        }
    }
    true
  })));

}

fn main() {
    emptyObjectExample();
    simpleObjectWithANumber();
    listObjects();
}<|endoftext|>


<commit_before>use crate::bvh::BVHNode;
use crate::camera::PTCamera;
use crate::color::Color;
use crate::config::*;
use crate::float::*;
use crate::intersect::Ray;
use crate::scene::Scene;

mod vertex;

use self::vertex::*;

#[allow(clippy::if_same_then_else)]
pub fn bdpt<'a>(
    camera_ray: Ray,
    scene: &'a Scene,
    camera: &'a PTCamera,
    config: &RenderConfig,
    node_stack: &mut Vec<(&'a BVHNode, Float)>,
) -> Color {
    let camera_vertex = CameraVertex::new(camera, camera_ray);
    let (beta, ray) = camera_vertex.sample_next();
    let camera_path = generate_path(beta, ray, scene, config, node_stack);
    let (light, light_pdf) = match config.light_mode {
        LightMode::Scene => scene.sample_light().unwrap_or((camera.flash(), 1.0)),
        LightMode::Camera => (camera.flash(), 1.0),
    };
    let (light_pos, pos_pdf) = light.sample_pos();
    let light_vertex = LightVertex::new(light, light_pos, light_pdf * pos_pdf);
    let (beta, ray) = light_vertex.sample_next();
    let light_path = generate_path(beta, ray, scene, config, node_stack);
    let mut c = Color::black();
    // Paths contain vertices after the light / camera
    // 0 corresponds to no vertices from that subpath,
    // 1 is the starting vertex
    // 2+ are regular path vertices
    for s in (0..light_path.len() + 2).rev() {
        // Light path can't hit camera so start t from 1
        for t in (1..camera_path.len() + 2).rev() {
            // TODO: handle rr
            if s + t < 2 || s + t - 2 > config.bounces {
                continue;
            }
            // No light vertices
            let (radiance, path) = if s == 0 {
                if let Some(vertex) = camera_path.get(t - 2) {
                    if let Some(light_vertex) = vertex.to_light_vertex(&scene) {
                        let path = BDPath::new(light_vertex, &[],
                                               &camera_vertex, &camera_path[0..t - 2]);
                        (vertex.path_radiance(), path)
                    } else {
                        continue;
                    }
                } else {
                    continue;
                }
            // Connect camera and light
            } else if s == 1 && t == 1 {
                // TODO
                continue;
            // Connect light vertex to camera
            } else if t == 1 {
                // TODO
                continue;
            // Connect camera vertex to light
            } else if s == 1 {
                let c_vertex = &camera_path[t - 2];
                let (mut connection_ray, radiance) = light_vertex.connect_to(c_vertex);
                if !radiance.is_black() && scene.intersect(&mut connection_ray, node_stack).is_none() {
                    let path = BDPath::new(light_vertex.clone(), &[],
                                           &camera_vertex, &camera_path[0..=t - 2]);
                    (radiance, path)
                } else {
                    continue;
                }
            // Everything else
            } else {
                let l_vertex = &light_path[s - 2];
                let c_vertex = &camera_path[t - 2];
                let (mut connection_ray, radiance) = l_vertex.connect_to(c_vertex);
                if !radiance.is_black() && scene.intersect(&mut connection_ray, node_stack).is_none() {
                    let path = BDPath::new(light_vertex.clone(), &light_path[0..=s - 2],
                                           &camera_vertex, &camera_path[0..=t - 2]);
                    (radiance, path)
                } else {
                    continue;
                }
            };
            if true {
                // MIS
                let weight = if s + t == 2 {
                    1.0
                } else {
                    let pdf_strat = path.pdf(s, t).unwrap();
                    let mut sum_pdf = 0.0;
                    for i in 2..=s + t {
                        if let Some(pdf) = path.pdf(s + t - i, i) {
                            sum_pdf += pdf;
                        }
                    }
                    pdf_strat / sum_pdf
                };
                c += weight * radiance;
            } else {
                // uniform scale
                c += radiance / (s + t - 1).to_float();
            }
        }
    }
    c
}

fn generate_path<'a>(
    mut beta: Color,
    mut ray: Ray,
    scene: &'a Scene,
    config: &RenderConfig,
    node_stack: &mut Vec<(&'a BVHNode, Float)>,
) -> Vec<SurfaceVertex<'a>> {
    let mut bounce = 0;
    let mut path = Vec::new();
    while let Some(hit) = scene.intersect(&mut ray, node_stack) {
        path.push(SurfaceVertex::new(
            ray.clone(),
            beta,
            hit.interaction(&config),
        ));
        let isect = &path.last().unwrap().isect;
        let mut pdf = 1.0;
        let terminate = if bounce < config.bounces {
            false
        } else if config.russian_roulette {
            // Survival probability
            let prob = beta.luma().min(0.95);
            pdf *= prob;
            rand::random::<Float>() > prob
        } else {
            true
        };
        if !terminate {
            // TODO: account for non-symmetry
            if let Some((bsdf, new_ray, bsdf_pdf)) = isect.sample_bsdf(-ray.dir) {
                ray = new_ray;
                pdf *= bsdf_pdf;
                beta *= isect.cos_t(ray.dir).abs() * bsdf / pdf;
                bounce += 1;
            } else {
                break;
            }
        } else {
            break;
        }
    }
    path
}
<commit_msg>Implement power heuristic<commit_after>use crate::bvh::BVHNode;
use crate::camera::PTCamera;
use crate::color::Color;
use crate::config::*;
use crate::float::*;
use crate::intersect::Ray;
use crate::scene::Scene;

mod vertex;

use self::vertex::*;

#[allow(clippy::if_same_then_else)]
pub fn bdpt<'a>(
    camera_ray: Ray,
    scene: &'a Scene,
    camera: &'a PTCamera,
    config: &RenderConfig,
    node_stack: &mut Vec<(&'a BVHNode, Float)>,
) -> Color {
    let camera_vertex = CameraVertex::new(camera, camera_ray);
    let (beta, ray) = camera_vertex.sample_next();
    let camera_path = generate_path(beta, ray, scene, config, node_stack);
    let (light, light_pdf) = match config.light_mode {
        LightMode::Scene => scene.sample_light().unwrap_or((camera.flash(), 1.0)),
        LightMode::Camera => (camera.flash(), 1.0),
    };
    let (light_pos, pos_pdf) = light.sample_pos();
    let light_vertex = LightVertex::new(light, light_pos, light_pdf * pos_pdf);
    let (beta, ray) = light_vertex.sample_next();
    let light_path = generate_path(beta, ray, scene, config, node_stack);
    let mut c = Color::black();
    // Paths contain vertices after the light / camera
    // 0 corresponds to no vertices from that subpath,
    // 1 is the starting vertex
    // 2+ are regular path vertices
    for s in (0..light_path.len() + 2).rev() {
        // Light path can't hit camera so start t from 1
        for t in (1..camera_path.len() + 2).rev() {
            // TODO: handle rr
            if s + t < 2 || s + t - 2 > config.bounces {
                continue;
            }
            // No light vertices
            let (radiance, path) = if s == 0 {
                if let Some(vertex) = camera_path.get(t - 2) {
                    if let Some(light_vertex) = vertex.to_light_vertex(&scene) {
                        let path = BDPath::new(light_vertex, &[],
                                               &camera_vertex, &camera_path[0..t - 2]);
                        (vertex.path_radiance(), path)
                    } else {
                        continue;
                    }
                } else {
                    continue;
                }
            // Connect camera and light
            } else if s == 1 && t == 1 {
                // TODO
                continue;
            // Connect light vertex to camera
            } else if t == 1 {
                // TODO
                continue;
            // Connect camera vertex to light
            } else if s == 1 {
                let c_vertex = &camera_path[t - 2];
                let (mut connection_ray, radiance) = light_vertex.connect_to(c_vertex);
                if !radiance.is_black() && scene.intersect(&mut connection_ray, node_stack).is_none() {
                    let path = BDPath::new(light_vertex.clone(), &[],
                                           &camera_vertex, &camera_path[0..=t - 2]);
                    (radiance, path)
                } else {
                    continue;
                }
            // Everything else
            } else {
                let l_vertex = &light_path[s - 2];
                let c_vertex = &camera_path[t - 2];
                let (mut connection_ray, radiance) = l_vertex.connect_to(c_vertex);
                if !radiance.is_black() && scene.intersect(&mut connection_ray, node_stack).is_none() {
                    let path = BDPath::new(light_vertex.clone(), &light_path[0..=s - 2],
                                           &camera_vertex, &camera_path[0..=t - 2]);
                    (radiance, path)
                } else {
                    continue;
                }
            };
            if true {
                // MIS
                let weight = if s + t == 2 {
                    1.0
                } else {
                    let power = 2;
                    let pdf_strat = path.pdf(s, t).unwrap().powi(power);
                    let mut sum_pdf = 0.0;
                    for i in 2..=s + t {
                        if let Some(pdf) = path.pdf(s + t - i, i) {
                            sum_pdf += pdf.powi(power);
                        }
                    }
                    pdf_strat / sum_pdf
                };
                c += weight * radiance;
            } else {
                // uniform scale
                c += radiance / (s + t - 1).to_float();
            }
        }
    }
    c
}

fn generate_path<'a>(
    mut beta: Color,
    mut ray: Ray,
    scene: &'a Scene,
    config: &RenderConfig,
    node_stack: &mut Vec<(&'a BVHNode, Float)>,
) -> Vec<SurfaceVertex<'a>> {
    let mut bounce = 0;
    let mut path = Vec::new();
    while let Some(hit) = scene.intersect(&mut ray, node_stack) {
        path.push(SurfaceVertex::new(
            ray.clone(),
            beta,
            hit.interaction(&config),
        ));
        let isect = &path.last().unwrap().isect;
        let mut pdf = 1.0;
        let terminate = if bounce < config.bounces {
            false
        } else if config.russian_roulette {
            // Survival probability
            let prob = beta.luma().min(0.95);
            pdf *= prob;
            rand::random::<Float>() > prob
        } else {
            true
        };
        if !terminate {
            // TODO: account for non-symmetry
            if let Some((bsdf, new_ray, bsdf_pdf)) = isect.sample_bsdf(-ray.dir) {
                ray = new_ray;
                pdf *= bsdf_pdf;
                beta *= isect.cos_t(ray.dir).abs() * bsdf / pdf;
                bounce += 1;
            } else {
                break;
            }
        } else {
            break;
        }
    }
    path
}
<|endoftext|>


<commit_before>use crossbeam::channel::unbounded;
use rosrust;
use std::collections::BTreeSet;
use std::process::Command;

mod util;

mod msg {
    rosrust::rosmsg_include!(rosgraph_msgs / Log);
}

#[test]
fn can_read_log_from_rosout_for_rosrust() {
    let _roscore = util::run_roscore_for(util::Language::Multi, util::Feature::Log);
    let _publisher_cpp = util::ChildProcessTerminator::spawn(
        Command::new("rosrun")
            .arg("roscpp_tutorials")
            .arg("talker")
            .arg("__name:=talker_cpp"),
    );
    let _publisher_py = util::ChildProcessTerminator::spawn(
        Command::new("rosrun")
            .arg("rospy_tutorials")
            .arg("talker")
            .arg("__name:=talker_py"),
    );
    let _publisher_rust = util::ChildProcessTerminator::spawn_example(
        "../examples/pubsub",
        Command::new("cargo")
            .arg("run")
            .arg("--bin")
            .arg("publisher")
            .arg("__name:=talker_rust"),
    );

    rosrust::init("rosout_agg_listener");

    let (tx, rx) = unbounded();

    let _subscriber =
        rosrust::subscribe::<msg::rosgraph_msgs::Log, _>("/rosout_agg", 100, move |data| {
            tx.send((data.level, data.name, data.msg)).unwrap();
        })
        .unwrap();

    let mut rate = rosrust::rate(1.0);

    let mut expected_messages = BTreeSet::new();
    expected_messages.insert("/talker_cpp");
    expected_messages.insert("/talker_py");
    expected_messages.insert("/talker_rust");

    for _ in 0..10 {
        for (level, name, message) in rx.try_iter() {
            println!(
                "Received message from {} at level {}: {}",
                name, level, message
            );
            if level == 2 && message.contains("hello world") {
                expected_messages.remove(name.as_str());
            }
        }
        if expected_messages.is_empty() {
            return;
        }
        rate.sleep();
    }

    panic!("Failed to receive data on /rosout_agg");
}
<commit_msg>Create failing test for multiple rosout publishers<commit_after>use crossbeam::channel::unbounded;
use rosrust;
use std::collections::BTreeSet;
use std::process::Command;

mod util;

mod msg {
    rosrust::rosmsg_include!(rosgraph_msgs / Log);
}

#[test]
fn can_read_log_from_rosout_for_multiple() {
    let _roscore = util::run_roscore_for(util::Language::Multi, util::Feature::Log);
    let _publisher_cpp = util::ChildProcessTerminator::spawn(
        Command::new("rosrun")
            .arg("roscpp_tutorials")
            .arg("talker")
            .arg("__name:=talker_cpp"),
    );
    let _publisher_py = util::ChildProcessTerminator::spawn(
        Command::new("rosrun")
            .arg("rospy_tutorials")
            .arg("talker")
            .arg("__name:=talker_py"),
    );
    let _publisher_rust = util::ChildProcessTerminator::spawn_example(
        "../examples/pubsub",
        Command::new("cargo")
            .arg("run")
            .arg("--bin")
            .arg("publisher")
            .arg("__name:=talker_rust"),
    );

    rosrust::init("rosout_agg_listener");

    let (tx, rx) = unbounded();
    let tx_agg = tx.clone();

    let _subscriber =
        rosrust::subscribe::<msg::rosgraph_msgs::Log, _>("/rosout", 100, move |data| {
            tx.send((false, data.level, data.name, data.msg)).unwrap();
        })
        .unwrap();

    let _subscriber_agg =
        rosrust::subscribe::<msg::rosgraph_msgs::Log, _>("/rosout_agg", 100, move |data| {
            tx_agg
                .send((true, data.level, data.name, data.msg))
                .unwrap();
        })
        .unwrap();

    let mut rate = rosrust::rate(1.0);

    let mut expected_messages = BTreeSet::new();
    expected_messages.insert((true, "/talker_cpp".to_owned()));
    expected_messages.insert((false, "/talker_cpp".to_owned()));
    expected_messages.insert((true, "/talker_py".to_owned()));
    expected_messages.insert((false, "/talker_py".to_owned()));
    expected_messages.insert((true, "/talker_rust".to_owned()));
    expected_messages.insert((false, "/talker_rust".to_owned()));

    for _ in 0..10 {
        for (aggregated, level, name, message) in rx.try_iter() {
            println!(
                "Received {}message from {} at level {}: {}",
                if aggregated { "aggregated " } else { "" },
                name,
                level,
                message,
            );
            if level == 2 && message.contains("hello world") {
                expected_messages.remove(&(aggregated, name));
            }
        }
        if expected_messages.is_empty() {
            return;
        }
        rate.sleep();
    }

    let cases = expected_messages
        .iter()
        .map(|(aggregated, name)| {
            format!(
                "{} on {}",
                name,
                if *aggregated {
                    "/rosout_agg"
                } else {
                    "/rosout"
                },
            )
        })
        .collect::<Vec<String>>();

    panic!("Failed to receive data from: {:?}", cases);
}
<|endoftext|>


<commit_before>// Copyright 2018 Chao Lin & William Sergeant (Sorbonne University)

// 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.

#![macro_use]
use middle::analysis::ast::*;
use ast::Expression::*;
use std::cmp;
use syntax::codemap::BytePos;
pub use rust::NO_EXPANSION;

enum Predicate {
    And(usize),
    Not(usize),
    Oom(usize),
    Zom(usize),
    Nothing
}

enum VecType {
    And,
    OneOrMore,
    Nothing
}

pub struct UselessChaining<'a: 'c, 'b: 'a, 'c>
{
  grammar: &'c AGrammar<'a, 'b>,
  pred: Predicate,
  vec_pred : Vec<Predicate>,
  vec_type : VecType
}

impl <'a, 'b, 'c> UselessChaining<'a, 'b, 'c>
{
  pub fn analyse(grammar: AGrammar<'a, 'b>) -> Partial<AGrammar<'a, 'b>> {
    UselessChaining::check_chaining(&grammar);
    Partial::Value(grammar)
  }

  fn check_chaining(grammar: &'c AGrammar<'a, 'b>){
    let mut analyser = UselessChaining{
      grammar: grammar,
      pred: Predicate::Nothing,
      vec_pred: vec![],
      vec_type: VecType::Nothing
    };
    for rule in &grammar.rules {
      analyser.visit_expr(rule.expr_idx)
    }
  }

  fn span_end_point(&self, sp: Span) -> Span{
      let lo = cmp::max(sp.hi().0 - 1, sp.lo().0);
      sp.with_lo(BytePos(lo))
  }

  fn get_th(&self, n: usize) -> &'static str {
      match n {
          1 => "st",
          2 => "nd",
          3 => "rd",
          _ => "th"
      }
  }

  fn warn_useless_chaining(&self, pred: (&'static str, &'static str, &'static str, &'static str), span2: Span, span1: Span){
      let (detected,help,first,second) = pred;
      self.grammar.span_warn(
          span1,
          format!(
              "Detected useless chaining: {}
              \nHelp: {}
              \n1{} predicate {}"
          ,detected,help,self.get_th(1),first)
      );
      self.grammar.span_note(
          span2,
          format!("2{} predicate {}",self.get_th(2),second)
      )
  }

  fn warn_vec_useless_chaining(&self, pred: (&'static str, &'static str, &'static str), i: usize, span: Span){
      let (warn,note,span_note) = pred;
      if i==0 {
          self.grammar.span_warn(
              span,
              format!(
                  "Detected useless chaining: multiple {}
                  \nHelp: {}
                  \n1{} occurence of {}"
              ,warn,note,self.get_th(1),warn)
          )
      }
      else{
          self.grammar.span_note(
              span,
              format!("{}{} occurence of {}",i+1,self.get_th(i+1),span_note)
          )
      }

  }

  fn warn_verify_multiple(&self) {
      for (i, x) in self.vec_pred.iter().enumerate() {
          match x {
              &Predicate::And(this) => {
                  let lo = self.grammar[this].span().lo();
                  let span = Span::new(lo,lo,NO_EXPANSION);
                  self.warn_vec_useless_chaining(("&","&(&e) -> &e","and"),i,span);
              }
              &Predicate::Oom(this) => {
                  let sp = self.grammar[this].span();
                  let span = self.span_end_point(sp);
                  self.warn_vec_useless_chaining(("+","(e+)+ -> e+","one or more"),i,span);
              }
              _ => unreachable!()
          }
      }
  }

  fn verify_multiple(&mut self){
      if self.vec_pred.len()>=2 {
          self.warn_verify_multiple()
      }
      self.vec_pred.clear();
      self.vec_type=VecType::Nothing;
  }

  fn warning(&mut self, current: Predicate){
      match (&self.pred, current) {
          (&Predicate::Zom(t),Predicate::Oom(this)) => {
              self.warn_useless_chaining(
                  ("(e+)*","(e+)* -> e+","One or more","Zero or more"),
                  self.span_end_point(self.grammar[this].span()),
                  self.span_end_point(self.grammar[t].span())
              );
          }
          (&Predicate::Not(t),Predicate::Not(this)) => {
              let f_lo = self.grammar[this].span().lo();
              let s_lo = self.grammar[t].span().lo();
              self.warn_useless_chaining(
                  ("!(!e)","!(!e) -> &e","not","not"),
                  Span::new(f_lo, f_lo, NO_EXPANSION),
                  Span::new(s_lo, s_lo, NO_EXPANSION)
              );
          }
          (&Predicate::And(t),Predicate::Not(this)) => {
              let f_lo = self.grammar[this].span().lo();
              let s_lo = self.grammar[t].span().lo();
              self.warn_useless_chaining(
                  ("&(!e)","&(!e) -> !e","not","and"),
                  Span::new(f_lo, f_lo, NO_EXPANSION),
                  Span::new(s_lo, s_lo, NO_EXPANSION)
              );
          }
          (&Predicate::Not(t),Predicate::And(this)) => {
              let f_lo = self.grammar[this].span().lo();
              let s_lo = self.grammar[t].span().lo();
              self.warn_useless_chaining(
                  ("!(&e)","!(&e) -> !e","and","not"),
                  Span::new(f_lo, f_lo, NO_EXPANSION),
                  Span::new(s_lo, s_lo, NO_EXPANSION)
              );
          }
          _ => {}
      }
  }

 }

impl<'a, 'b, 'c> ExprByIndex for UselessChaining<'a, 'b, 'c>
{
  fn expr_by_index(&self, index: usize) -> Expression {
    self.grammar.expr_by_index(index).clone()
  }
}

impl<'a, 'b, 'c> Visitor<()> for UselessChaining<'a, 'b, 'c>
{
  fn visit_str_literal(&mut self, _this: usize, _lit: String){
      self.pred=Predicate::Nothing;
      self.verify_multiple();
  }

  fn visit_non_terminal_symbol(&mut self, _this: usize, rule: Ident){
      let predicate = self.grammar.find_rule_by_ident(rule).expr_idx;
      match self.expr_by_index(predicate){
          ZeroOrMore(_child) => {
            self.warning(Predicate::Zom(predicate));
          }
          OneOrMore(_child) => {
            self.warning(Predicate::Oom(predicate));
            match self.vec_type {
                VecType::OneOrMore => {
                    self.vec_pred.push(Predicate::Oom(predicate));
                }
                _ => ()
            }
          }
          NotPredicate(_child) => {
            self.warning(Predicate::Not(predicate));
          }
          AndPredicate(_child) => {
            self.warning(Predicate::And(predicate));
            match self.vec_type {
                VecType::And => {
                    self.vec_pred.push(Predicate::And(predicate));
                }
                _ => ()
            }
          }
          _ => {}
      }
      self.pred=Predicate::Nothing;
      self.verify_multiple();
  }

  fn visit_atom(&mut self, _this: usize){
      self.pred=Predicate::Nothing;
      self.verify_multiple();
  }

  fn visit_one_or_more(&mut self, this: usize, child: usize){
    // println!("one_or_more");
    self.warning(Predicate::Oom(this));
    match self.vec_type {
        VecType::And => {
            self.verify_multiple()
        }
        VecType::Nothing => {
            self.vec_type=VecType::OneOrMore
        }
        _ => ()
    }
    self.vec_pred.push(Predicate::Oom(this));
    self.visit_expr(child)
  }

  fn visit_zero_or_more(&mut self, this: usize, child: usize){
    // println!("zero_or_more");
    self.pred = Predicate::Zom(this);
    self.verify_multiple();
    self.visit_expr(child)
  }

  fn visit_not_predicate(&mut self, this: usize, child: usize){
    // println!("not_predicate");
    self.warning(Predicate::Not(this));
    self.pred=Predicate::Not(this);
    self.verify_multiple();
    self.visit_expr(child)
  }

  fn visit_and_predicate(&mut self, this: usize, child: usize){
    // println!("and_predicate");
    self.warning(Predicate::And(this));
    self.pred=Predicate::And(this);

    match self.vec_type {
        VecType::OneOrMore => {
            self.verify_multiple()
        }
        VecType::Nothing => {
            self.vec_type=VecType::And;
        }
        _ => ()
    }
    self.vec_pred.push(Predicate::And(this));
    self.visit_expr(child)
  }

  fn visit_sequence(&mut self, _: usize, children: Vec<usize>){
    for child in children {
        self.verify_multiple();
        self.visit_expr(child);
    }
  }

  fn visit_choice(&mut self, _: usize, children: Vec<usize>){
      for child in children {
          self.verify_multiple();
          self.visit_expr(child);
      }
  }
}
<commit_msg>[analysis] nothing for useless chaining<commit_after>// Copyright 2018 Chao Lin & William Sergeant (Sorbonne University)

// 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.

#![macro_use]
use middle::analysis::ast::*;
use ast::Expression::*;
use std::cmp;
use syntax::codemap::BytePos;
pub use rust::NO_EXPANSION;

enum Predicate {
    And(usize),
    Not(usize),
    Oom(usize),
    Zom(usize),
    Nothing
}

enum VecType {
    And,
    OneOrMore,
    Nothing
}

pub struct UselessChaining<'a: 'c, 'b: 'a, 'c>
{
  grammar: &'c AGrammar<'a, 'b>,
  pred: Predicate,
  vec_pred : Vec<Predicate>,
  vec_type : VecType
}

impl <'a, 'b, 'c> UselessChaining<'a, 'b, 'c>
{
  pub fn analyse(grammar: AGrammar<'a, 'b>) -> Partial<AGrammar<'a, 'b>> {
    UselessChaining::check_chaining(&grammar);
    Partial::Value(grammar)
  }

  fn check_chaining(grammar: &'c AGrammar<'a, 'b>){
    let mut analyser = UselessChaining{
      grammar: grammar,
      pred: Predicate::Nothing,
      vec_pred: vec![],
      vec_type: VecType::Nothing
    };
    for rule in &grammar.rules {
      analyser.visit_expr(rule.expr_idx)
    }
  }

  fn span_end_point(&self, sp: Span) -> Span{
      let lo = cmp::max(sp.hi().0 - 1, sp.lo().0);
      sp.with_lo(BytePos(lo))
  }

  fn get_th(&self, n: usize) -> &'static str {
      match n {
          1 => "st",
          2 => "nd",
          3 => "rd",
          _ => "th"
      }
  }

  fn warn_useless_chaining(&self, pred: (&'static str, &'static str, &'static str, &'static str), span2: Span, span1: Span){
      let (detected,help,first,second) = pred;
      self.grammar.span_warn(
          span1,
          format!(
              "Detected useless chaining: {}
              \nHelp: {}
              \n1{} predicate {}"
          ,detected,help,self.get_th(1),first)
      );
      self.grammar.span_note(
          span2,
          format!("2{} predicate {}",self.get_th(2),second)
      )
  }

  fn warn_vec_useless_chaining(&self, pred: (&'static str, &'static str, &'static str), i: usize, span: Span){
      let (warn,note,span_note) = pred;
      if i==0 {
          self.grammar.span_warn(
              span,
              format!(
                  "Detected useless chaining: multiple {}
                  \nHelp: {}
                  \n1{} occurence of {}"
              ,warn,note,self.get_th(1),warn)
          )
      }
      else{
          self.grammar.span_note(
              span,
              format!("{}{} occurence of {}",i+1,self.get_th(i+1),span_note)
          )
      }

  }

  fn warn_verify_multiple(&self) {
      for (i, x) in self.vec_pred.iter().enumerate() {
          match x {
              &Predicate::And(this) => {
                  let lo = self.grammar[this].span().lo();
                  let span = Span::new(lo,lo,NO_EXPANSION);
                  self.warn_vec_useless_chaining(("&","&(&e) -> &e","and"),i,span);
              }
              &Predicate::Oom(this) => {
                  let sp = self.grammar[this].span();
                  let span = self.span_end_point(sp);
                  self.warn_vec_useless_chaining(("+","(e+)+ -> e+","one or more"),i,span);
              }
              _ => unreachable!()
          }
      }
  }

  fn verify_multiple(&mut self){
      if self.vec_pred.len()>=2 {
          self.warn_verify_multiple()
      }
      self.vec_pred.clear();
      self.vec_type=VecType::Nothing;
  }

  fn warning(&mut self, current: Predicate){
      match (&self.pred, current) {
          (&Predicate::Zom(t),Predicate::Oom(this)) => {
              self.warn_useless_chaining(
                  ("(e+)*","(e+)* -> e+","One or more","Zero or more"),
                  self.span_end_point(self.grammar[this].span()),
                  self.span_end_point(self.grammar[t].span())
              );
          }
          (&Predicate::Not(t),Predicate::Not(this)) => {
              let f_lo = self.grammar[this].span().lo();
              let s_lo = self.grammar[t].span().lo();
              self.warn_useless_chaining(
                  ("!(!e)","!(!e) -> &e","not","not"),
                  Span::new(f_lo, f_lo, NO_EXPANSION),
                  Span::new(s_lo, s_lo, NO_EXPANSION)
              );
          }
          (&Predicate::And(t),Predicate::Not(this)) => {
              let f_lo = self.grammar[this].span().lo();
              let s_lo = self.grammar[t].span().lo();
              self.warn_useless_chaining(
                  ("&(!e)","&(!e) -> !e","not","and"),
                  Span::new(f_lo, f_lo, NO_EXPANSION),
                  Span::new(s_lo, s_lo, NO_EXPANSION)
              );
          }
          (&Predicate::Not(t),Predicate::And(this)) => {
              let f_lo = self.grammar[this].span().lo();
              let s_lo = self.grammar[t].span().lo();
              self.warn_useless_chaining(
                  ("!(&e)","!(&e) -> !e","and","not"),
                  Span::new(f_lo, f_lo, NO_EXPANSION),
                  Span::new(s_lo, s_lo, NO_EXPANSION)
              );
          }
          _ => {}
      }
  }

 }

impl<'a, 'b, 'c> ExprByIndex for UselessChaining<'a, 'b, 'c>
{
  fn expr_by_index(&self, index: usize) -> Expression {
    self.grammar.expr_by_index(index).clone()
  }
}

impl<'a, 'b, 'c> Visitor<()> for UselessChaining<'a, 'b, 'c>
{

  fn visit_str_literal(&mut self, _this: usize, _lit: String){
      self.pred=Predicate::Nothing;
      self.verify_multiple();
  }

  fn visit_atom(&mut self, _this: usize){
      self.pred=Predicate::Nothing;
      self.verify_multiple();
  }

  fn visit_non_terminal_symbol(&mut self, _this: usize, rule: Ident){
      let predicate = self.grammar.find_rule_by_ident(rule).expr_idx;
      match self.expr_by_index(predicate){
          ZeroOrMore(_child) => {
            self.warning(Predicate::Zom(predicate));
          }
          OneOrMore(_child) => {
            self.warning(Predicate::Oom(predicate));
            match self.vec_type {
                VecType::OneOrMore => {
                    self.vec_pred.push(Predicate::Oom(predicate));
                }
                _ => ()
            }
          }
          NotPredicate(_child) => {
            self.warning(Predicate::Not(predicate));
          }
          AndPredicate(_child) => {
            self.warning(Predicate::And(predicate));
            match self.vec_type {
                VecType::And => {
                    self.vec_pred.push(Predicate::And(predicate));
                }
                _ => ()
            }
          }
          _ => {}
      }
      self.pred=Predicate::Nothing;
      self.verify_multiple();
  }

  fn visit_one_or_more(&mut self, this: usize, child: usize){
    // println!("one_or_more");
    self.warning(Predicate::Oom(this));
    match self.vec_type {
        VecType::And => {
            self.verify_multiple()
        }
        VecType::Nothing => {
            self.vec_type=VecType::OneOrMore
        }
        _ => ()
    }
    self.vec_pred.push(Predicate::Oom(this));
    self.visit_expr(child)
  }

  fn visit_zero_or_more(&mut self, this: usize, child: usize){
    // println!("zero_or_more");
    self.pred = Predicate::Zom(this);
    self.verify_multiple();
    self.visit_expr(child)
  }

  fn visit_not_predicate(&mut self, this: usize, child: usize){
    // println!("not_predicate");
    self.warning(Predicate::Not(this));
    self.pred=Predicate::Not(this);
    self.verify_multiple();
    self.visit_expr(child)
  }

  fn visit_and_predicate(&mut self, this: usize, child: usize){
    // println!("and_predicate");
    self.warning(Predicate::And(this));
    self.pred=Predicate::And(this);

    match self.vec_type {
        VecType::OneOrMore => {
            self.verify_multiple()
        }
        VecType::Nothing => {
            self.vec_type=VecType::And;
        }
        _ => ()
    }
    self.vec_pred.push(Predicate::And(this));
    self.visit_expr(child)
  }

  fn visit_sequence(&mut self, _: usize, children: Vec<usize>){
    for child in children {
        self.verify_multiple();
        self.visit_expr(child);
    }
  }

  fn visit_choice(&mut self, _: usize, children: Vec<usize>){
      for child in children {
          self.verify_multiple();
          self.visit_expr(child);
      }
  }
}
<|endoftext|>


<commit_before>use std::result::Result;

use super::script::*;

///
/// Represents a parse error
///
pub struct ParseError {

}

///
/// Tool that parses our scripting language
///
pub struct ParseScriptTool {
}

impl ParseError {
    pub fn new() -> ParseError {
        ParseError { }
    }
}

struct ParseState<'a> {
    remaining: &'a [ScriptToken]
}

impl<'a> ParseState<'a> {
    ///
    /// Returns true if a token is considered syntax (gets returned from lookahead)
    ///
    fn is_syntax(token: &ScriptToken) -> bool {
        match token.token {
            ScriptLexerToken::Whitespace    |
            ScriptLexerToken::Comment       => false,

            _                               => true
        }
    }

    ///
    /// Looks ahead to the next syntactically relevant lexer match (and returns the tokens after it)
    ///
    fn lookahead(&self) -> Option<(&'a ScriptToken, &'a [ScriptToken])> {
        let mut index   = 0;
        let len         = self.remaining.len();

        loop {
            if index >= len {
                return None;
            } else if ParseState::is_syntax(&self.remaining[index]) {
                let token       = &self.remaining[index];
                let remaining   = &self.remaining[index+1..len];
                return Some((token, remaining));
            }

            index += 1;
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn lookahead_is(&self, token: ScriptLexerToken) -> bool {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches
                true
            } else {
                // Token does not match
                false
            }
        } else {
            // End of file
            false
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn accept(&mut self, token: ScriptLexerToken) -> Option<&'a ScriptToken> {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches: remove it from the input and return it
                self.remaining = remaining;
                Some(lookahead)
            } else {
                // Next token does not match
                None
            }
        } else {
            // Reached the end of file
            None
        }
    }

    ///
    /// Parses a statement
    ///
    pub fn parse_statement(&mut self) -> Result<Script, ParseError> {
        if self.accept(ScriptLexerToken::Newline).is_some() {
            // Newlines are ignored
            self.parse_statement()
        } else if self.accept(ScriptLexerToken::Let).is_some() {
            // self.parse_let()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Var).is_some() {
            // self.parse_var()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Def).is_some() {
            // self.parse_def()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::If).is_some() {
            // self.parse_if()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Using).is_some() {
            // self.parse_using()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::While).is_some() {
            // self.parse_while()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Loop).is_some() {
            // self.parse_loop()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::For).is_some() {
            // self.parse_for()
            unimplemented!()
        } else if self.lookahead_is(ScriptLexerToken::Identifier) {
            // While commands are either <Expression> or <Expression> <Expression>, we
            // force the first expression to be an identifier at the moment
            self.parse_command()
        } else {
            // Unrecognised token
            Err(ParseError::new())
        }
    }

    ///
    /// Parses a command
    ///
    /// Syntax '<expression>', '<expression> <expression>'
    ///
    pub fn parse_command(&mut self) -> Result<Script, ParseError> {
        // Starts with an expression specifying the command to run
        self.parse_expression().and_then(move |command_expression| {
            // Followed by arguments (or an end-of-expression marker)
            if self.accept(ScriptLexerToken::Newline).is_some()
               || self.accept(ScriptLexerToken::EndOfFile).is_some() {
                // Newline or EOF ends a command
                Ok(Script::RunCommand(command_expression, None))

            } else {
                // Anything else should be an argument expression
                self.parse_expression().and_then(move |argument_expression| {
                    Ok(Script::RunCommand(command_expression, Some(argument_expression)))

                }).and_then(move |command| {
                    // Command must be followed by a newline
                    if self.accept(ScriptLexerToken::Newline).is_some()
                       || self.accept(ScriptLexerToken::EndOfFile).is_some() {
                        Ok(command)
                    } else {
                        Err(ParseError::new())
                    }

                })

            }
        })
    }

    ///
    /// Parses an Expression
    ///
    pub fn parse_expression(&mut self) -> Result<Expression, ParseError> {
        unimplemented!()
        /*
        if let Some((lookahead1, remainder1)) = lookahead(input) {
            let expr1 = match lookahead1.token {
                ScriptLexerToken::Identifier    => Ok((Expression::Identifier(lookahead1.clone()), remainder)),
                ScriptLexerToken::Number        |
                ScriptLexerToken::HexNumber     => Ok((Expression::Number(lookahead1.clone()), remainder)),
                ScriptLexerToken::String        => Ok((Expression::String(lookahead1.clone()), remainder)),

                _ => Err(ParseError::new())
            };

            expr1
        } else {
            // EOF
            Err(ParseError::new())
        }
        */
    }

    /*
    pub fn parse_let<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_var<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_def<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_if<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_using<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_while<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_loop<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_for<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }
    */
}

impl ParseScriptTool {
    ///
    /// Creates a new script parsing tool
    ///
    pub fn new() -> ParseScriptTool {
        ParseScriptTool { }
    }
}<commit_msg>Make lookahead_is have special treatment for the EOF marker<commit_after>use std::result::Result;

use super::script::*;

///
/// Represents a parse error
///
pub struct ParseError {

}

///
/// Tool that parses our scripting language
///
pub struct ParseScriptTool {
}

impl ParseError {
    pub fn new() -> ParseError {
        ParseError { }
    }
}

struct ParseState<'a> {
    remaining: &'a [ScriptToken]
}

impl<'a> ParseState<'a> {
    ///
    /// Returns true if a token is considered syntax (gets returned from lookahead)
    ///
    fn is_syntax(token: &ScriptToken) -> bool {
        match token.token {
            ScriptLexerToken::Whitespace    |
            ScriptLexerToken::Comment       => false,

            _                               => true
        }
    }

    ///
    /// Looks ahead to the next syntactically relevant lexer match (and returns the tokens after it)
    ///
    fn lookahead(&self) -> Option<(&'a ScriptToken, &'a [ScriptToken])> {
        let mut index   = 0;
        let len         = self.remaining.len();

        loop {
            if index >= len {
                return None;
            } else if ParseState::is_syntax(&self.remaining[index]) {
                let token       = &self.remaining[index];
                let remaining   = &self.remaining[index+1..len];
                return Some((token, remaining));
            }

            index += 1;
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn lookahead_is(&self, token: ScriptLexerToken) -> bool {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches
                true
            } else {
                // Token does not match
                false
            }
        } else {
            // End of file
            if token == ScriptLexerToken::EndOfFile {
                // With lookahead_is we can look for the end of file (but we can't accept it because there's no token data associated with it)
                true
            } else {
                false
            }
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn accept(&mut self, token: ScriptLexerToken) -> Option<&'a ScriptToken> {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches: remove it from the input and return it
                self.remaining = remaining;
                Some(lookahead)
            } else {
                // Next token does not match
                None
            }
        } else {
            // Reached the end of file
            None
        }
    }

    ///
    /// Parses a statement
    ///
    pub fn parse_statement(&mut self) -> Result<Script, ParseError> {
        if self.accept(ScriptLexerToken::Newline).is_some() {
            // Newlines are ignored
            self.parse_statement()
        } else if self.accept(ScriptLexerToken::Let).is_some() {
            // self.parse_let()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Var).is_some() {
            // self.parse_var()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Def).is_some() {
            // self.parse_def()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::If).is_some() {
            // self.parse_if()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Using).is_some() {
            // self.parse_using()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::While).is_some() {
            // self.parse_while()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Loop).is_some() {
            // self.parse_loop()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::For).is_some() {
            // self.parse_for()
            unimplemented!()
        } else if self.lookahead_is(ScriptLexerToken::Identifier) {
            // While commands are either <Expression> or <Expression> <Expression>, we
            // force the first expression to be an identifier at the moment
            self.parse_command()
        } else {
            // Unrecognised token
            Err(ParseError::new())
        }
    }

    ///
    /// Parses a command
    ///
    /// Syntax '<expression>', '<expression> <expression>'
    ///
    pub fn parse_command(&mut self) -> Result<Script, ParseError> {
        // Starts with an expression specifying the command to run
        self.parse_expression().and_then(move |command_expression| {
            // Followed by arguments (or an end-of-expression marker)
            if self.accept(ScriptLexerToken::Newline).is_some()
               || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                // Newline or EOF ends a command
                Ok(Script::RunCommand(command_expression, None))

            } else {
                // Anything else should be an argument expression
                self.parse_expression().and_then(move |argument_expression| {
                    Ok(Script::RunCommand(command_expression, Some(argument_expression)))

                }).and_then(move |command| {
                    // Command must be followed by a newline
                    if self.accept(ScriptLexerToken::Newline).is_some()
                       || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                        Ok(command)
                    } else {
                        Err(ParseError::new())
                    }

                })

            }
        })
    }

    ///
    /// Parses an Expression
    ///
    pub fn parse_expression(&mut self) -> Result<Expression, ParseError> {
        unimplemented!()
        /*
        if let Some((lookahead1, remainder1)) = lookahead(input) {
            let expr1 = match lookahead1.token {
                ScriptLexerToken::Identifier    => Ok((Expression::Identifier(lookahead1.clone()), remainder)),
                ScriptLexerToken::Number        |
                ScriptLexerToken::HexNumber     => Ok((Expression::Number(lookahead1.clone()), remainder)),
                ScriptLexerToken::String        => Ok((Expression::String(lookahead1.clone()), remainder)),

                _ => Err(ParseError::new())
            };

            expr1
        } else {
            // EOF
            Err(ParseError::new())
        }
        */
    }

    /*
    pub fn parse_let<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_var<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_def<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_if<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_using<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_while<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_loop<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_for<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }
    */
}

impl ParseScriptTool {
    ///
    /// Creates a new script parsing tool
    ///
    pub fn new() -> ParseScriptTool {
        ParseScriptTool { }
    }
}<|endoftext|>