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

//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashSet;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::process::Command;

use build_helper::output;

use Build;

pub fn check(build: &mut Build) {
    let mut checked = HashSet::new();
    let path = env::var_os("PATH").unwrap_or(OsString::new());
    let mut need_cmd = |cmd: &OsStr| {
        if !checked.insert(cmd.to_owned()) {
            return
        }
        for path in env::split_paths(&path).map(|p| p.join(cmd)) {
            if fs::metadata(&path).is_ok() ||
               fs::metadata(path.with_extension("exe")).is_ok() {
                return
            }
        }
        panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
    };

    // If we've got a git directory we're gona need git to update
    // submodules and learn about various other aspects.
    if fs::metadata(build.src.join(".git")).is_ok() {
        need_cmd("git".as_ref());
    }

    // We need cmake, but only if we're actually building LLVM
    for host in build.config.host.iter() {
        if let Some(config) = build.config.target_config.get(host) {
            if config.llvm_config.is_some() {
                continue
            }
        }
        need_cmd("cmake".as_ref());
        if build.config.ninja {
            need_cmd("ninja".as_ref())
        }
        break
    }

    need_cmd("python".as_ref());

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in build.config.target.iter() {
        need_cmd(build.cc(target).as_ref());
        if let Some(ar) = build.ar(target) {
            need_cmd(ar.as_ref());
        }
    }
    for host in build.config.host.iter() {
        need_cmd(build.cxx(host).as_ref());
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(&build.config.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() {
        panic!("filecheck executable {:?} does not exist", filecheck);
    }

    for target in build.config.target.iter() {
        // Either can't build or don't want to run jemalloc on these targets
        if target.contains("rumprun") ||
           target.contains("bitrig") ||
           target.contains("openbsd") ||
           target.contains("msvc") {
            build.config.use_jemalloc = false;
        }

        // Can't compile for iOS unless we're on OSX
        if target.contains("apple-ios") &&
           !build.config.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on OSX");
        }

        // Make sure musl-root is valid if specified
        if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
            match build.config.musl_root {
                Some(ref root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL the build.musl-root option \
                            must be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }

        if target.contains("arm-linux-android") {
            need_cmd("adb".as_ref());
        }
    }

    for host in build.flags.host.iter() {
        if !build.config.host.contains(host) {
            panic!("specified host `{}` is not in the ./configure list", host);
        }
    }
    for target in build.flags.target.iter() {
        if !build.config.target.contains(target) {
            panic!("specified target `{}` is not in the ./configure list",
                   target);
        }
    }

    let run = |cmd: &mut Command| {
        cmd.output().map(|output| {
            String::from_utf8_lossy(&output.stdout)
                   .lines().next().unwrap()
                   .to_string()
        })
    };
    build.gdb_version = run(Command::new("gdb").arg("--version")).ok();
    build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
    if build.lldb_version.is_some() {
        build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
    }
}
<commit_msg>rustbuild: Ensure PATH does not contain invalid character `"`<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashSet;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::process::Command;

use build_helper::output;

use Build;

pub fn check(build: &mut Build) {
    let mut checked = HashSet::new();
    let path = env::var_os("PATH").unwrap_or(OsString::new());
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) {
        if path.to_string_lossy().contains("\"") {
            panic!("PATH contains invalid character '\"'");
        }
    }
    let mut need_cmd = |cmd: &OsStr| {
        if !checked.insert(cmd.to_owned()) {
            return
        }
        for path in env::split_paths(&path).map(|p| p.join(cmd)) {
            if fs::metadata(&path).is_ok() ||
               fs::metadata(path.with_extension("exe")).is_ok() {
                return
            }
        }
        panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
    };

    // If we've got a git directory we're gona need git to update
    // submodules and learn about various other aspects.
    if fs::metadata(build.src.join(".git")).is_ok() {
        need_cmd("git".as_ref());
    }

    // We need cmake, but only if we're actually building LLVM
    for host in build.config.host.iter() {
        if let Some(config) = build.config.target_config.get(host) {
            if config.llvm_config.is_some() {
                continue
            }
        }
        need_cmd("cmake".as_ref());
        if build.config.ninja {
            need_cmd("ninja".as_ref())
        }
        break
    }

    need_cmd("python".as_ref());

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in build.config.target.iter() {
        need_cmd(build.cc(target).as_ref());
        if let Some(ar) = build.ar(target) {
            need_cmd(ar.as_ref());
        }
    }
    for host in build.config.host.iter() {
        need_cmd(build.cxx(host).as_ref());
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(&build.config.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() {
        panic!("filecheck executable {:?} does not exist", filecheck);
    }

    for target in build.config.target.iter() {
        // Either can't build or don't want to run jemalloc on these targets
        if target.contains("rumprun") ||
           target.contains("bitrig") ||
           target.contains("openbsd") ||
           target.contains("msvc") {
            build.config.use_jemalloc = false;
        }

        // Can't compile for iOS unless we're on OSX
        if target.contains("apple-ios") &&
           !build.config.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on OSX");
        }

        // Make sure musl-root is valid if specified
        if target.contains("musl") && (target.contains("x86_64") || target.contains("i686")) {
            match build.config.musl_root {
                Some(ref root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL the build.musl-root option \
                            must be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }

        if target.contains("arm-linux-android") {
            need_cmd("adb".as_ref());
        }
    }

    for host in build.flags.host.iter() {
        if !build.config.host.contains(host) {
            panic!("specified host `{}` is not in the ./configure list", host);
        }
    }
    for target in build.flags.target.iter() {
        if !build.config.target.contains(target) {
            panic!("specified target `{}` is not in the ./configure list",
                   target);
        }
    }

    let run = |cmd: &mut Command| {
        cmd.output().map(|output| {
            String::from_utf8_lossy(&output.stdout)
                   .lines().next().unwrap()
                   .to_string()
        })
    };
    build.gdb_version = run(Command::new("gdb").arg("--version")).ok();
    build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
    if build.lldb_version.is_some() {
        build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
    }
}
<|endoftext|>


<commit_before>//! Cartridge model specific emulation

use super::Cartridge;

/// Interface to model-specific operations
pub struct Model {
    /// String identifier
    pub name: &'static str,
    /// Handle ROM write
    pub write: fn(cart: &mut Cartridge, addr: u16, val: u8),
}

mod mbc0 {
    use super::Model;
    use cartridge::Cartridge;

    fn write(_: &mut Cartridge, addr: u16, val: u8) {
        debug!("Unhandled ROM write: {:04x} {:02x}", addr, val);
    }

    pub static MODEL: Model = Model { name: "MBC0", write: write };
}

mod mbc1 {
    use super::Model;
    use cartridge::Cartridge;

    fn write(cart: &mut Cartridge, addr: u16, val: u8) {
        match addr {
            0x0000...0x1fff =>
                // Writing a low nibble 0xa to anywhere in that
                // address range removes RAM write protect, All other
                // values enable it.
                cart.set_ram_wp(val & 0xf != 0xa),
            0x2000...0x3fff => {
                // Select a new ROM bank, bits [4:0]
                let cur_bank = cart.rom_bank() & !0x1f;

                cart.set_rom_bank(cur_bank | (val & 0x1f));
            }
            0x4000...0x5fff =>
                if cart.bank_ram() {
                    // Select a new RAM bank
                    cart.set_ram_bank(val & 0x3);
                } else {
                    // Select a new ROM bank, bits [6:5]
                    let cur_bank = cart.rom_bank() & !0x60;

                    cart.set_rom_bank(cur_bank | ((val << 5) & 0x60));
                },
            0x6000...0x7fff =>
                // Switch RAM/ROM banking mode
                cart.set_bank_ram(val & 1 != 0),
            _ =>
                debug!("Unhandled ROM write: {:04x} {:02x}", addr, val),
        }
    }

    pub static MODEL: Model = Model { name: "MBC1", write: write };
}

mod mbc3 {
    use super::Model;
    use cartridge::Cartridge;

    fn write(cart: &mut Cartridge, addr: u16, val: u8) {
        match addr {
            0x0000...0x1fff =>
                // Writing a low nibble 0xa to anywhere in that
                // address range removes RAM write protect, All other
                // values enable it.
                cart.set_ram_wp(val & 0xf != 0xa),
            0x2000...0x3fff =>
                // Select a new ROM bank
                cart.set_rom_bank(val & 0x7f),
            0x4000...0x5fff =>
                // Select a new RAM bank
                cart.set_ram_bank(val),
            0x6000...0x7fff =>
                debug!("Unhandled RTC access"),
            _ =>
                debug!("Unhandled ROM write: {:04x} {:02x}", addr, val),
        }
    }

    pub static MODEL: Model = Model { name: "MBC1", write: write };
}

/// Return a cartridge instance for a given cartridge type
pub fn from_id(id: u8) -> Model {
    match id {
        0           => mbc0::MODEL,
        0x01...0x03 => mbc1::MODEL,
        0x12...0x13 => mbc3::MODEL,
        _           => panic!("Unknown cartridge model {:02x}", id),
    }
}
<commit_msg>Add a couple missing IDs for MBC3 cartridge type<commit_after>//! Cartridge model specific emulation

use super::Cartridge;

/// Interface to model-specific operations
pub struct Model {
    /// String identifier
    pub name: &'static str,
    /// Handle ROM write
    pub write: fn(cart: &mut Cartridge, addr: u16, val: u8),
}

mod mbc0 {
    use super::Model;
    use cartridge::Cartridge;

    fn write(_: &mut Cartridge, addr: u16, val: u8) {
        debug!("Unhandled ROM write: {:04x} {:02x}", addr, val);
    }

    pub static MODEL: Model = Model { name: "MBC0", write: write };
}

mod mbc1 {
    use super::Model;
    use cartridge::Cartridge;

    fn write(cart: &mut Cartridge, addr: u16, val: u8) {
        match addr {
            0x0000...0x1fff =>
                // Writing a low nibble 0xa to anywhere in that
                // address range removes RAM write protect, All other
                // values enable it.
                cart.set_ram_wp(val & 0xf != 0xa),
            0x2000...0x3fff => {
                // Select a new ROM bank, bits [4:0]
                let cur_bank = cart.rom_bank() & !0x1f;

                cart.set_rom_bank(cur_bank | (val & 0x1f));
            }
            0x4000...0x5fff =>
                if cart.bank_ram() {
                    // Select a new RAM bank
                    cart.set_ram_bank(val & 0x3);
                } else {
                    // Select a new ROM bank, bits [6:5]
                    let cur_bank = cart.rom_bank() & !0x60;

                    cart.set_rom_bank(cur_bank | ((val << 5) & 0x60));
                },
            0x6000...0x7fff =>
                // Switch RAM/ROM banking mode
                cart.set_bank_ram(val & 1 != 0),
            _ =>
                debug!("Unhandled ROM write: {:04x} {:02x}", addr, val),
        }
    }

    pub static MODEL: Model = Model { name: "MBC1", write: write };
}

mod mbc3 {
    use super::Model;
    use cartridge::Cartridge;

    fn write(cart: &mut Cartridge, addr: u16, val: u8) {
        match addr {
            0x0000...0x1fff =>
                // Writing a low nibble 0xa to anywhere in that
                // address range removes RAM write protect, All other
                // values enable it.
                cart.set_ram_wp(val & 0xf != 0xa),
            0x2000...0x3fff =>
                // Select a new ROM bank
                cart.set_rom_bank(val & 0x7f),
            0x4000...0x5fff =>
                // Select a new RAM bank
                cart.set_ram_bank(val),
            0x6000...0x7fff =>
                debug!("Unhandled RTC access"),
            _ =>
                debug!("Unhandled ROM write: {:04x} {:02x}", addr, val),
        }
    }

    pub static MODEL: Model = Model { name: "MBC1", write: write };
}

/// Return a cartridge instance for a given cartridge type
pub fn from_id(id: u8) -> Model {
    match id {
        0           => mbc0::MODEL,
        0x01...0x03 => mbc1::MODEL,
        0x0f...0x13 => mbc3::MODEL,
        _           => panic!("Unknown cartridge model 0x{:02x}", id),
    }
}
<|endoftext|>


<commit_before>use crate::fx::FxHashMap;
use std::cmp::max;
use std::slice;
use std::iter;

use super::*;

pub struct TestGraph {
    num_nodes: usize,
    start_node: usize,
    successors: FxHashMap<usize, Vec<usize>>,
    predecessors: FxHashMap<usize, Vec<usize>>,
}

impl TestGraph {
    pub fn new(start_node: usize, edges: &[(usize, usize)]) -> Self {
        let mut graph = TestGraph {
            num_nodes: start_node + 1,
            start_node,
            successors: FxHashMap::default(),
            predecessors: FxHashMap::default(),
        };
        for &(source, target) in edges {
            graph.num_nodes = max(graph.num_nodes, source + 1);
            graph.num_nodes = max(graph.num_nodes, target + 1);
            graph.successors.entry(source).or_default().push(target);
            graph.predecessors.entry(target).or_default().push(source);
        }
        for node in 0..graph.num_nodes {
            graph.successors.entry(node).or_default();
            graph.predecessors.entry(node).or_default();
        }
        graph
    }
}

impl DirectedGraph for TestGraph {
    type Node = usize;
}

impl WithStartNode for TestGraph {
    fn start_node(&self) -> usize {
        self.start_node
    }
}

impl WithNumNodes for TestGraph {
    fn num_nodes(&self) -> usize {
        self.num_nodes
    }
}

impl WithPredecessors for TestGraph {
    fn predecessors(&self,
                    node: usize)
                    -> <Self as GraphPredecessors<'_>>::Iter {
        self.predecessors[&node].iter().cloned()
    }
}

impl WithSuccessors for TestGraph {
    fn successors(&self, node: usize) -> <Self as GraphSuccessors>::Iter {
        self.successors[&node].iter().cloned()
    }
}

impl<'graph> GraphPredecessors<'graph> for TestGraph {
    type Item = usize;
    type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
}

impl<'graph> GraphSuccessors<'graph> for TestGraph {
    type Item = usize;
    type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
}
<commit_msg>Add missing lifetime specifier<commit_after>use crate::fx::FxHashMap;
use std::cmp::max;
use std::slice;
use std::iter;

use super::*;

pub struct TestGraph {
    num_nodes: usize,
    start_node: usize,
    successors: FxHashMap<usize, Vec<usize>>,
    predecessors: FxHashMap<usize, Vec<usize>>,
}

impl TestGraph {
    pub fn new(start_node: usize, edges: &[(usize, usize)]) -> Self {
        let mut graph = TestGraph {
            num_nodes: start_node + 1,
            start_node,
            successors: FxHashMap::default(),
            predecessors: FxHashMap::default(),
        };
        for &(source, target) in edges {
            graph.num_nodes = max(graph.num_nodes, source + 1);
            graph.num_nodes = max(graph.num_nodes, target + 1);
            graph.successors.entry(source).or_default().push(target);
            graph.predecessors.entry(target).or_default().push(source);
        }
        for node in 0..graph.num_nodes {
            graph.successors.entry(node).or_default();
            graph.predecessors.entry(node).or_default();
        }
        graph
    }
}

impl DirectedGraph for TestGraph {
    type Node = usize;
}

impl WithStartNode for TestGraph {
    fn start_node(&self) -> usize {
        self.start_node
    }
}

impl WithNumNodes for TestGraph {
    fn num_nodes(&self) -> usize {
        self.num_nodes
    }
}

impl WithPredecessors for TestGraph {
    fn predecessors(&self,
                    node: usize)
                    -> <Self as GraphPredecessors<'_>>::Iter {
        self.predecessors[&node].iter().cloned()
    }
}

impl WithSuccessors for TestGraph {
    fn successors(&self, node: usize) -> <Self as GraphSuccessors<'_>>::Iter {
        self.successors[&node].iter().cloned()
    }
}

impl<'graph> GraphPredecessors<'graph> for TestGraph {
    type Item = usize;
    type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
}

impl<'graph> GraphSuccessors<'graph> for TestGraph {
    type Item = usize;
    type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
}
<|endoftext|>


<commit_before>
extern crate serial;

use std::env;
use std::io;
use std::time::Duration;
use std::process::exit;
use std::thread::sleep;

use std::io::prelude::*;
use serial::prelude::*;

fn main() {
    let args: Vec<String> = env::args().skip(1).collect();
    if args.len() != 1 {
        writeln!(io::stderr(), "Program takes exactly one argument. (The serial port)").unwrap();
        exit(1);
    }

    let mut port = serial::open(&args[0]).unwrap();
    let mut settings = serial::PortSettings::default();
    settings.set_char_size(serial::CharSize::Bits8);
    settings.set_parity(serial::Parity::ParityNone);
    settings.set_stop_bits(serial::StopBits::Stop1);
    if let Err(err) = settings.set_baud_rate(serial::BaudRate::Baud9600) {
        return;
    }

    if let Err(err) = port.configure(&settings) {
        return;
    }

    let mut buf = vec![0; 256];
    let mut message = String::new();
    loop {
        match port.read(&mut buf[..]) {
            Ok(bytes_read) => {
                for i in 0..bytes_read {
                    match buf[i] as char {
                        '\n' if message.trim()=="ready" => {
                            send_level(&mut io::stdin(), &mut port);
                            return;
                        }

                        '\n' => {
                            println!("{}", message=="ready");
                            message.clear();
                        }

                        character => message.push(character)
                    }
                }
            }

            Err(e) => {
                println!("error: {}", e);
            }
        }
        sleep(Duration::from_millis(100));
    }
}

fn send_level(input: &mut Read, output: &mut Write) {
    let mut level_data = vec![];
    match input.read_to_end(&mut level_data) {
        Ok(_) => {
            output.write(level_data.as_slice()).unwrap();
        },
        _ => {
            writeln!(io::stderr(), "Could not read standard input.").unwrap();
            exit(2);
        }
    }
}
<commit_msg>Improved top side part of the program<commit_after>
extern crate serial;

use std::env;
use std::io;
use std::time::Duration;
use std::process::exit;
use std::thread::sleep;

use std::io::prelude::*;
use serial::prelude::*;

fn main() {
    let args: Vec<String> = env::args().skip(1).collect();
    if args.len() != 1 {
        writeln!(io::stderr(), "Program takes exactly one argument. (The serial port)").unwrap();
        exit(1);
    }

    let mut port = serial::open(&args[0]).unwrap();
    let mut settings = serial::PortSettings::default();
    settings.set_char_size(serial::CharSize::Bits8);
    settings.set_parity(serial::Parity::ParityNone);
    settings.set_stop_bits(serial::StopBits::Stop1);
    if let Err(err) = settings.set_baud_rate(serial::BaudRate::Baud9600) {
        return;
    }

    if let Err(err) = port.configure(&settings) {
        return;
    }

    let mut buf = vec![0; 256];
    let mut message = String::new();
    loop {
        match port.read(&mut buf[..]) {
            Ok(bytes_read) => {
                for i in 0..bytes_read {
                    match buf[i] as char {
                        '\n' if message.trim()=="ready" => {
                            send_level(&mut io::stdin(), &mut port);
                            return;
                        }

                        '\n' => {
                            println!("{}", message=="ready");
                            message.clear();
                        }

                        character => message.push(character)
                    }
                }
            }

            Err(e) => {
                println!("error: {}", e);
            }
        }
        sleep(Duration::from_millis(100));
    }
}

// Reads level and prepares it to be sent
fn read_level(input: &mut Read) -> String {
    let mut buf = String::new();
    input.read_to_string(&mut buf).unwrap();

    let mut result = String::new();
    let mut width = 0u8;
    let mut height = 0u8;
    for line in buf.trim().lines() {
        result.push_str(line);
        height += 1;
        width = if line.len() as u8 > width {line.len() as u8} else {width};
    }
    format!("{}{}{}", width as char, height as char, result)
}

fn send_level(input: &mut Read, output: &mut Write) {
    let level = read_level(input);
    write!(output, "{}", level).unwrap();
}
<|endoftext|>


<commit_before>use std;
use std::boxed::Box;
use std::cell::Cell;
use std::mem::MaybeUninit;
use std::os::raw::c_void;
use neon_runtime;
use neon_runtime::raw;
use neon_runtime::scope::Root;
use types::{JsObject, JsValue};
use handle::{Handle, Managed};
use object::class::ClassMap;
use result::{JsResult, NeonResult};
use super::ModuleContext;

#[cfg(feature = "legacy-runtime")]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Env(raw::Isolate);

#[cfg(feature = "napi-runtime")]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Env(raw::Env);

extern "C" fn drop_class_map(map: Box<ClassMap>) {
    std::mem::drop(map);
}

impl Env {
    #[cfg(feature = "legacy-runtime")]
    pub(crate) fn to_raw(self) -> raw::Isolate {
        let Self(ptr) = self;
        ptr
    }

    #[cfg(feature = "napi-runtime")]
    pub(crate) fn to_raw(self) -> raw::Env {
        let Self(ptr) = self;
        ptr
    }

    pub(crate) fn class_map(&mut self) -> &mut ClassMap {
        let mut ptr: *mut c_void = unsafe { neon_runtime::class::get_class_map(self.to_raw()) };
        if ptr.is_null() {
            let b: Box<ClassMap> = Box::new(ClassMap::new());
            let raw = Box::into_raw(b);
            ptr = unsafe { std::mem::transmute(raw) };
            let free_map: *mut c_void = unsafe { std::mem::transmute(drop_class_map as usize) };
            unsafe {
                neon_runtime::class::set_class_map(self.to_raw(), ptr, free_map);
            }
        }
        unsafe { std::mem::transmute(ptr) }
    }

    #[cfg(feature = "napi-runtime")]
    pub(crate) fn current() -> Env {
        panic!("Context::current() will not implemented with n-api")
    }

    #[cfg(feature = "legacy-runtime")]
    pub(crate) fn current() -> Env {
        unsafe {
            std::mem::transmute(neon_runtime::call::current_isolate())
        }
    }
}

pub struct ScopeMetadata {
    env: Env,
    active: Cell<bool>
}

pub struct Scope<'a, R: Root + 'static> {
    pub metadata: ScopeMetadata,
    pub handle_scope: &'a mut R
}

impl<'a, R: Root + 'static> Scope<'a, R> {
    pub fn with<T, F: for<'b> FnOnce(Scope<'b, R>) -> T>(env: Env, f: F) -> T {
        let mut handle_scope: R = unsafe { R::allocate() };
        unsafe {
            handle_scope.enter(env.to_raw());
        }
        let result = {
            let scope = Scope {
                metadata: ScopeMetadata {
                    env,
                    active: Cell::new(true)
                },
                handle_scope: &mut handle_scope
            };
            f(scope)
        };
        unsafe {
            handle_scope.exit(env.to_raw());
        }
        result
    }
}

pub trait ContextInternal<'a>: Sized {
    fn scope_metadata(&self) -> &ScopeMetadata;

    fn env(&self) -> Env {
        self.scope_metadata().env
    }

    fn is_active(&self) -> bool {
        self.scope_metadata().active.get()
    }

    fn check_active(&self) {
        if !self.is_active() {
            panic!("execution context is inactive");
        }
    }

    fn activate(&self) { self.scope_metadata().active.set(true); }
    fn deactivate(&self) { self.scope_metadata().active.set(false); }

    fn try_catch_internal<'b: 'a, F>(&mut self, f: F) -> Result<Handle<'a, JsValue>, Handle<'a, JsValue>>
        where F: FnOnce(&mut Self) -> JsResult<'b, JsValue>
    {
        let p = Box::into_raw(Box::new(f)) as *mut c_void;
        let mut local: MaybeUninit<raw::Local> = MaybeUninit::zeroed();
        let threw = unsafe { neon_runtime::try_catch::with(try_catch_glue::<Self, F>, self as *mut Self as *mut c_void, p, &mut *local.as_mut_ptr()) };
        let local = unsafe { local.assume_init() };
        if threw {
            Err(JsValue::new_internal(local))
        } else {
            Ok(JsValue::new_internal(local))
        }
    }
}

extern "C" fn try_catch_glue<'a, 'b: 'a, C: ContextInternal<'a>, F>(p: *mut c_void, cx: *mut c_void, ok: *mut bool, ok_value: *mut raw::Local)
    where C: ContextInternal<'a>,
          F: FnOnce(&mut C) -> JsResult<'b, JsValue>
{
    let f: F = *unsafe { Box::from_raw(p as *mut F) };

    // FIXME: convert_panics(f)
    match f(unsafe { std::mem::transmute(cx) }) {
        Ok(result) => unsafe {
            *ok = true;
            *ok_value = result.to_raw();
        }
        Err(_) => unsafe {
            *ok = false;
        }
    }
}

#[cfg(feature = "legacy-runtime")]
pub fn initialize_module(exports: Handle<JsObject>, init: fn(ModuleContext) -> NeonResult<()>) {
    let env = Env::current();

    ModuleContext::with(env, exports, |cx| {
        let _ = init(cx);
    });
}

#[cfg(feature = "napi-runtime")]
pub fn initialize_module(env: raw::Env, exports: Handle<JsObject>, init: fn(ModuleContext) -> NeonResult<()>) {
    ModuleContext::with(Env(env), exports, |cx| {
        let _ = init(cx);
    });
}
<commit_msg>Add a comment explaining the boxing.<commit_after>use std;
use std::boxed::Box;
use std::cell::Cell;
use std::mem::MaybeUninit;
use std::os::raw::c_void;
use neon_runtime;
use neon_runtime::raw;
use neon_runtime::scope::Root;
use types::{JsObject, JsValue};
use handle::{Handle, Managed};
use object::class::ClassMap;
use result::{JsResult, NeonResult};
use super::ModuleContext;

#[cfg(feature = "legacy-runtime")]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Env(raw::Isolate);

#[cfg(feature = "napi-runtime")]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Env(raw::Env);

extern "C" fn drop_class_map(map: Box<ClassMap>) {
    std::mem::drop(map);
}

impl Env {
    #[cfg(feature = "legacy-runtime")]
    pub(crate) fn to_raw(self) -> raw::Isolate {
        let Self(ptr) = self;
        ptr
    }

    #[cfg(feature = "napi-runtime")]
    pub(crate) fn to_raw(self) -> raw::Env {
        let Self(ptr) = self;
        ptr
    }

    pub(crate) fn class_map(&mut self) -> &mut ClassMap {
        let mut ptr: *mut c_void = unsafe { neon_runtime::class::get_class_map(self.to_raw()) };
        if ptr.is_null() {
            let b: Box<ClassMap> = Box::new(ClassMap::new());
            let raw = Box::into_raw(b);
            ptr = unsafe { std::mem::transmute(raw) };
            let free_map: *mut c_void = unsafe { std::mem::transmute(drop_class_map as usize) };
            unsafe {
                neon_runtime::class::set_class_map(self.to_raw(), ptr, free_map);
            }
        }
        unsafe { std::mem::transmute(ptr) }
    }

    #[cfg(feature = "napi-runtime")]
    pub(crate) fn current() -> Env {
        panic!("Context::current() will not implemented with n-api")
    }

    #[cfg(feature = "legacy-runtime")]
    pub(crate) fn current() -> Env {
        unsafe {
            std::mem::transmute(neon_runtime::call::current_isolate())
        }
    }
}

pub struct ScopeMetadata {
    env: Env,
    active: Cell<bool>
}

pub struct Scope<'a, R: Root + 'static> {
    pub metadata: ScopeMetadata,
    pub handle_scope: &'a mut R
}

impl<'a, R: Root + 'static> Scope<'a, R> {
    pub fn with<T, F: for<'b> FnOnce(Scope<'b, R>) -> T>(env: Env, f: F) -> T {
        let mut handle_scope: R = unsafe { R::allocate() };
        unsafe {
            handle_scope.enter(env.to_raw());
        }
        let result = {
            let scope = Scope {
                metadata: ScopeMetadata {
                    env,
                    active: Cell::new(true)
                },
                handle_scope: &mut handle_scope
            };
            f(scope)
        };
        unsafe {
            handle_scope.exit(env.to_raw());
        }
        result
    }
}

pub trait ContextInternal<'a>: Sized {
    fn scope_metadata(&self) -> &ScopeMetadata;

    fn env(&self) -> Env {
        self.scope_metadata().env
    }

    fn is_active(&self) -> bool {
        self.scope_metadata().active.get()
    }

    fn check_active(&self) {
        if !self.is_active() {
            panic!("execution context is inactive");
        }
    }

    fn activate(&self) { self.scope_metadata().active.set(true); }
    fn deactivate(&self) { self.scope_metadata().active.set(false); }

    fn try_catch_internal<'b: 'a, F>(&mut self, f: F) -> Result<Handle<'a, JsValue>, Handle<'a, JsValue>>
        where F: FnOnce(&mut Self) -> JsResult<'b, JsValue>
    {
        // A closure does not have a guaranteed layout, so we need to box it in order to pass
        // a pointer to it across the boundary into C++.
        let p = Box::into_raw(Box::new(f)) as *mut c_void;
        let mut local: MaybeUninit<raw::Local> = MaybeUninit::zeroed();
        let threw = unsafe { neon_runtime::try_catch::with(try_catch_glue::<Self, F>, self as *mut Self as *mut c_void, p, &mut *local.as_mut_ptr()) };
        let local = unsafe { local.assume_init() };
        if threw {
            Err(JsValue::new_internal(local))
        } else {
            Ok(JsValue::new_internal(local))
        }
    }
}

extern "C" fn try_catch_glue<'a, 'b: 'a, C: ContextInternal<'a>, F>(p: *mut c_void, cx: *mut c_void, ok: *mut bool, ok_value: *mut raw::Local)
    where C: ContextInternal<'a>,
          F: FnOnce(&mut C) -> JsResult<'b, JsValue>
{
    let f: F = *unsafe { Box::from_raw(p as *mut F) };

    // FIXME: convert_panics(f)
    match f(unsafe { std::mem::transmute(cx) }) {
        Ok(result) => unsafe {
            *ok = true;
            *ok_value = result.to_raw();
        }
        Err(_) => unsafe {
            *ok = false;
        }
    }
}

#[cfg(feature = "legacy-runtime")]
pub fn initialize_module(exports: Handle<JsObject>, init: fn(ModuleContext) -> NeonResult<()>) {
    let env = Env::current();

    ModuleContext::with(env, exports, |cx| {
        let _ = init(cx);
    });
}

#[cfg(feature = "napi-runtime")]
pub fn initialize_module(env: raw::Env, exports: Handle<JsObject>, init: fn(ModuleContext) -> NeonResult<()>) {
    ModuleContext::with(Env(env), exports, |cx| {
        let _ = init(cx);
    });
}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate rusqlite;

use common::bookmark::*;
use dao::query_parser::*;
use std::str::FromStr;
use self::chrono::*;

#[derive(Debug)]
pub struct BookmarkDao<'a> {
    pub connection: &'a rusqlite::Connection,
    pub read_sql: String,
    pub delete_sql: String,
    pub insert_sql: String,
    pub update_sql: String,
    pub list_sql: String
}

impl<'a> BookmarkDao<'a> {
    pub fn insert(&self, b: Bookmark) {
        let insert_query = parse_query(&b.to_btree(), String::from(&*self.insert_sql));

        match self.connection.execute(insert_query.as_str(), &[] ) {
            Ok(insert) => println!("{} rows were inserted", insert),
            Err(err) => panic!("insert failed: {}", err),
        }
    }

    pub fn delete(&self, b: Bookmark) {
        let delete_query = parse_query(&b.to_btree(), String::from(&*self.delete_sql));

        self.connection.execute(delete_query.as_str(), &[] )
            .expect("delete failed");
    }

    pub fn read(&self, b: Bookmark) -> Result<Bookmark, rusqlite::Error> {
        let read_query = parse_query(&b.to_btree(), String::from(&*self.read_sql));

        let mut stmt = match self.connection.prepare(read_query.as_str()) {
            Ok(read) => read,
            Err(err) => panic!("read failed: {}", err),
        };

        let bookmark_iter = stmt.query_map(&[], |row| {
            Bookmark {
                id: row.get(0),
                name: row.get(1),
                url: row.get(2),
                rev_no: row.get(5)
            }
        }).unwrap();

        bookmark_iter.last().expect("read failed !")
    }

    pub fn update(&self, b: Bookmark) {
        let update_query = parse_query(&b.to_btree(), String::from(&*self.update_sql));

        match self.connection.execute(update_query.as_str(), &[] ) {
            Ok(update) => update,
            Err(err) => panic!("listed failed: {}", err),
        };

    }

    pub fn list(&self, b: Bookmark) -> Vec<Bookmark> {
        let mut list_bookmark = Vec::<Bookmark>::new();
        let list_query = parse_query(&b.to_btree(), String::from(&*self.list_sql));

         let mut query_result = match self.connection.prepare(list_query.as_str()) {
            Ok(list) => list,
            Err(err) => panic!("listed failed: {}", err),
        };

        let bookmark_iter = query_result.query_map(&[], |row| {
            let time_dump: String = row.get(3);
            let stamp_dump: String = row.get(4);

            Bookmark {
                id: row.get(0),
                name: row.get(1),
                url: row.get(2),
                rev_no: row.get(5)
            }
        }).unwrap();

        for result in bookmark_iter {
            match result {
                Ok(b) => list_bookmark.push(b),
                Err(_) => continue
            }
        }

        list_bookmark
    }
}

pub fn hello_from_dao() -> String {
    "Hello, I am bookmark dao!".to_string()
}
<commit_msg>clean<commit_after>extern crate chrono;
extern crate rusqlite;

use common::bookmark::*;
use dao::query_parser::*;

#[derive(Debug)]
pub struct BookmarkDao<'a> {
    pub connection: &'a rusqlite::Connection,
    pub read_sql: String,
    pub delete_sql: String,
    pub insert_sql: String,
    pub update_sql: String,
    pub list_sql: String
}

impl<'a> BookmarkDao<'a> {
    pub fn insert(&self, b: Bookmark) {
        let insert_query = parse_query(&b.to_btree(), String::from(&*self.insert_sql));

        match self.connection.execute(insert_query.as_str(), &[] ) {
            Ok(insert) => println!("{} rows were inserted", insert),
            Err(err) => panic!("insert failed: {}", err),
        }
    }

    pub fn delete(&self, b: Bookmark) {
        let delete_query = parse_query(&b.to_btree(), String::from(&*self.delete_sql));

        self.connection.execute(delete_query.as_str(), &[] )
            .expect("delete failed");
    }

    pub fn read(&self, b: Bookmark) -> Result<Bookmark, rusqlite::Error> {
        let read_query = parse_query(&b.to_btree(), String::from(&*self.read_sql));

        let mut stmt = match self.connection.prepare(read_query.as_str()) {
            Ok(read) => read,
            Err(err) => panic!("read failed: {}", err),
        };

        let bookmark_iter = stmt.query_map(&[], |row| {
            Bookmark {
                id: row.get(0),
                name: row.get(1),
                url: row.get(2),
                rev_no: row.get(5)
            }
        }).unwrap();

        bookmark_iter.last().expect("read failed !")
    }

    pub fn update(&self, b: Bookmark) {
        let update_query = parse_query(&b.to_btree(), String::from(&*self.update_sql));

        match self.connection.execute(update_query.as_str(), &[] ) {
            Ok(update) => update,
            Err(err) => panic!("listed failed: {}", err),
        };

    }

    pub fn list(&self, b: Bookmark) -> Vec<Bookmark> {
        let mut list_bookmark = Vec::<Bookmark>::new();
        let list_query = parse_query(&b.to_btree(), String::from(&*self.list_sql));

         let mut query_result = match self.connection.prepare(list_query.as_str()) {
            Ok(list) => list,
            Err(err) => panic!("listed failed: {}", err),
        };

        let bookmark_iter = query_result.query_map(&[], |row| {
            Bookmark {
                id: row.get(0),
                name: row.get(1),
                url: row.get(2),
                rev_no: row.get(3)
            }
        }).unwrap();

        for result in bookmark_iter {
            match result {
                Ok(b) => list_bookmark.push(b),
                Err(_) => continue
            }
        }

        list_bookmark
    }
}

pub fn hello_from_dao() -> String {
    "Hello, I am bookmark dao!".to_string()
}
<|endoftext|>


<commit_before>//! This module is UNSTABLE, the reason is - just added.

use std::convert::From;
use std::io::{self, Read, BufRead};
use std::str::{from_utf8, Utf8Error};

use super::{read_marker};
use super::{
    ReadError,
    MarkerReadError,
};
use super::{BigEndianRead};

use super::super::init::Marker;
use super::super::value::ValueRef;

// TODO: Display trait.
#[derive(Debug)]
pub enum Error<'r> {
    /// Failed to fill the internal reader buffer.
    ///
    /// RMP tries to obtain the buffer at the beginning of read operation using `read_buf` function.
    ///
    /// According to the Rust documentation, `fill_buf` function will return an I/O error if the
    /// underlying reader was read, but returned an error.
    InvalidBufferFill(io::Error),
    /// Failed to read the type marker value.
    InvalidMarkerRead(ReadError),
    /// Failed to read string/array/map size.
    InvalidLengthRead(ReadError),
    /// Failed to read packed non-marker data.
    InvalidDataRead(ReadError),

    // length overflow

    /// Failed to interpret a byte slice as a UTF-8 string.
    ///
    /// Contains untouched bytearray with the underlying decoding error.
    InvalidUtf8(&'r [u8], Utf8Error),
}

impl<'r> From<MarkerReadError> for Error<'r> {
    fn from(err: MarkerReadError) -> Error<'r> {
        Error::InvalidMarkerRead(From::from(err))
    }
}

fn read_length<R, D>(rd: &mut R) -> Result<D, ReadError>
    where R: Read,
          D: BigEndianRead
{
    D::read(rd).map_err(From::from)
}

fn read_str(buf: &[u8], len: usize) -> Result<&str, Error> {
    if len > buf.len() {
        return Err(Error::InvalidDataRead(ReadError::UnexpectedEOF));
    }

    // Take a slice.
    let buf = &buf[..len];

    // Try to decode sliced buffer as UTF-8.
    let res = try!(from_utf8(buf).map_err(|err| Error::InvalidUtf8(buf, err)));

    Ok(res)
}

// NOTE: Consumes nothing from the given `BufRead` either on success or fail.
pub fn read_value_ref<R>(rd: &mut R) -> Result<ValueRef, Error>
    where R: BufRead
{
    let mut buf = try!(rd.fill_buf().map_err(|err| Error::InvalidBufferFill(err)));

    // Reading the marker involves either 1 byte read or nothing. On success consumes strictly
    // 1 byte from the `buf`, not from the `rd`.
    let marker = try!(read_marker(&mut buf));

    let val = match marker {
        Marker::FixedString(len) => {
            // Impossible to panic, since u8 always fits in usize.
            let len = len as usize;

            let res = try!(read_str(buf, len));

            ValueRef::String(res)
        }
        Marker::Str8 => {
            let len: u8 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));

            // Impossible to panic, since u8 always fits in usize.
            let len = len as usize;

            let res = try!(read_str(buf, len));

            ValueRef::String(res)
        }
        _ => unimplemented!(),
    };

    Ok(val)
}

// TODO: Concepts: less code; more tests; fast refactoring after each test; no more than 5 min for
// each red-yellow-green.
<commit_msg>Cleanup: minor.<commit_after>//! This module is UNSTABLE, the reason is - just added.

use std::convert::From;
use std::io::{self, Read, BufRead};
use std::str::{from_utf8, Utf8Error};

use super::{read_marker};
use super::{
    ReadError,
    MarkerReadError,
};
use super::{BigEndianRead};

use super::super::init::Marker;
use super::super::value::ValueRef;

// TODO: Display trait.
#[derive(Debug)]
pub enum Error<'r> {
    /// Failed to fill the internal reader buffer.
    ///
    /// RMP tries to obtain the buffer at the beginning of read operation using `read_buf` function.
    ///
    /// According to the Rust documentation, `fill_buf` function will return an I/O error if the
    /// underlying reader was read, but returned an error.
    InvalidBufferFill(io::Error),
    /// Failed to read the type marker value.
    InvalidMarkerRead(ReadError),
    /// Failed to read string/array/map size.
    InvalidLengthRead(ReadError),
    /// Failed to read packed non-marker data.
    InvalidDataRead(ReadError),

    // length overflow (read length >= usize -> cannot be sliced).

    /// Failed to interpret a byte slice as a UTF-8 string.
    ///
    /// Contains untouched bytearray with the underlying decoding error.
    InvalidUtf8(&'r [u8], Utf8Error),
}

impl<'r> From<MarkerReadError> for Error<'r> {
    fn from(err: MarkerReadError) -> Error<'r> {
        Error::InvalidMarkerRead(From::from(err))
    }
}

fn read_length<R, D>(rd: &mut R) -> Result<D, ReadError>
    where R: Read,
          D: BigEndianRead
{
    D::read(rd).map_err(From::from)
}

fn read_str(buf: &[u8], len: usize) -> Result<&str, Error> {
    if len > buf.len() {
        return Err(Error::InvalidDataRead(ReadError::UnexpectedEOF));
    }

    // Take a slice.
    let buf = &buf[..len];

    // Try to decode sliced buffer as UTF-8.
    let res = try!(from_utf8(buf).map_err(|err| Error::InvalidUtf8(buf, err)));

    Ok(res)
}

// NOTE: Consumes nothing from the given `BufRead` either on success or fail.
pub fn read_value_ref<R>(rd: &mut R) -> Result<ValueRef, Error>
    where R: BufRead
{
    let mut buf = try!(rd.fill_buf().map_err(|err| Error::InvalidBufferFill(err)));

    // Reading the marker involves either 1 byte read or nothing. On success consumes strictly
    // 1 byte from the `buf`, not from the `rd`.
    let marker = try!(read_marker(&mut buf));

    let val = match marker {
        Marker::FixedString(len) => {
            // Impossible to panic, since u8 always fits in usize.
            let len = len as usize;
            let res = try!(read_str(buf, len));
            ValueRef::String(res)
        }
        Marker::Str8 => {
            let len: u8 = try!(read_length(&mut buf).map_err(|err| Error::InvalidLengthRead(err)));

            // Impossible to panic, since u8 always fits in usize.
            let len = len as usize;
            let res = try!(read_str(buf, len));
            ValueRef::String(res)
        }
        Marker::Str16 => {
            unimplemented!();
        }
        Marker::Str32 => {
            unimplemented!();
        }
        _ => unimplemented!(),
    };

    Ok(val)
}

// TODO: Concepts: less code; more tests; fast refactoring after each test; no more than 5 min for
// each red-yellow-green.
<|endoftext|>


<commit_before>//! Extensions to the parsing API with niche applicability.

use super::*;

/// Extensions to the `ParseStream` API to support speculative parsing.
pub trait Speculative {
    /// Advance this parse stream to the position of a forked parse stream.
    ///
    /// This is the opposite operation to [`ParseStream::fork`].
    /// You can fork a parse stream, perform some speculative parsing, then join
    /// the original stream to the fork to "commit" the parsing from the fork to
    /// the main stream.
    ///
    /// If you can avoid doing this, you should, as it limits the ability to
    /// generate useful errors. That said, it is often the only way to parse
    /// syntax of the form `A* B*` for arbitrary syntax `A` and `B`. The problem
    /// is that when the fork fails to parse an `A`, it's impossible to tell
    /// whether that was because of a syntax error and the user meant to provide
    /// an `A`, or that the `A`s are finished and its time to start parsing `B`s.
    /// Use with care.
    ///
    /// Also note that if `A` is a subset of `B`, `A* B*` can be parsed by parsing
    /// `B*` and removing the leading members of `A` from the repetition, bypassing
    /// the need to involve the downsides associated with speculative parsing.
    ///
    /// [`ParseStream::fork`]: ../struct.ParseBuffer.html#method.fork
    ///
    /// # Example
    ///
    /// There has been chatter about the possibility of making the colons in the
    /// turbofish syntax like `path::to::<T>` no longer required by accepting
    /// `path::to<T>` in expression position. Specifically, according to [RFC#2544],
    /// [`PathSegment`] parsing should always try to consume a following `<` token
    /// as the start of generic arguments, and reset to the `<` if that fails
    /// (e.g. the token is acting as a less-than operator).
    ///
    /// This is the exact kind of parsing behavior which requires the "fork, try,
    /// commit" behavior that [`ParseStream::fork`] discourages. With `advance_to`,
    /// we can avoid having to parse the speculatively parsed content a second time.
    ///
    /// This change in behavior can be implemented in syn by replacing just the
    /// `Parse` implementation for `PathSegment`:
    ///
    /// ```edition2018
    /// # use syn::ext::IdentExt;
    /// use syn::parse::discouraged::Speculative;
    /// # use syn::parse::{Parse, ParseStream};
    /// # use syn::{Ident, PathArguments, Result, Token};
    ///
    /// pub struct PathSegment {
    ///     pub ident: Ident,
    ///     pub arguments: PathArguments,
    /// }
    ///
    /// # impl<T> From<T> for PathSegment
    /// # where
    /// #     T: Into<Ident>,
    /// # {
    /// #     fn from(ident: T) -> Self {
    /// #         PathSegment {
    /// #             ident: ident.into(),
    /// #             arguments: PathArguments::None,
    /// #         }
    /// #     }
    /// # }
    ///
    ///
    /// impl Parse for PathSegment {
    ///     fn parse(input: ParseStream) -> Result<Self> {
    ///         if input.peek(Token![super])
    ///             || input.peek(Token![self])
    ///             || input.peek(Token![Self])
    ///             || input.peek(Token![crate])
    ///             || input.peek(Token![extern])
    ///         {
    ///             let ident = input.call(Ident::parse_any)?;
    ///             return Ok(PathSegment::from(ident));
    ///         }
    ///
    ///         let ident = input.parse()?;
    ///         if input.peek(Token![::]) && input.peek3(Token![<]) {
    ///             return Ok(PathSegment {
    ///                 ident: ident,
    ///                 arguments: PathArguments::AngleBracketed(input.parse()?),
    ///             });
    ///         }
    ///         if input.peek(Token![<]) && !input.peek(Token![<=]) {
    ///             let fork = input.fork();
    ///             if let Ok(arguments) = fork.parse() {
    ///                 input.advance_to(&fork);
    ///                 return Ok(PathSegment {
    ///                     ident: ident,
    ///                     arguments: PathArguments::AngleBracketed(arguments),
    ///                 });
    ///             }
    ///         }
    ///         Ok(PathSegment::from(ident))
    ///     }
    /// }
    ///
    /// # syn::parse_str::<PathSegment>("a<b,c>").unwrap();
    /// ```
    ///
    /// # Drawbacks
    ///
    /// The main drawback of this style of speculative parsing is in error
    /// presentation. Even if the lookahead is the "correct" parse, the error
    /// that is shown is that of the "fallback" parse. To use the same example
    /// as the turbofish above, take the following unfinished "turbofish":
    ///
    /// ```text
    /// let _ = f<&'a fn(), for<'a> serde::>();
    /// ```
    ///
    /// If this is parsed as generic arguments, we can provide the error message
    ///
    /// ```text
    /// error: expected identifier
    ///  --> src.rs:L:C
    ///   |
    /// L | let _ = f<&'a fn(), for<'a> serde::>();
    ///   |                                    ^
    /// ```
    ///
    /// but if parsed using the above speculative parsing, it falls back to
    /// assuming that the `<` is a less-than when it fails to parse the
    /// generic arguments, and tries to interpret the `&'a` as the start of a
    /// labelled loop, resulting in the much less helpful error
    ///
    /// ```text
    /// error: expected `:`
    ///  --> src.rs:L:C
    ///   |
    /// L | let _ = f<&'a fn(), for<'a> serde::>();
    ///   |               ^^
    /// ```
    ///
    /// This can be mitigated with various heuristics (two examples: show both
    /// forks' parse errors, or show the one that consumed more tokens), but
    /// when you can control the grammar, sticking to something that can be
    /// parsed LL(3) and without the LL(*) speculative parsing this makes
    /// possible, displaying reasonable errors becomes much more simple.
    ///
    /// [RFC#2544]: https://github.com/rust-lang/rfcs/pull/2544
    /// [`PathSegment`]: ../../struct.PathSegment.html
    ///
    /// # Performance
    ///
    /// This method performs a cheap fixed amount of work that does not depend
    /// on how far apart the two streams are positioned.
    ///
    /// # Panics
    ///
    /// The forked stream in the argument of `advance_to` must have been
    /// obtained by forking `self`. Attempting to advance to any other stream
    /// will cause a panic.
    fn advance_to(&self, fork: &Self);
}

impl<'a> Speculative for ParseBuffer<'a> {
    fn advance_to(&self, fork: &Self) {
        if !private::same_scope(self.cursor(), fork.cursor()) {
            panic!("Fork was not derived from the advancing parse stream");
        }

        // See comment on `cell` in the struct definition.
        self.cell
            .set(unsafe { mem::transmute::<Cursor, Cursor<'static>>(fork.cursor()) })
    }
}
<commit_msg>Format rfc link without #<commit_after>//! Extensions to the parsing API with niche applicability.

use super::*;

/// Extensions to the `ParseStream` API to support speculative parsing.
pub trait Speculative {
    /// Advance this parse stream to the position of a forked parse stream.
    ///
    /// This is the opposite operation to [`ParseStream::fork`].
    /// You can fork a parse stream, perform some speculative parsing, then join
    /// the original stream to the fork to "commit" the parsing from the fork to
    /// the main stream.
    ///
    /// If you can avoid doing this, you should, as it limits the ability to
    /// generate useful errors. That said, it is often the only way to parse
    /// syntax of the form `A* B*` for arbitrary syntax `A` and `B`. The problem
    /// is that when the fork fails to parse an `A`, it's impossible to tell
    /// whether that was because of a syntax error and the user meant to provide
    /// an `A`, or that the `A`s are finished and its time to start parsing `B`s.
    /// Use with care.
    ///
    /// Also note that if `A` is a subset of `B`, `A* B*` can be parsed by parsing
    /// `B*` and removing the leading members of `A` from the repetition, bypassing
    /// the need to involve the downsides associated with speculative parsing.
    ///
    /// [`ParseStream::fork`]: ../struct.ParseBuffer.html#method.fork
    ///
    /// # Example
    ///
    /// There has been chatter about the possibility of making the colons in the
    /// turbofish syntax like `path::to::<T>` no longer required by accepting
    /// `path::to<T>` in expression position. Specifically, according to [RFC 2544],
    /// [`PathSegment`] parsing should always try to consume a following `<` token
    /// as the start of generic arguments, and reset to the `<` if that fails
    /// (e.g. the token is acting as a less-than operator).
    ///
    /// This is the exact kind of parsing behavior which requires the "fork, try,
    /// commit" behavior that [`ParseStream::fork`] discourages. With `advance_to`,
    /// we can avoid having to parse the speculatively parsed content a second time.
    ///
    /// This change in behavior can be implemented in syn by replacing just the
    /// `Parse` implementation for `PathSegment`:
    ///
    /// ```edition2018
    /// # use syn::ext::IdentExt;
    /// use syn::parse::discouraged::Speculative;
    /// # use syn::parse::{Parse, ParseStream};
    /// # use syn::{Ident, PathArguments, Result, Token};
    ///
    /// pub struct PathSegment {
    ///     pub ident: Ident,
    ///     pub arguments: PathArguments,
    /// }
    ///
    /// # impl<T> From<T> for PathSegment
    /// # where
    /// #     T: Into<Ident>,
    /// # {
    /// #     fn from(ident: T) -> Self {
    /// #         PathSegment {
    /// #             ident: ident.into(),
    /// #             arguments: PathArguments::None,
    /// #         }
    /// #     }
    /// # }
    ///
    ///
    /// impl Parse for PathSegment {
    ///     fn parse(input: ParseStream) -> Result<Self> {
    ///         if input.peek(Token![super])
    ///             || input.peek(Token![self])
    ///             || input.peek(Token![Self])
    ///             || input.peek(Token![crate])
    ///             || input.peek(Token![extern])
    ///         {
    ///             let ident = input.call(Ident::parse_any)?;
    ///             return Ok(PathSegment::from(ident));
    ///         }
    ///
    ///         let ident = input.parse()?;
    ///         if input.peek(Token![::]) && input.peek3(Token![<]) {
    ///             return Ok(PathSegment {
    ///                 ident: ident,
    ///                 arguments: PathArguments::AngleBracketed(input.parse()?),
    ///             });
    ///         }
    ///         if input.peek(Token![<]) && !input.peek(Token![<=]) {
    ///             let fork = input.fork();
    ///             if let Ok(arguments) = fork.parse() {
    ///                 input.advance_to(&fork);
    ///                 return Ok(PathSegment {
    ///                     ident: ident,
    ///                     arguments: PathArguments::AngleBracketed(arguments),
    ///                 });
    ///             }
    ///         }
    ///         Ok(PathSegment::from(ident))
    ///     }
    /// }
    ///
    /// # syn::parse_str::<PathSegment>("a<b,c>").unwrap();
    /// ```
    ///
    /// # Drawbacks
    ///
    /// The main drawback of this style of speculative parsing is in error
    /// presentation. Even if the lookahead is the "correct" parse, the error
    /// that is shown is that of the "fallback" parse. To use the same example
    /// as the turbofish above, take the following unfinished "turbofish":
    ///
    /// ```text
    /// let _ = f<&'a fn(), for<'a> serde::>();
    /// ```
    ///
    /// If this is parsed as generic arguments, we can provide the error message
    ///
    /// ```text
    /// error: expected identifier
    ///  --> src.rs:L:C
    ///   |
    /// L | let _ = f<&'a fn(), for<'a> serde::>();
    ///   |                                    ^
    /// ```
    ///
    /// but if parsed using the above speculative parsing, it falls back to
    /// assuming that the `<` is a less-than when it fails to parse the
    /// generic arguments, and tries to interpret the `&'a` as the start of a
    /// labelled loop, resulting in the much less helpful error
    ///
    /// ```text
    /// error: expected `:`
    ///  --> src.rs:L:C
    ///   |
    /// L | let _ = f<&'a fn(), for<'a> serde::>();
    ///   |               ^^
    /// ```
    ///
    /// This can be mitigated with various heuristics (two examples: show both
    /// forks' parse errors, or show the one that consumed more tokens), but
    /// when you can control the grammar, sticking to something that can be
    /// parsed LL(3) and without the LL(*) speculative parsing this makes
    /// possible, displaying reasonable errors becomes much more simple.
    ///
    /// [RFC 2544]: https://github.com/rust-lang/rfcs/pull/2544
    /// [`PathSegment`]: ../../struct.PathSegment.html
    ///
    /// # Performance
    ///
    /// This method performs a cheap fixed amount of work that does not depend
    /// on how far apart the two streams are positioned.
    ///
    /// # Panics
    ///
    /// The forked stream in the argument of `advance_to` must have been
    /// obtained by forking `self`. Attempting to advance to any other stream
    /// will cause a panic.
    fn advance_to(&self, fork: &Self);
}

impl<'a> Speculative for ParseBuffer<'a> {
    fn advance_to(&self, fork: &Self) {
        if !private::same_scope(self.cursor(), fork.cursor()) {
            panic!("Fork was not derived from the advancing parse stream");
        }

        // See comment on `cell` in the struct definition.
        self.cell
            .set(unsafe { mem::transmute::<Cursor, Cursor<'static>>(fork.cursor()) })
    }
}
<|endoftext|>


<commit_before>use syn::parenthesized;
use syn::parse::{discouraged::Speculative, Parse, ParseStream, Parser, Result};

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_between_sources() {
    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input1: ParseStream) -> Result<Self> {
            let nested = |input2: ParseStream| {
                input1.advance_to(&input2);
                Ok(Self)
            };
            nested.parse_str("")
        }
    }

    syn::parse_str::<BreakRules>("").unwrap();
}

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_between_brackets() {
    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input: ParseStream) -> Result<Self> {
            let a;
            let b;
            parenthesized!(a in input);
            parenthesized!(b in input);
            a.advance_to(&b);
            Ok(Self)
        }
    }

    syn::parse_str::<BreakRules>("()()").unwrap();
}

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_into_brackets() {
    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input: ParseStream) -> Result<Self> {
            let a;
            parenthesized!(a in input);
            input.advance_to(&a);
            Ok(Self)
        }
    }

    syn::parse_str::<BreakRules>("()").unwrap();
}
<commit_msg>Add test for parsing with trailing None delimited groups<commit_after>use proc_macro2::{Delimiter, Group, Punct, Spacing, TokenStream, TokenTree};
use std::iter::FromIterator;
use syn::parse::{discouraged::Speculative, Parse, ParseStream, Parser, Result};
use syn::{parenthesized, Token};

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_between_sources() {
    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input1: ParseStream) -> Result<Self> {
            let nested = |input2: ParseStream| {
                input1.advance_to(&input2);
                Ok(Self)
            };
            nested.parse_str("")
        }
    }

    syn::parse_str::<BreakRules>("").unwrap();
}

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_between_brackets() {
    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input: ParseStream) -> Result<Self> {
            let a;
            let b;
            parenthesized!(a in input);
            parenthesized!(b in input);
            a.advance_to(&b);
            Ok(Self)
        }
    }

    syn::parse_str::<BreakRules>("()()").unwrap();
}

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_into_brackets() {
    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input: ParseStream) -> Result<Self> {
            let a;
            parenthesized!(a in input);
            input.advance_to(&a);
            Ok(Self)
        }
    }

    syn::parse_str::<BreakRules>("()").unwrap();
}

#[test]
fn trailing_empty_none_group() {
    fn parse(input: ParseStream) -> Result<()> {
        input.parse::<Token![+]>()?;

        let content;
        parenthesized!(content in input);
        content.parse::<Token![+]>()?;

        Ok(())
    }

    // `+ ( + <Ø Ø> ) <Ø <Ø Ø> Ø>`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Punct(Punct::new('+', Spacing::Alone)),
        TokenTree::Group(Group::new(
            Delimiter::Parenthesis,
            TokenStream::from_iter(vec![
                TokenTree::Punct(Punct::new('+', Spacing::Alone)),
                TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())),
            ]),
        )),
        TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())),
        TokenTree::Group(Group::new(
            Delimiter::None,
            TokenStream::from_iter(vec![TokenTree::Group(Group::new(
                Delimiter::None,
                TokenStream::new(),
            ))]),
        )),
    ]);

    parse.parse2(tokens).unwrap();
}
<|endoftext|>


<commit_before>
#![feature(alloc_system)]

extern crate alloc_system;

#[macro_use]
extern crate rustfbp;
extern crate capnp;

use self::rustfbp::scheduler::{Scheduler, Comp};
use self::rustfbp::ports::{IP, Ports};

use std::collections::HashMap;
use std::env;

fn main() {
    run(&env::args().nth(1).unwrap());
}

mod edge_capnp {
    include!("path_capnp.rs");
    include!("fbp_action.rs");
}
use edge_capnp::fbp_action;

#[allow(unused_must_use)]
fn run(path_fbp: &str) {

    let mut sched = Scheduler::new();
    sched.add_node("open", "fs_file_open.so");
    sched.add_node("lex", "nucleus_flow_parser_lexical.so");
    sched.add_node("sem", "nucleus_flow_parser_semantic.so");
    sched.add_node("vm", "nucleus_flow_vm.so");
    sched.add_node("errors", "nucleus_flow_errors.so");
    sched.add_node("graph_print", "nucleus_flow_parser_graph_print.so");
    sched.add_node("graph_check", "nucleus_flow_parser_graph_check.so");
    sched.add_node("sched", "nucleus_flow_scheduler.so");
    sched.add_node("iip", "nucleus_capnp_encode.so");
    sched.add_node("nucleus_find_edge", "nucleus_find_edge.so");
    sched.add_node("nucleus_find_node", "nucleus_find_node.so");
    sched.add_node("halter", "halter.so");

    let (mut p, senders) = Ports::new("exterior".into(), sched.sender.clone(),
                                      vec!["r".into()],
                                      vec![],
                                      vec!["s".into(), "opt".into(), "w".into(),
                                           "h".into(), "add".into()],
                                      vec![]).expect("cannot create");
    sched.agents.insert("exterior".into(), Comp {
        inputs: senders,
        inputs_array: HashMap::new(),
        sort: "".into(),
        start: false,
    });

    // Send the start ip for the graph
    p.connect("h".into(), sched.get_sender("halter".into(), "input".into()).unwrap()).expect("unable to connect");
    let start_ip = IP::new();
    p.send("h".into(), start_ip).expect("start");

    p.connect("s".into(), sched.get_sender("open".into(), "input".into()).unwrap()).expect("unable to connect");
    sched.connect("open".into(), "output".into(), "lex".into(), "input".into()).expect("cannot connect");
    sched.connect("lex".into(), "output".into(), "sem".into(), "input".into()).expect("cannot connect");
    sched.connect("sem".into(), "output".into(), "graph_check".into(), "input".into()).expect("cannot connect");
    sched.connect("graph_check".into(), "output".into(), "vm".into(), "input".into()).expect("cannot connect");
    sched.connect("graph_check".into(), "error".into(), "errors".into(), "semantic_error".into()).expect("cannot connect");

    sched.connect("open".into(), "error".into(), "errors".into(), "file_error".into()).expect("cannot connect");
    sched.connect("sem".into(), "error".into(), "errors".into(), "semantic_error".into()).expect("cannot connect");
    sched.connect("errors".into(), "output".into(), "vm".into(), "input".into()).expect("cannot connect");

    // reccursive part
    sched.connect("vm".into(), "ask_graph".into(), "open".into(), "input".into()).expect("cannot connect");

    // With Graph print
    // sched.connect("vm".into(), "output".into(), "graph_print".into(), "input".into()).expect("cannot connect");
    // sched.connect("graph_print".into(), "output".into(), "sched".into(), "graph".into()).expect("cannot connect");

    // Without Graph print
    sched.connect("vm".into(), "output".into(), "sched".into(), "graph".into()).expect("cannot connect");

    sched.connect("sched".into(), "ask_path".into(), "nucleus_find_edge".into(), "input".into()).expect("cannot connect");
    sched.connect("nucleus_find_edge".into(), "output".into(), "sched".into(), "edge_path".into()).expect("cannot connect");

    sched.connect("vm".into(), "ask_path".into(), "nucleus_find_node".into(), "input".into()).expect("cannot connect");
    sched.connect("nucleus_find_node".into(), "output".into(), "vm".into(), "new_path".into()).expect("cannot connect");

    // IIP part
    sched.connect("sched".into(), "iip_path".into(), "iip".into(), "path".into()).expect("cannot connect");
    sched.connect("sched".into(), "iip_edge".into(), "iip".into(), "edge".into()).expect("cannot connect");
    sched.connect("sched".into(), "iip_input".into(), "iip".into(), "input".into()).expect("cannot connect");
    sched.connect("iip".into(), "output".into(), "sched".into(), "iip".into()).expect("cannot connect");

    sched.connect("sched".into(), "ask_graph".into(), "vm".into(), "input".into()).expect("cannot connect ask_graph");

    // Send the first IP to the scheduler
    p.connect("add".into(), sched.get_sender("sched".into(), "action".into()).unwrap()).expect("unable to connect");
    let mut start_ip = IP::new();
    {
        let builder: fbp_action::Builder = start_ip.build_schema();
        let mut add = builder.init_add();
        add.set_name("main");
        add.set_comp(&path_fbp);
    }
    p.send("add".into(), start_ip).expect("add");

    sched.join();
}
<commit_msg>VM: new structures<commit_after>
#![feature(alloc_system)]

extern crate alloc_system;

#[macro_use]
extern crate rustfbp;
extern crate capnp;

use self::rustfbp::scheduler::{Scheduler, Comp};
use self::rustfbp::ports::{IP};

use std::collections::HashMap;
use std::env;

fn main() {
    run(&env::args().nth(1).unwrap());
}

mod edge_capnp {
    include!("path_capnp.rs");
    include!("fbp_action.rs");
}
use edge_capnp::fbp_action;

#[allow(unused_must_use)]
fn run(path_fbp: &str) {

    let mut sched = Scheduler::new();
    sched.add_node("open", "fs_file_open.so").expect("cannot add node");
    sched.add_node("lex", "nucleus_flow_parser_lexical.so").expect("cannot add node");
    sched.add_node("sem", "nucleus_flow_parser_semantic.so").expect("cannot add node");
    sched.add_node("vm", "nucleus_flow_vm.so").expect("cannot add node");
    sched.add_node("errors", "nucleus_flow_errors.so").expect("cannot add node");
    sched.add_node("graph_print", "nucleus_flow_parser_graph_print.so").expect("cannot add node");
    sched.add_node("graph_check", "nucleus_flow_parser_graph_check.so").expect("cannot add node");
    sched.add_node("sched", "nucleus_flow_scheduler.so").expect("cannot add node");
    sched.add_node("iip", "nucleus_capnp_encode.so").expect("cannot add node");
    sched.add_node("nucleus_find_edge", "nucleus_find_edge.so").expect("cannot add node");
    sched.add_node("nucleus_find_node", "nucleus_find_node.so").expect("cannot add node");
    sched.add_node("halter", "halter.so").expect("cannot add node");

    // Send the start ip for the graph
    let h = sched.get_sender("halter".into(), "input".into()).expect("halter not found");
    let start_ip = IP::new();
    h.send(start_ip).expect("start");

    sched.connect("open".into(), "output".into(), "lex".into(), "input".into()).expect("cannot connect");
    sched.connect("lex".into(), "output".into(), "sem".into(), "input".into()).expect("cannot connect");
    sched.connect("sem".into(), "output".into(), "graph_check".into(), "input".into()).expect("cannot connect");
    sched.connect("graph_check".into(), "output".into(), "vm".into(), "input".into()).expect("cannot connect");
    sched.connect("graph_check".into(), "error".into(), "errors".into(), "semantic_error".into()).expect("cannot connect");

    sched.connect("open".into(), "error".into(), "errors".into(), "file_error".into()).expect("cannot connect");
    sched.connect("sem".into(), "error".into(), "errors".into(), "semantic_error".into()).expect("cannot connect");
    sched.connect("errors".into(), "output".into(), "vm".into(), "input".into()).expect("cannot connect");

    // reccursive part
    sched.connect("vm".into(), "ask_graph".into(), "open".into(), "input".into()).expect("cannot connect");

    // With Graph print
    // sched.connect("vm".into(), "output".into(), "graph_print".into(), "input".into()).expect("cannot connect");
    // sched.connect("graph_print".into(), "output".into(), "sched".into(), "graph".into()).expect("cannot connect");

    // Without Graph print
    sched.connect("vm".into(), "output".into(), "sched".into(), "graph".into()).expect("cannot connect");

    sched.connect("sched".into(), "ask_path".into(), "nucleus_find_edge".into(), "input".into()).expect("cannot connect");
    sched.connect("nucleus_find_edge".into(), "output".into(), "sched".into(), "edge_path".into()).expect("cannot connect");

    sched.connect("vm".into(), "ask_path".into(), "nucleus_find_node".into(), "input".into()).expect("cannot connect");
    sched.connect("nucleus_find_node".into(), "output".into(), "vm".into(), "new_path".into()).expect("cannot connect");

    // IIP part
    sched.connect("sched".into(), "iip_path".into(), "iip".into(), "path".into()).expect("cannot connect");
    sched.connect("sched".into(), "iip_edge".into(), "iip".into(), "edge".into()).expect("cannot connect");
    sched.connect("sched".into(), "iip_input".into(), "iip".into(), "input".into()).expect("cannot connect");
    sched.connect("iip".into(), "output".into(), "sched".into(), "iip".into()).expect("cannot connect");

    sched.connect("sched".into(), "ask_graph".into(), "vm".into(), "input".into()).expect("cannot connect ask_graph");

    let add = sched.get_sender("sched".into(), "action".into()).expect("action of sched not found");

    // Send the first IP to the scheduler
    let mut start_ip = IP::new();
    {
        let builder: fbp_action::Builder = start_ip.build_schema();
        let mut add = builder.init_add();
        add.set_name("main");
        add.set_comp(&path_fbp);
    }
    add.send(start_ip).expect("cannot send start_ip");
    sched.join();
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::build_project::{build_project, build_schema, commit_project};
use crate::compiler_state::{ArtifactMapKind, CompilerState, ProjectName};
use crate::config::Config;
use crate::errors::{BuildProjectError, Error, Result};
use crate::graphql_asts::GraphQLAsts;
use crate::{source_for_location, watchman::FileSource};
use common::{Diagnostic, PerfLogEvent, PerfLogger};
use futures::future::join_all;
use graphql_cli::DiagnosticPrinter;
use log::{error, info};
use rayon::prelude::*;
use schema::Schema;
use std::{collections::HashMap, sync::Arc};
use tokio::task;

pub struct Compiler<TPerfLogger>
where
    TPerfLogger: PerfLogger + 'static,
{
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
}

impl<TPerfLogger: PerfLogger> Compiler<TPerfLogger> {
    pub fn new(config: Config, perf_logger: Arc<TPerfLogger>) -> Self {
        Self {
            config: Arc::new(config),
            perf_logger,
        }
    }

    pub async fn compile(self) -> Result<CompilerState> {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;
        let mut compiler_state = file_source
            .query(&setup_event, self.perf_logger.as_ref())
            .await?;
        self.build_projects(&mut compiler_state, &setup_event)
            .await?;

        self.perf_logger.complete_event(setup_event);

        self.config.artifact_writer.finalize()?;

        Ok(compiler_state)
    }

    pub fn build_schemas(
        &self,
        compiler_state: &CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> HashMap<ProjectName, Arc<Schema>> {
        let timer = setup_event.start("build_schemas");
        let mut schemas = HashMap::new();
        for project_config in self.config.enabled_projects() {
            let schema = build_schema(compiler_state, project_config);
            schemas.insert(project_config.name, Arc::new(schema));
        }
        setup_event.stop(timer);
        schemas
    }

    pub async fn watch(&self) -> Result<()> {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;

        let (mut compiler_state, mut subscription) = file_source
            .subscribe(&setup_event, self.perf_logger.as_ref())
            .await?;

        if self
            .build_projects(&mut compiler_state, &setup_event)
            .await
            .is_err()
        {
            // noop, build_projects should have logged already
        } else {
            info!("Compilation completed.");
        }
        self.perf_logger.complete_event(setup_event);
        info!("Waiting for changes...");

        loop {
            if let Some(file_source_changes) = subscription.next_change().await? {
                let incremental_build_event =
                    self.perf_logger.create_event("incremental_build_event");
                let incremental_build_time =
                    incremental_build_event.start("incremental_build_time");

                // TODO Single change to file in VSCode sometimes produces
                // 2 watchman change events for the same file

                info!("Change detected.");
                let had_new_changes = compiler_state.merge_file_source_changes(
                    &self.config,
                    &file_source_changes,
                    &incremental_build_event,
                    self.perf_logger.as_ref(),
                    false,
                )?;

                if had_new_changes {
                    info!("Start compiling...");
                    if self
                        .build_projects(&mut compiler_state, &incremental_build_event)
                        .await
                        .is_err()
                    {
                        // noop, build_projects should have logged already
                    } else {
                        info!("Compilation completed.");
                    }
                    incremental_build_event.stop(incremental_build_time);
                } else {
                    incremental_build_event.stop(incremental_build_time);
                    info!("No compilation required.");
                }
                self.perf_logger.complete_event(incremental_build_event);
                // We probably don't want the messages queue to grow indefinitely
                // and we need to flush then, as the check/build is completed
                self.perf_logger.flush();
                info!("Waiting for changes...");
            }
        }
    }

    async fn build_projects(
        &self,
        compiler_state: &mut CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> Result<()> {
        let result = build_projects(
            Arc::clone(&self.config),
            Arc::clone(&self.perf_logger),
            setup_event,
            compiler_state,
        )
        .await;
        match result {
            Ok(()) => {
                compiler_state.complete_compilation();
                Ok(())
            }
            Err(error) => {
                match &error {
                    Error::DiagnosticsError { errors } => {
                        for diagnostic in errors {
                            self.print_diagnostic(diagnostic);
                        }
                    }
                    Error::BuildProjectsErrors { errors } => {
                        for error in errors {
                            self.print_project_error(error);
                        }
                    }
                    error => {
                        error!("{}", error);
                    }
                }
                error!("Compilation failed.");
                Err(error)
            }
        }
    }

    fn print_project_error(&self, error: &BuildProjectError) {
        if let BuildProjectError::ValidationErrors { errors } = error {
            for diagnostic in errors {
                self.print_diagnostic(diagnostic);
            }
        };
    }

    fn print_diagnostic(&self, diagnostic: &Diagnostic) {
        let printer = DiagnosticPrinter::new(|source_location| {
            source_for_location(&self.config.root_dir, source_location).map(|source| source.text)
        });
        error!("{}", printer.diagnostic_to_string(diagnostic));
    }
}

async fn build_projects<TPerfLogger: PerfLogger + 'static>(
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
    setup_event: &impl PerfLogEvent,
    compiler_state: &mut CompilerState,
) -> Result<()> {
    let mut graphql_asts = setup_event.time("parse_sources_time", || {
        GraphQLAsts::from_graphql_sources_map(
            &compiler_state.graphql_sources,
            &compiler_state.dirty_definitions,
        )
    })?;

    let build_results: Vec<_> = config
        .par_enabled_projects()
        .filter(|project_config| compiler_state.project_has_pending_changes(project_config.name))
        .map(|project_config| {
            build_project(
                &config,
                project_config,
                compiler_state,
                &graphql_asts,
                Arc::clone(&perf_logger),
            )
        })
        .collect();
    let mut results = Vec::new();
    let mut errors = Vec::new();
    for result in build_results {
        match result {
            Ok(result) => results.push(result),
            Err(error) => errors.push(error),
        }
    }

    if errors.is_empty() {
        let mut handles = Vec::new();
        for (project_name, schema, programs, artifacts) in results {
            let config = Arc::clone(&config);
            let perf_logger = Arc::clone(&perf_logger);
            let artifact_map = compiler_state
                .artifacts
                .get(&project_name)
                .cloned()
                .unwrap_or_else(|| Arc::new(ArtifactMapKind::Unconnected(Default::default())));
            let removed_definition_names = graphql_asts
                .remove(&project_name)
                .expect("Expect GraphQLAsts to exist.")
                .removed_definition_names;
            handles.push(task::spawn(async move {
                let project_config = &config.projects[&project_name];
                Ok((
                    project_name,
                    commit_project(
                        &config,
                        project_config,
                        perf_logger,
                        &schema,
                        programs,
                        artifacts,
                        artifact_map,
                        removed_definition_names,
                    )
                    .await?,
                ))
            }));
        }
        for commit_result in join_all(handles).await {
            match commit_result.unwrap() {
                Ok((project_name, next_artifact_map)) => {
                    let next_artifact_map = Arc::new(ArtifactMapKind::Mapping(next_artifact_map));
                    compiler_state
                        .artifacts
                        .insert(project_name, next_artifact_map);
                }
                Err(error) => {
                    errors.push(error);
                }
            }
        }
    };

    if errors.is_empty() {
        Ok(())
    } else {
        Err(Error::BuildProjectsErrors { errors })
    }
}
<commit_msg>ensure all project errors are printed<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::build_project::{build_project, build_schema, commit_project};
use crate::compiler_state::{ArtifactMapKind, CompilerState, ProjectName};
use crate::config::Config;
use crate::errors::{BuildProjectError, Error, Result};
use crate::graphql_asts::GraphQLAsts;
use crate::{source_for_location, watchman::FileSource};
use common::{Diagnostic, PerfLogEvent, PerfLogger};
use futures::future::join_all;
use graphql_cli::DiagnosticPrinter;
use log::{error, info};
use rayon::prelude::*;
use schema::Schema;
use std::{collections::HashMap, sync::Arc};
use tokio::task;

pub struct Compiler<TPerfLogger>
where
    TPerfLogger: PerfLogger + 'static,
{
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
}

impl<TPerfLogger: PerfLogger> Compiler<TPerfLogger> {
    pub fn new(config: Config, perf_logger: Arc<TPerfLogger>) -> Self {
        Self {
            config: Arc::new(config),
            perf_logger,
        }
    }

    pub async fn compile(self) -> Result<CompilerState> {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;
        let mut compiler_state = file_source
            .query(&setup_event, self.perf_logger.as_ref())
            .await?;
        self.build_projects(&mut compiler_state, &setup_event)
            .await?;

        self.perf_logger.complete_event(setup_event);

        self.config.artifact_writer.finalize()?;

        Ok(compiler_state)
    }

    pub fn build_schemas(
        &self,
        compiler_state: &CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> HashMap<ProjectName, Arc<Schema>> {
        let timer = setup_event.start("build_schemas");
        let mut schemas = HashMap::new();
        for project_config in self.config.enabled_projects() {
            let schema = build_schema(compiler_state, project_config);
            schemas.insert(project_config.name, Arc::new(schema));
        }
        setup_event.stop(timer);
        schemas
    }

    pub async fn watch(&self) -> Result<()> {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;

        let (mut compiler_state, mut subscription) = file_source
            .subscribe(&setup_event, self.perf_logger.as_ref())
            .await?;

        if self
            .build_projects(&mut compiler_state, &setup_event)
            .await
            .is_err()
        {
            // noop, build_projects should have logged already
        } else {
            info!("Compilation completed.");
        }
        self.perf_logger.complete_event(setup_event);
        info!("Waiting for changes...");

        loop {
            if let Some(file_source_changes) = subscription.next_change().await? {
                let incremental_build_event =
                    self.perf_logger.create_event("incremental_build_event");
                let incremental_build_time =
                    incremental_build_event.start("incremental_build_time");

                // TODO Single change to file in VSCode sometimes produces
                // 2 watchman change events for the same file

                info!("Change detected.");
                let had_new_changes = compiler_state.merge_file_source_changes(
                    &self.config,
                    &file_source_changes,
                    &incremental_build_event,
                    self.perf_logger.as_ref(),
                    false,
                )?;

                if had_new_changes {
                    info!("Start compiling...");
                    if self
                        .build_projects(&mut compiler_state, &incremental_build_event)
                        .await
                        .is_err()
                    {
                        // noop, build_projects should have logged already
                    } else {
                        info!("Compilation completed.");
                    }
                    incremental_build_event.stop(incremental_build_time);
                } else {
                    incremental_build_event.stop(incremental_build_time);
                    info!("No compilation required.");
                }
                self.perf_logger.complete_event(incremental_build_event);
                // We probably don't want the messages queue to grow indefinitely
                // and we need to flush then, as the check/build is completed
                self.perf_logger.flush();
                info!("Waiting for changes...");
            }
        }
    }

    async fn build_projects(
        &self,
        compiler_state: &mut CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> Result<()> {
        let result = build_projects(
            Arc::clone(&self.config),
            Arc::clone(&self.perf_logger),
            setup_event,
            compiler_state,
        )
        .await;
        match result {
            Ok(()) => {
                compiler_state.complete_compilation();
                Ok(())
            }
            Err(error) => {
                match &error {
                    Error::DiagnosticsError { errors } => {
                        for diagnostic in errors {
                            self.print_diagnostic(diagnostic);
                        }
                    }
                    Error::BuildProjectsErrors { errors } => {
                        for error in errors {
                            self.print_project_error(error);
                        }
                    }
                    error => {
                        error!("{}", error);
                    }
                }
                error!("Compilation failed.");
                Err(error)
            }
        }
    }

    fn print_project_error(&self, error: &BuildProjectError) {
        match error {
            BuildProjectError::ValidationErrors { errors } => {
                for diagnostic in errors {
                    self.print_diagnostic(diagnostic);
                }
            }
            BuildProjectError::PersistErrors { errors } => {
                for error in errors {
                    error!("{}", error);
                }
            }
            _ => {
                error!("{}", error);
            }
        }
    }

    fn print_diagnostic(&self, diagnostic: &Diagnostic) {
        let printer = DiagnosticPrinter::new(|source_location| {
            source_for_location(&self.config.root_dir, source_location).map(|source| source.text)
        });
        error!("{}", printer.diagnostic_to_string(diagnostic));
    }
}

async fn build_projects<TPerfLogger: PerfLogger + 'static>(
    config: Arc<Config>,
    perf_logger: Arc<TPerfLogger>,
    setup_event: &impl PerfLogEvent,
    compiler_state: &mut CompilerState,
) -> Result<()> {
    let mut graphql_asts = setup_event.time("parse_sources_time", || {
        GraphQLAsts::from_graphql_sources_map(
            &compiler_state.graphql_sources,
            &compiler_state.dirty_definitions,
        )
    })?;

    let build_results: Vec<_> = config
        .par_enabled_projects()
        .filter(|project_config| compiler_state.project_has_pending_changes(project_config.name))
        .map(|project_config| {
            build_project(
                &config,
                project_config,
                compiler_state,
                &graphql_asts,
                Arc::clone(&perf_logger),
            )
        })
        .collect();
    let mut results = Vec::new();
    let mut errors = Vec::new();
    for result in build_results {
        match result {
            Ok(result) => results.push(result),
            Err(error) => errors.push(error),
        }
    }

    if errors.is_empty() {
        let mut handles = Vec::new();
        for (project_name, schema, programs, artifacts) in results {
            let config = Arc::clone(&config);
            let perf_logger = Arc::clone(&perf_logger);
            let artifact_map = compiler_state
                .artifacts
                .get(&project_name)
                .cloned()
                .unwrap_or_else(|| Arc::new(ArtifactMapKind::Unconnected(Default::default())));
            let removed_definition_names = graphql_asts
                .remove(&project_name)
                .expect("Expect GraphQLAsts to exist.")
                .removed_definition_names;
            handles.push(task::spawn(async move {
                let project_config = &config.projects[&project_name];
                Ok((
                    project_name,
                    commit_project(
                        &config,
                        project_config,
                        perf_logger,
                        &schema,
                        programs,
                        artifacts,
                        artifact_map,
                        removed_definition_names,
                    )
                    .await?,
                ))
            }));
        }
        for commit_result in join_all(handles).await {
            match commit_result.unwrap() {
                Ok((project_name, next_artifact_map)) => {
                    let next_artifact_map = Arc::new(ArtifactMapKind::Mapping(next_artifact_map));
                    compiler_state
                        .artifacts
                        .insert(project_name, next_artifact_map);
                }
                Err(error) => {
                    errors.push(error);
                }
            }
        }
    };

    if errors.is_empty() {
        Ok(())
    } else {
        Err(Error::BuildProjectsErrors { errors })
    }
}
<|endoftext|>