<commit_before>// Lints
#![forbid(private_in_public)]
#![forbid(bare_trait_objects)]
#![deny(unused_must_use)]
#![deny(unused_assignments)]
#![deny(clippy::missing_safety_doc)]
#![allow(clippy::empty_loop)]
// no_std
#![no_std]
// Unstable features
#![feature(alloc_error_handler)]
#![feature(alloc_prelude)]
#![feature(allocator_api)]
#![feature(slice_ptr_get)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(llvm_asm)]
#![feature(const_fn)]
#![feature(integer_atomics)]
#![feature(panic_info_message)]
#![feature(trait_alias)]
#![feature(never_type)]

mod allocator;

// pub mod attachment;
// pub mod console;
pub mod ipc;
pub mod net;
pub mod process;
pub mod service;
pub mod syscall;

use core::alloc::Layout;
use core::panic::PanicInfo;

pub use d7abi;
pub use pinecone;
pub use x86_64::{self, PhysAddr, VirtAddr};

#[macro_use]
extern crate alloc;

extern "Rust" {
    fn main() -> u64;
}

#[no_mangle]
pub extern "C" fn _start() {
    let return_code = unsafe { main() };
    self::syscall::exit(return_code);
}

#[panic_handler]
#[no_mangle]
extern "C" fn panic(info: &PanicInfo) -> ! {
    use self::syscall::debug_print;

    let no_location = format!("(location unavailable)");
    let location = info
        .location()
        .map(|l| format!("file '{}', line {}", l.file(), l.line()))
        .unwrap_or(no_location);

    let no_args = format_args!("(message unavailable)");
    let message = format!("  {:?}", info.message().unwrap_or(&no_args));

    let _ = debug_print(&format!("Error: {}\n  {}", location, message));

    syscall::exit(1)
}

#[global_allocator]
static HEAP_ALLOCATOR: allocator::GlobAlloc =
    allocator::GlobAlloc::new(allocator::BlockAllocator::new());

#[alloc_error_handler]
fn out_of_memory(_: Layout) -> ! {
    unsafe {
        llvm_asm!("xchg bx, bx"::::"intel","volatile");
        llvm_asm!("cli"::::"intel","volatile");
        llvm_asm!("hlt"::::"intel","volatile");
    }
    loop {}
}

// Output macros
// TODO: print to stdout and not debug_print

#[macro_export]
macro_rules! println {
    ($($arg:tt)*) => ({
        $crate::syscall::debug_print(&format!("{}", &format_args!($($arg)*)));
    });
}

// #[macro_export]
// macro_rules! print {
//     ($($arg:tt)*) => ({
//         $crate::syscall::debug_print(&format!("{}", &format_args!($($arg)*)));
//     });
// }

// #[macro_export]
// macro_rules! println {
//     ($fmt:expr) => ($crate::print!(concat!($fmt, "\n")));
//     ($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*));
// }
<commit_msg>libd7: migrate to new asm! macro<commit_after>// Lints
#![forbid(private_in_public)]
#![forbid(bare_trait_objects)]
#![deny(unused_must_use)]
#![deny(unused_assignments)]
#![deny(clippy::missing_safety_doc)]
#![allow(clippy::empty_loop)]
// no_std
#![no_std]
// Unstable features
#![feature(alloc_error_handler)]
#![feature(alloc_prelude)]
#![feature(allocator_api)]
#![feature(slice_ptr_get)]
#![feature(nonnull_slice_from_raw_parts)]
#![feature(asm)]
#![feature(llvm_asm)]
#![feature(const_fn)]
#![feature(integer_atomics)]
#![feature(panic_info_message)]
#![feature(trait_alias)]
#![feature(never_type)]

mod allocator;

// pub mod attachment;
// pub mod console;
pub mod ipc;
pub mod net;
pub mod process;
pub mod service;
pub mod syscall;

use core::alloc::Layout;
use core::panic::PanicInfo;

pub use d7abi;
pub use pinecone;
pub use x86_64::{self, PhysAddr, VirtAddr};

#[macro_use]
extern crate alloc;

extern "Rust" {
    fn main() -> u64;
}

#[no_mangle]
pub extern "C" fn _start() {
    let return_code = unsafe { main() };
    self::syscall::exit(return_code);
}

#[panic_handler]
#[no_mangle]
extern "C" fn panic(info: &PanicInfo) -> ! {
    use self::syscall::debug_print;

    let no_location = format!("(location unavailable)");
    let location = info
        .location()
        .map(|l| format!("file '{}', line {}", l.file(), l.line()))
        .unwrap_or(no_location);

    let no_args = format_args!("(message unavailable)");
    let message = format!("  {:?}", info.message().unwrap_or(&no_args));

    let _ = debug_print(&format!("Error: {}\n  {}", location, message));

    syscall::exit(1)
}

#[global_allocator]
static HEAP_ALLOCATOR: allocator::GlobAlloc =
    allocator::GlobAlloc::new(allocator::BlockAllocator::new());

#[alloc_error_handler]
fn out_of_memory(_: Layout) -> ! {
    unsafe {
        asm!("xchg bx, bx");
        loop {
            asm!("cli; hlt");
        }
    }
}

// Output macros
// TODO: print to stdout and not debug_print

#[macro_export]
macro_rules! println {
    ($($arg:tt)*) => ({
        $crate::syscall::debug_print(&format!("{}", &format_args!($($arg)*)));
    });
}

// #[macro_export]
// macro_rules! print {
//     ($($arg:tt)*) => ({
//         $crate::syscall::debug_print(&format!("{}", &format_args!($($arg)*)));
//     });
// }

// #[macro_export]
// macro_rules! println {
//     ($fmt:expr) => ($crate::print!(concat!($fmt, "\n")));
//     ($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*));
// }
<|endoftext|>


<commit_before>// Copyright 2017 Serde Developers
//
// 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.

#![feature(lang_items, start)]
#![no_std]

extern crate libc;

#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
    0
}

#[lang = "eh_personality"]
#[no_mangle]
pub extern fn rust_eh_personality() {}

#[lang = "panic_fmt"]
#[no_mangle]
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
                               _file: &'static str,
                               _line: u32) -> ! {
    unsafe {
        libc::abort()
    }
}

//////////////////////////////////////////////////////////////////////////////

#[macro_use]
extern crate serde_derive;

#[derive(Serialize, Deserialize)]
struct Unit;

#[derive(Serialize, Deserialize)]
struct Newtype(u8);

#[derive(Serialize, Deserialize)]
struct Tuple(u8, u8);

#[derive(Serialize, Deserialize)]
struct Struct { f: u8 }

#[derive(Serialize, Deserialize)]
enum Enum {
    Unit,
    Newtype(u8),
    Tuple(u8, u8),
    Struct { f: u8 },
}
<commit_msg>Format no_std test code with rustfmt 0.4.1<commit_after>// Copyright 2017 Serde Developers
//
// 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.

#![feature(lang_items, start)]
#![no_std]

extern crate libc;

#[start]
fn start(_argc: isize, _argv: *const *const u8) -> isize {
    0
}

#[lang = "eh_personality"]
#[no_mangle]
pub extern "C" fn rust_eh_personality() {}

#[lang = "panic_fmt"]
#[no_mangle]
pub extern "C" fn rust_begin_panic(
    _msg: core::fmt::Arguments,
    _file: &'static str,
    _line: u32,
) -> ! {
    unsafe {
        libc::abort();
    }
}

//////////////////////////////////////////////////////////////////////////////

#[macro_use]
extern crate serde_derive;

#[derive(Serialize, Deserialize)]
struct Unit;

#[derive(Serialize, Deserialize)]
struct Newtype(u8);

#[derive(Serialize, Deserialize)]
struct Tuple(u8, u8);

#[derive(Serialize, Deserialize)]
struct Struct {
    f: u8,
}

#[derive(Serialize, Deserialize)]
enum Enum {
    Unit,
    Newtype(u8),
    Tuple(u8, u8),
    Struct { f: u8 },
}
<|endoftext|>


<commit_before>use helpers::*;
use helpers::values::*;

#[test]
fn list_() {
    assert_eval("(list)", "'()");
    assert_eval("(list (+ 0 1) 2 3)", "'(1 2 3)");
}

#[test]
fn length() {
    assert_eval("(length '())", "0");
    assert_eval("(length '(1 2 3))", "3");
    assert_eval("(length (list (+ 0 1)))", "1");
}

#[test]
fn length_bad_arity() {
    assert_eval_err("(length '() '())", bad_arity("length"));
}

#[test]
fn length_bad_arguments() {
    assert_eval_err("(length 1)", wrong_argument_type(integer(1)));
}

#[test]
fn pair_() {
    assert_eval("(pair? 1)", "#f");
    assert_eval("(pair? #t)", "#f");
    assert_eval("(pair? '())", "#f");
    assert_eval("(pair? (lambda (x) 0))", "#f");
    assert_eval("(pair? '(1 2 3))", "#t");
    assert_eval("(pair? '(1 2 . 3))", "#t");
}

#[test]
fn pair_bad_arity() {
    assert_eval_err("(pair?)", bad_arity("pair?"));
    assert_eval_err("(pair? 1 2)", bad_arity("pair?"));
}

#[test]
fn cons() {
    assert_eval("(cons 'a '())", "'(a)");
    assert_eval("(cons '(a) '(b c d))", "'((a) b c d)");
    assert_eval("(cons 1 '(b c))", "'(1 b c)");
    assert_eval("(cons 'a 3)", "'(a . 3)");
    assert_eval("(cons '(a b) 'c)", "'((a b) . c)");
}

#[test]
fn cons_bad_arity() {
    assert_eval_err("(cons)", bad_arity("cons"));
    assert_eval_err("(cons 1)", bad_arity("cons"));
    assert_eval_err("(cons 1 2 3)", bad_arity("cons"));
}

#[test]
fn car() {
    assert_eval("(car '(a b c))", "'a");
    assert_eval("(car '(1 . 2))", "1");
}

#[test]
fn car_bad_arity() {
    assert_eval_err("(car)", bad_arity("car"));
    assert_eval_err("(car '(a) '(b))", bad_arity("car"));
}

#[test]
fn car_wrong_argument_type() {
    assert_eval_err("(car 12)", wrong_argument_type(integer(12)));
    assert_eval_err("(car '())", wrong_argument_type(nil()));
}

#[test]
fn cdr() {
    assert_eval("(cdr '((a) b c d))", "'(b c d)");
    assert_eval("(cdr '(1 . 2))", "2");
}

#[test]
fn cdr_bad_arity() {
    assert_eval_err("(cdr)", bad_arity("cdr"));
    assert_eval_err("(cdr '(a) '(b))", bad_arity("cdr"));
}

#[test]
fn cdr_wrong_argument_type() {
    assert_eval_err("(cdr 12)", wrong_argument_type(integer(12)));
    assert_eval_err("(cdr '())", wrong_argument_type(nil()));
}

#[test]
fn null() {
    assert_eval("(null? '())", "#t");
    assert_eval("(null? 1)", "#f");
    assert_eval("(null? '(1 2 3))", "#f");
    assert_eval("(null? #t)", "#f");
}

#[test]
fn null_bad_arity() {
    assert_eval_err("(null?)", bad_arity("null?"));
    assert_eval_err("(null? '(a) '(b))", bad_arity("null?"));
}

#[test]
fn list_question_mark() {
    assert_eval("(list? '(a b c))", "#t");
    assert_eval("(list? '())", "#t");
    assert_eval("(list? '(a . b))", "#f");
    assert_eval("(list? 1)", "#f");
}

#[test]
fn list_question_mark_bad_arity() {
    assert_eval_err("(list?)", bad_arity("list?"));
    assert_eval_err("(list? '() '())", bad_arity("list?"));
}
<commit_msg>Moved most of the tests on lists to use the vm.<commit_after>use helpers::*;
use helpers::values::*;

#[test]
fn list_() {
    assert_eval_vm("(list)", "'()");
    assert_eval_vm("(list (+ 0 1) 2 3)", "'(1 2 3)");
}

#[test]
fn length() {
    assert_eval_vm("(length '())", "0");
    assert_eval_vm("(length '(1 2 3))", "3");
    assert_eval_vm("(length (list (+ 0 1)))", "1");
}

#[test]
fn length_bad_arity() {
    assert_eval_vm_err("(length '() '())", bad_arity("length"));
}

#[test]
fn length_bad_arguments() {
    assert_eval_vm_err("(length 1)", wrong_argument_type(integer(1)));
}

#[test]
fn pair_() {
    assert_eval_vm("(pair? 1)", "#f");
    assert_eval_vm("(pair? #t)", "#f");
    assert_eval_vm("(pair? '())", "#f");
    assert_eval("(pair? (lambda (x) 0))", "#f");
    assert_eval_vm("(pair? '(1 2 3))", "#t");
    assert_eval_vm("(pair? '(1 2 . 3))", "#t");
}

#[test]
fn pair_bad_arity() {
    assert_eval_vm_err("(pair?)", bad_arity("pair?"));
    assert_eval_vm_err("(pair? 1 2)", bad_arity("pair?"));
}

#[test]
fn cons() {
    assert_eval_vm("(cons 'a '())", "'(a)");
    assert_eval_vm("(cons '(a) '(b c d))", "'((a) b c d)");
    assert_eval_vm("(cons 1 '(b c))", "'(1 b c)");
    assert_eval_vm("(cons 'a 3)", "'(a . 3)");
    assert_eval_vm("(cons '(a b) 'c)", "'((a b) . c)");
}

#[test]
fn cons_bad_arity() {
    assert_eval_vm_err("(cons)", bad_arity("cons"));
    assert_eval_vm_err("(cons 1)", bad_arity("cons"));
    assert_eval_vm_err("(cons 1 2 3)", bad_arity("cons"));
}

#[test]
fn car() {
    assert_eval_vm("(car '(a b c))", "'a");
    assert_eval_vm("(car '(1 . 2))", "1");
}

#[test]
fn car_bad_arity() {
    assert_eval_vm_err("(car)", bad_arity("car"));
    assert_eval_vm_err("(car '(a) '(b))", bad_arity("car"));
}

#[test]
fn car_wrong_argument_type() {
    assert_eval_vm_err("(car 12)", wrong_argument_type(integer(12)));
    assert_eval_vm_err("(car '())", wrong_argument_type(nil()));
}

#[test]
fn cdr() {
    assert_eval_vm("(cdr '((a) b c d))", "'(b c d)");
    assert_eval_vm("(cdr '(1 . 2))", "2");
}

#[test]
fn cdr_bad_arity() {
    assert_eval_vm_err("(cdr)", bad_arity("cdr"));
    assert_eval_vm_err("(cdr '(a) '(b))", bad_arity("cdr"));
}

#[test]
fn cdr_wrong_argument_type() {
    assert_eval_vm_err("(cdr 12)", wrong_argument_type(integer(12)));
    assert_eval_vm_err("(cdr '())", wrong_argument_type(nil()));
}

#[test]
fn null() {
    assert_eval_vm("(null? '())", "#t");
    assert_eval_vm("(null? 1)", "#f");
    assert_eval_vm("(null? '(1 2 3))", "#f");
    assert_eval_vm("(null? #t)", "#f");
}

#[test]
fn null_bad_arity() {
    assert_eval_vm_err("(null?)", bad_arity("null?"));
    assert_eval_vm_err("(null? '(a) '(b))", bad_arity("null?"));
}

#[test]
fn list_question_mark() {
    assert_eval_vm("(list? '(a b c))", "#t");
    assert_eval_vm("(list? '())", "#t");
    assert_eval_vm("(list? '(a . b))", "#f");
    assert_eval_vm("(list? 1)", "#f");
}

#[test]
fn list_question_mark_bad_arity() {
    assert_eval_vm_err("(list?)", bad_arity("list?"));
    assert_eval_vm_err("(list? '() '())", bad_arity("list?"));
}
<|endoftext|>


<commit_before>// use std::slice;
use std::path::{Path, PathBuf};
use std::io;
use std::io::{Cursor, Read, Write};
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, Mutex, MutexGuard};
use std::cmp;

use rex::filesystem::Filesystem;

use super::bytes;

lazy_static! {
    pub static ref FILES: Mutex<HashMap<PathBuf, Arc<Mutex<Cursor<Vec<u8>>>>>> = Mutex::new(HashMap::new());
}

pub struct MockFile(Arc<Mutex<Cursor<Vec<u8>>>>);

impl MockFile {
    fn new(vec: Arc<Mutex<Cursor<Vec<u8>>>>) -> MockFile {
        MockFile(vec)
    }
}

impl Read for MockFile {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut vec = self.0.lock().unwrap();
        vec.read(buf)
    }
}

impl Write for MockFile {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let mut vec = self.0.lock().unwrap();
        vec.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        let mut vec = self.0.lock().unwrap();
        vec.flush()
    }
}

pub struct MockFilesystem;

impl Filesystem for MockFilesystem {
    type FSRead = MockFile;
    type FSWrite = MockFile;

    fn open<P: AsRef<Path>>(path: P) -> io::Result<Self::FSRead> {
        FILES.lock().unwrap().get(path.as_ref()).ok_or(io::Error::new(io::ErrorKind::NotFound, "File not found!")).map(|file|
            MockFile::new(file.clone())
        )
    }

    fn save<P: AsRef<Path>>(path: P) -> io::Result<Self::FSWrite> {
        let file = Arc::new(Mutex::new(Cursor::new(Vec::new())));
        if let Entry::Vacant(entry) = FILES.lock().unwrap().entry(path.as_ref().into()) {
            entry.insert(file.clone());
            Ok(MockFile::new(file))
        } else {
            Err(io::Error::new(io::ErrorKind::AlreadyExists, "File alredy exists!"))
        }
    }
}

impl MockFilesystem {
    pub fn reset() {
        FILES.lock().unwrap().clear();
    }

    pub fn get_inner<'a, P: AsRef<Path>>(path: P) -> Vec<u8> {
        // This function is very ugly, in general we would like to "unwrap" the file from the
        // mock filesystem. Sadly, there doesn't seem to be a better way.
        let f = FILES.lock().unwrap().remove(path.as_ref()).unwrap();
        let a = Arc::try_unwrap(f).unwrap();
        let m = a.lock().unwrap();
        let v = m.clone();
        v.into_inner()
    }

    pub fn put<'a, P: AsRef<Path>>(path: P, v: Vec<u8>) {
        FILES.lock().unwrap().insert(path.as_ref().into(), Arc::new(Mutex::new(Cursor::new(v))));
    }
}
<commit_msg>Basic support for file checking to pass component tests<commit_after>// use std::slice;
use std::path::{Path, PathBuf};
use std::io;
use std::io::{Cursor, Read, Write};
use std::collections::hash_map::{HashMap, Entry};
use std::sync::{Arc, Mutex, MutexGuard};
use std::cmp;

use rex::filesystem::Filesystem;

use super::bytes;

lazy_static! {
    pub static ref FILES: Mutex<HashMap<PathBuf, Arc<Mutex<Cursor<Vec<u8>>>>>> = Mutex::new(HashMap::new());
}

pub struct MockFile(Arc<Mutex<Cursor<Vec<u8>>>>);

impl MockFile {
    fn new(vec: Arc<Mutex<Cursor<Vec<u8>>>>) -> MockFile {
        MockFile(vec)
    }
}

impl Read for MockFile {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let mut vec = self.0.lock().unwrap();
        vec.read(buf)
    }
}

impl Write for MockFile {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let mut vec = self.0.lock().unwrap();
        vec.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        let mut vec = self.0.lock().unwrap();
        vec.flush()
    }
}

pub struct MockFilesystem;

impl Filesystem for MockFilesystem {
    type FSRead = MockFile;
    type FSWrite = MockFile;

    fn make_absolute<P: AsRef<Path>>(p: P) -> io::Result<PathBuf> {
        Ok(p.as_ref().into())
    }

    fn open<P: AsRef<Path>>(path: P) -> io::Result<Self::FSRead> {
        FILES.lock().unwrap().get(path.as_ref()).ok_or(io::Error::new(io::ErrorKind::NotFound, "File not found!")).map(|file|
            MockFile::new(file.clone())
        )
    }

    fn can_open<P: AsRef<Path>>(p: P) -> io::Result<()> {
        Ok(())
    }

    fn save<P: AsRef<Path>>(path: P) -> io::Result<Self::FSWrite> {
        let file = Arc::new(Mutex::new(Cursor::new(Vec::new())));
        if let Entry::Vacant(entry) = FILES.lock().unwrap().entry(path.as_ref().into()) {
            entry.insert(file.clone());
            Ok(MockFile::new(file))
        } else {
            Err(io::Error::new(io::ErrorKind::AlreadyExists, "File alredy exists!"))
        }
    }

    fn can_save<P: AsRef<Path>>(p: P) -> io::Result<()> {
        Ok(())
    }
}

impl MockFilesystem {
    pub fn reset() {
        FILES.lock().unwrap().clear();
    }

    pub fn get_inner<'a, P: AsRef<Path>>(path: P) -> Vec<u8> {
        // This function is very ugly, in general we would like to "unwrap" the file from the
        // mock filesystem. Sadly, there doesn't seem to be a better way.
        let f = FILES.lock().unwrap().remove(path.as_ref()).unwrap();
        let a = Arc::try_unwrap(f).unwrap();
        let m = a.lock().unwrap();
        let v = m.clone();
        v.into_inner()
    }

    pub fn put<'a, P: AsRef<Path>>(path: P, v: Vec<u8>) {
        FILES.lock().unwrap().insert(path.as_ref().into(), Arc::new(Mutex::new(Cursor::new(v))));
    }
}
<|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 fnv::{FnvHashMap, FnvHashSet};

use graphql_ir::*;
use interner::StringKey;
use std::collections::hash_map::Entry;
use std::fmt;

struct Node {
    ir: Option<ExecutableDefinition>,
    parents: Vec<StringKey>,
    children: Vec<StringKey>,
}

impl fmt::Debug for Node {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_fmt(format_args!(
            "parents: {:?} / children: {:?}",
            self.parents, self.children
        ))
    }
}

pub fn get_reachable_ir(
    definitions: Vec<ExecutableDefinition>,
    base_definition_names: FnvHashSet<StringKey>,
    reachable_names: FnvHashSet<StringKey>,
) -> Vec<ExecutableDefinition> {
    if reachable_names.is_empty() {
        return vec![];
    }

    let trees = build_dependency_trees(definitions);

    let mut visited = FnvHashSet::default();
    let mut filtered_definitions = FnvHashMap::default();

    for key in reachable_names.into_iter() {
        if trees.contains_key(&key) {
            add_related_nodes(
                &mut visited,
                &mut filtered_definitions,
                &trees,
                &base_definition_names,
                key,
            );
        }
    }

    filtered_definitions
        .drain()
        .map(|(_, definition)| definition)
        .collect()
}

// Build a set of dependency trees that nodes are "doubly linked"
fn build_dependency_trees(definitions: Vec<ExecutableDefinition>) -> FnvHashMap<StringKey, Node> {
    let mut trees = FnvHashMap::with_capacity_and_hasher(definitions.len(), Default::default());

    for definition in definitions.into_iter() {
        let name = match &definition {
            ExecutableDefinition::Operation(operation) => operation.name.item,
            ExecutableDefinition::Fragment(fragment) => fragment.name.item,
        };

        // Visit the selections of the IR to build it's `children`
        let mut children = vec![];
        let selections = match &definition {
            ExecutableDefinition::Operation(operation) => &operation.selections,
            ExecutableDefinition::Fragment(fragment) => &fragment.selections,
        };
        visit_selections(&mut trees, &selections, name, &mut children);

        // Insert or update the representation of the IR in the dependency tree
        match trees.entry(name) {
            // Add a new node for current IR to the dependency tree
            Entry::Vacant(entry) => {
                entry.insert(Node {
                    ir: Some(definition),
                    parents: vec![],
                    children,
                });
            }

            // The node is already created when visiting selections of the IR, but it's `ir` and `children` haven't been set
            Entry::Occupied(mut entry) => {
                let node = entry.get_mut();
                if let Some(def) = &node.ir {
                    panic!(
                        "Duplicate definition: had {:?} and found another {:?}.",
                        def, node.ir
                    );
                }
                node.ir = Some(definition);
                node.children = children;
            }
        }
    }
    trees
}

// Visit the selections of current IR, set the `children` for the node representing the IR,
// and the `parents` for nodes representing the children IR
fn visit_selections(
    trees: &mut FnvHashMap<StringKey, Node>,
    selections: &[Selection],
    parent_name: StringKey,
    children: &mut Vec<StringKey>,
) {
    for selection in selections {
        match selection {
            Selection::FragmentSpread(node) => {
                let key = node.fragment.item;
                match trees.get_mut(&key) {
                    None => {
                        trees.insert(
                            key,
                            Node {
                                ir: None,
                                parents: vec![parent_name],
                                children: vec![],
                            },
                        );
                    }
                    Some(node) => {
                        node.parents.push(parent_name);
                    }
                }
                children.push(key);
            }
            Selection::LinkedField(node) => {
                visit_selections(trees, &node.selections, parent_name, children);
            }
            Selection::InlineFragment(node) => {
                visit_selections(trees, &node.selections, parent_name, children);
            }
            Selection::ScalarField(_) => {}
            Selection::Condition(node) => {
                visit_selections(trees, &node.selections, parent_name, children);
            }
        }
    }
}

// From `key` of changed definition, recusively traverse up the depenency tree, and add all related nodes (ancestors
// of changned definitions which are not from base definitions, and all of their desendants) into the `result`
fn add_related_nodes(
    visited: &mut FnvHashSet<StringKey>,
    result: &mut FnvHashMap<StringKey, ExecutableDefinition>,
    trees: &FnvHashMap<StringKey, Node>,
    base_definition_names: &FnvHashSet<StringKey>,
    key: StringKey,
) {
    if !visited.insert(key) {
        return;
    }

    let parents = match trees.get(&key) {
        None => {
            panic!("Fragment {:?} not found in IR.", key);
        }
        Some(node) => node.parents.clone(),
    };
    if parents.is_empty() {
        if !base_definition_names.contains(&key) {
            add_descendants(result, trees, key);
        }
    } else {
        for parent in parents.into_iter() {
            add_related_nodes(visited, result, trees, base_definition_names, parent);
        }
    }
}

// Recursively add all descendants of current node into the `result`
fn add_descendants(
    result: &mut FnvHashMap<StringKey, ExecutableDefinition>,
    trees: &FnvHashMap<StringKey, Node>,
    key: StringKey,
) {
    if result.contains_key(&key) {
        return;
    }
    match trees.get(&key) {
        Some(Node {
            ir: Some(def),
            children,
            ..
        }) => {
            result.insert(key, def.clone());
            for child in children {
                add_descendants(result, trees, *child);
            }
        }
        _ => {
            panic!("Fragment {:?} not found in IR.", key);
        }
    }
}
<commit_msg>avoid clone() in dependency-analyzer<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 fnv::{FnvHashMap, FnvHashSet};

use graphql_ir::*;
use interner::StringKey;
use std::collections::hash_map::Entry;
use std::fmt;

struct Node {
    ir: Option<ExecutableDefinition>,
    parents: Vec<StringKey>,
    children: Vec<StringKey>,
}

impl fmt::Debug for Node {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_fmt(format_args!(
            "parents: {:?} / children: {:?}",
            self.parents, self.children
        ))
    }
}

pub fn get_reachable_ir(
    definitions: Vec<ExecutableDefinition>,
    base_definition_names: FnvHashSet<StringKey>,
    reachable_names: FnvHashSet<StringKey>,
) -> Vec<ExecutableDefinition> {
    if reachable_names.is_empty() {
        return vec![];
    }

    let trees = build_dependency_trees(definitions);

    let mut visited = FnvHashSet::default();
    let mut filtered_definitions = FnvHashMap::default();

    for key in reachable_names.into_iter() {
        if trees.contains_key(&key) {
            add_related_nodes(
                &mut visited,
                &mut filtered_definitions,
                &trees,
                &base_definition_names,
                key,
            );
        }
    }

    filtered_definitions
        .drain()
        .map(|(_, definition)| definition)
        .collect()
}

// Build a set of dependency trees that nodes are "doubly linked"
fn build_dependency_trees(definitions: Vec<ExecutableDefinition>) -> FnvHashMap<StringKey, Node> {
    let mut trees = FnvHashMap::with_capacity_and_hasher(definitions.len(), Default::default());

    for definition in definitions.into_iter() {
        let name = match &definition {
            ExecutableDefinition::Operation(operation) => operation.name.item,
            ExecutableDefinition::Fragment(fragment) => fragment.name.item,
        };

        // Visit the selections of the IR to build it's `children`
        let mut children = vec![];
        let selections = match &definition {
            ExecutableDefinition::Operation(operation) => &operation.selections,
            ExecutableDefinition::Fragment(fragment) => &fragment.selections,
        };
        visit_selections(&mut trees, &selections, name, &mut children);

        // Insert or update the representation of the IR in the dependency tree
        match trees.entry(name) {
            // Add a new node for current IR to the dependency tree
            Entry::Vacant(entry) => {
                entry.insert(Node {
                    ir: Some(definition),
                    parents: vec![],
                    children,
                });
            }

            // The node is already created when visiting selections of the IR, but it's `ir` and `children` haven't been set
            Entry::Occupied(mut entry) => {
                let node = entry.get_mut();
                if let Some(def) = &node.ir {
                    panic!(
                        "Duplicate definition: had {:?} and found another {:?}.",
                        def, node.ir
                    );
                }
                node.ir = Some(definition);
                node.children = children;
            }
        }
    }
    trees
}

// Visit the selections of current IR, set the `children` for the node representing the IR,
// and the `parents` for nodes representing the children IR
fn visit_selections(
    trees: &mut FnvHashMap<StringKey, Node>,
    selections: &[Selection],
    parent_name: StringKey,
    children: &mut Vec<StringKey>,
) {
    for selection in selections {
        match selection {
            Selection::FragmentSpread(node) => {
                let key = node.fragment.item;
                match trees.get_mut(&key) {
                    None => {
                        trees.insert(
                            key,
                            Node {
                                ir: None,
                                parents: vec![parent_name],
                                children: vec![],
                            },
                        );
                    }
                    Some(node) => {
                        node.parents.push(parent_name);
                    }
                }
                children.push(key);
            }
            Selection::LinkedField(node) => {
                visit_selections(trees, &node.selections, parent_name, children);
            }
            Selection::InlineFragment(node) => {
                visit_selections(trees, &node.selections, parent_name, children);
            }
            Selection::ScalarField(_) => {}
            Selection::Condition(node) => {
                visit_selections(trees, &node.selections, parent_name, children);
            }
        }
    }
}

// From `key` of changed definition, recusively traverse up the depenency tree, and add all related nodes (ancestors
// of changned definitions which are not from base definitions, and all of their desendants) into the `result`
fn add_related_nodes(
    visited: &mut FnvHashSet<StringKey>,
    result: &mut FnvHashMap<StringKey, ExecutableDefinition>,
    trees: &FnvHashMap<StringKey, Node>,
    base_definition_names: &FnvHashSet<StringKey>,
    key: StringKey,
) {
    if !visited.insert(key) {
        return;
    }

    let parents = match trees.get(&key) {
        None => {
            panic!("Fragment {:?} not found in IR.", key);
        }
        Some(node) => &node.parents,
    };
    if parents.is_empty() {
        if !base_definition_names.contains(&key) {
            add_descendants(result, trees, key);
        }
    } else {
        for parent in parents {
            add_related_nodes(visited, result, trees, base_definition_names, *parent);
        }
    }
}

// Recursively add all descendants of current node into the `result`
fn add_descendants(
    result: &mut FnvHashMap<StringKey, ExecutableDefinition>,
    trees: &FnvHashMap<StringKey, Node>,
    key: StringKey,
) {
    if result.contains_key(&key) {
        return;
    }
    match trees.get(&key) {
        Some(Node {
            ir: Some(def),
            children,
            ..
        }) => {
            result.insert(key, def.clone());
            for child in children {
                add_descendants(result, trees, *child);
            }
        }
        _ => {
            panic!("Fragment {:?} not found in IR.", key);
        }
    }
}
<|endoftext|>


<commit_before>// This is a hand-written binding to the very minimal part of libxml2 that we need.

#![allow(non_snake_case, non_camel_case_types)]
#![cfg_attr(rustfmt, rustfmt_skip)]

use glib_sys::gpointer;
use libc;

pub const XML_CHAR_ENCODING_NONE: libc::c_int = 0;

pub const XML_INTERNAL_GENERAL_ENTITY: libc::c_int = 1;

pub const XML_PARSE_NONET:     libc::c_int = 1 << 11;
pub const XML_PARSE_HUGE:      libc::c_int = 1 << 19;
pub const XML_PARSE_BIG_LINES: libc::c_int = 1 << 22;

pub type xmlDocPtr = gpointer;

pub type xmlEntityPtr = gpointer;

pub type UnusedFn = Option<unsafe extern "C" fn()>;

#[cfg_attr(rustfmt, rustfmt_skip)]
#[repr(C)]
pub struct xmlSAXHandler {
    pub internalSubset:    UnusedFn,
    pub isStandalone:      UnusedFn,
    pub hasInternalSubset: UnusedFn,
    pub hasExternalSubset: UnusedFn,
    pub resolveEntity:     UnusedFn,

    pub getEntity: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        name: *const libc::c_char,
    ) -> xmlEntityPtr>,

    pub entityDecl: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        name: *const libc::c_char,
        type_: libc::c_int,
        public_id: *const libc::c_char,
        system_id: *const libc::c_char,
        content: *const libc::c_char,
    )>,

    pub notationDecl:  UnusedFn,
    pub attributeDecl: UnusedFn,
    pub elementDecl:   UnusedFn,

    pub unparsedEntityDecl: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        name: *const libc::c_char,
        public_id: *const libc::c_char,
        system_id: *const libc::c_char,
        notation_name: *const libc::c_char,
    )>,

    pub setDocumentLocator: UnusedFn,
    pub startDocument:      UnusedFn,
    pub endDocument:        UnusedFn,

    pub startElement: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        name: *const libc::c_char,
        atts: *const *const libc::c_char,
    )>,

    pub endElement: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        name: *const libc::c_char,
    )>,

    pub reference: UnusedFn,

    pub characters: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        ch: *const libc::c_char,
        len: libc::c_int,
    )>,

    pub ignorableWhitespace: UnusedFn,

    pub processingInstruction: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        target: *const libc::c_char,
        data: *const libc::c_char,
    )>,

    pub comment:    UnusedFn,
    pub warning:    UnusedFn,

    pub error:      UnusedFn,

    pub fatalError: UnusedFn,

    pub getParameterEntity: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        name: *const libc::c_char,
    ) -> xmlEntityPtr>,

    pub cdataBlock: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        value: *const libc::c_char,
        len: libc::c_int,
    )>,

    pub externalSubset: UnusedFn,

    pub initialized: libc::c_uint,

    pub _private: gpointer,

    pub startElementNs: UnusedFn,
    pub endElementNs:   UnusedFn,

    pub serror: Option<unsafe extern "C" fn(user_data: *mut libc::c_void, error: xmlErrorPtr)>,
}

pub type xmlSAXHandlerPtr = *mut xmlSAXHandler;

// The original struct _xmlParserCtxt in libxml2 has a *ton* of
// fields; mostly are implementation details.  We only require access
// to fields up to replaceEntities, so we'll represent up to that
// field, and ignore subsequent ones.  This struct is used just to
// cast the xmlParserCtxtPtr that we get out of libxml2 into a
// Rust-visible structure; we don't need a complete representation of the
// original struct.
#[repr(C)]
pub struct xmlParserCtxt {
    pub sax: gpointer,
    pub userData: gpointer,
    pub myDoc: xmlDocPtr,
    pub wellFormed: libc::c_int,
    pub replaceEntities: libc::c_int,
    // ... libxml2 has more fields here; we don't use them
}

pub type xmlParserCtxtPtr = *mut xmlParserCtxt;

#[repr(C)]
pub struct xmlError {
    pub domain: libc::c_int,
    pub code: libc::c_int,
    pub message: *const libc::c_char,
    pub level: libc::c_int,
    pub file: *const libc::c_char,
    pub line: libc::c_int,
    pub str1: *const libc::c_char,
    pub str2: *const libc::c_char,
    pub str3: *const libc::c_char,
    pub int1: libc::c_int,
    pub int2: libc::c_int,
    pub ctxt: gpointer,
    pub node: gpointer,
}

pub type xmlErrorPtr = *mut xmlError;

pub type xmlInputReadCallback = Option<unsafe extern "C" fn(
    context: *mut libc::c_void,
    buffer: *mut libc::c_char,
    len: libc::c_int,
) -> libc::c_int>;

pub type xmlInputCloseCallback = Option<unsafe extern "C" fn(
    context: *mut libc::c_void,
) -> libc::c_int>;

pub type xmlCharEncoding = libc::c_int;

extern "C" {
    pub fn xmlInitParser();

    pub fn xmlCreateIOParserCtxt(
        sax: xmlSAXHandlerPtr,
        user_data: *mut libc::c_void,
        ioread: xmlInputReadCallback,
        ioclose: xmlInputCloseCallback,
        ioctx: *mut libc::c_void,
        enc: xmlCharEncoding,
    ) -> xmlParserCtxtPtr;

    pub fn xmlStopParser(ctxt: xmlParserCtxtPtr);

    pub fn xmlParseDocument(ctxt: xmlParserCtxtPtr) -> libc::c_int;

    pub fn xmlFreeDoc(doc: xmlDocPtr);

    pub fn xmlFreeParserCtxt(ctxt: xmlParserCtxtPtr);

    pub fn xmlCtxtGetLastError(ctxt: *mut libc::c_void) -> xmlErrorPtr;

    pub fn xmlCtxtUseOptions(
        ctxt: xmlParserCtxtPtr,
        options: libc::c_int,
    ) -> libc::c_int;

    pub fn xmlNewEntity(
        doc: xmlDocPtr,
        name: *const libc::c_char,
        type_: libc::c_int,
        external_id: *const libc::c_char,
        system_id: *const libc::c_char,
        content: *const libc::c_char,
    ) -> xmlEntityPtr;
}
<commit_msg>xmlSAXHandler: add prototypes for the startElementNs and endElementNs<commit_after>// This is a hand-written binding to the very minimal part of libxml2 that we need.

#![allow(non_snake_case, non_camel_case_types)]
#![cfg_attr(rustfmt, rustfmt_skip)]

use glib_sys::gpointer;
use libc;

pub const XML_CHAR_ENCODING_NONE: libc::c_int = 0;

pub const XML_INTERNAL_GENERAL_ENTITY: libc::c_int = 1;

pub const XML_PARSE_NONET:     libc::c_int = 1 << 11;
pub const XML_PARSE_HUGE:      libc::c_int = 1 << 19;
pub const XML_PARSE_BIG_LINES: libc::c_int = 1 << 22;

pub const XML_SAX2_MAGIC: libc::c_uint = 0xDEEDBEAF;

pub type xmlDocPtr = gpointer;

pub type xmlEntityPtr = gpointer;

pub type UnusedFn = Option<unsafe extern "C" fn()>;

#[cfg_attr(rustfmt, rustfmt_skip)]
#[repr(C)]
pub struct xmlSAXHandler {
    pub internalSubset:    UnusedFn,
    pub isStandalone:      UnusedFn,
    pub hasInternalSubset: UnusedFn,
    pub hasExternalSubset: UnusedFn,
    pub resolveEntity:     UnusedFn,

    pub getEntity: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        name: *const libc::c_char,
    ) -> xmlEntityPtr>,

    pub entityDecl: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        name: *const libc::c_char,
        type_: libc::c_int,
        public_id: *const libc::c_char,
        system_id: *const libc::c_char,
        content: *const libc::c_char,
    )>,

    pub notationDecl:  UnusedFn,
    pub attributeDecl: UnusedFn,
    pub elementDecl:   UnusedFn,

    pub unparsedEntityDecl: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        name: *const libc::c_char,
        public_id: *const libc::c_char,
        system_id: *const libc::c_char,
        notation_name: *const libc::c_char,
    )>,

    pub setDocumentLocator: UnusedFn,
    pub startDocument:      UnusedFn,
    pub endDocument:        UnusedFn,

    pub startElement: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        name: *const libc::c_char,
        atts: *const *const libc::c_char,
    )>,

    pub endElement: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        name: *const libc::c_char,
    )>,

    pub reference: UnusedFn,

    pub characters: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        ch: *const libc::c_char,
        len: libc::c_int,
    )>,

    pub ignorableWhitespace: UnusedFn,

    pub processingInstruction: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        target: *const libc::c_char,
        data: *const libc::c_char,
    )>,

    pub comment:    UnusedFn,
    pub warning:    UnusedFn,

    pub error:      UnusedFn,

    pub fatalError: UnusedFn,

    pub getParameterEntity: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        name: *const libc::c_char,
    ) -> xmlEntityPtr>,

    pub cdataBlock: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        value: *const libc::c_char,
        len: libc::c_int,
    )>,

    pub externalSubset: UnusedFn,

    pub initialized: libc::c_uint,

    pub _private: gpointer,

    pub startElementNs: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        localname: *mut libc::c_char,
	prefix: *mut libc::c_char,
	uri: *mut libc::c_char,
	nb_namespaces: libc::c_int,
	namespaces: *mut *mut libc::c_char,
	nb_attributes: libc::c_int,
	nb_defaulted: libc::c_int,
	attributes: *mut *mut libc::c_char,
    )>,

    pub endElementNs: Option<unsafe extern "C" fn(
        ctx: *mut libc::c_void,
        localname: *mut libc::c_char,
	prefix: *mut libc::c_char,
	uri: *mut libc::c_char,
    )>,

    pub serror: Option<unsafe extern "C" fn(user_data: *mut libc::c_void, error: xmlErrorPtr)>,
}

pub type xmlSAXHandlerPtr = *mut xmlSAXHandler;

// The original struct _xmlParserCtxt in libxml2 has a *ton* of
// fields; mostly are implementation details.  We only require access
// to fields up to replaceEntities, so we'll represent up to that
// field, and ignore subsequent ones.  This struct is used just to
// cast the xmlParserCtxtPtr that we get out of libxml2 into a
// Rust-visible structure; we don't need a complete representation of the
// original struct.
#[repr(C)]
pub struct xmlParserCtxt {
    pub sax: gpointer,
    pub userData: gpointer,
    pub myDoc: xmlDocPtr,
    pub wellFormed: libc::c_int,
    pub replaceEntities: libc::c_int,
    // ... libxml2 has more fields here; we don't use them
}

pub type xmlParserCtxtPtr = *mut xmlParserCtxt;

#[repr(C)]
pub struct xmlError {
    pub domain: libc::c_int,
    pub code: libc::c_int,
    pub message: *const libc::c_char,
    pub level: libc::c_int,
    pub file: *const libc::c_char,
    pub line: libc::c_int,
    pub str1: *const libc::c_char,
    pub str2: *const libc::c_char,
    pub str3: *const libc::c_char,
    pub int1: libc::c_int,
    pub int2: libc::c_int,
    pub ctxt: gpointer,
    pub node: gpointer,
}

pub type xmlErrorPtr = *mut xmlError;

pub type xmlInputReadCallback = Option<unsafe extern "C" fn(
    context: *mut libc::c_void,
    buffer: *mut libc::c_char,
    len: libc::c_int,
) -> libc::c_int>;

pub type xmlInputCloseCallback = Option<unsafe extern "C" fn(
    context: *mut libc::c_void,
) -> libc::c_int>;

pub type xmlCharEncoding = libc::c_int;

extern "C" {
    pub fn xmlInitParser();

    pub fn xmlCreateIOParserCtxt(
        sax: xmlSAXHandlerPtr,
        user_data: *mut libc::c_void,
        ioread: xmlInputReadCallback,
        ioclose: xmlInputCloseCallback,
        ioctx: *mut libc::c_void,
        enc: xmlCharEncoding,
    ) -> xmlParserCtxtPtr;

    pub fn xmlStopParser(ctxt: xmlParserCtxtPtr);

    pub fn xmlParseDocument(ctxt: xmlParserCtxtPtr) -> libc::c_int;

    pub fn xmlFreeDoc(doc: xmlDocPtr);

    pub fn xmlFreeParserCtxt(ctxt: xmlParserCtxtPtr);

    pub fn xmlCtxtGetLastError(ctxt: *mut libc::c_void) -> xmlErrorPtr;

    pub fn xmlCtxtUseOptions(
        ctxt: xmlParserCtxtPtr,
        options: libc::c_int,
    ) -> libc::c_int;

    pub fn xmlNewEntity(
        doc: xmlDocPtr,
        name: *const libc::c_char,
        type_: libc::c_int,
        external_id: *const libc::c_char,
        system_id: *const libc::c_char,
        content: *const libc::c_char,
    ) -> xmlEntityPtr;
}
<|endoftext|>


<commit_before>#[cfg(feature = "readline")]
extern crate readline;
extern crate lambed;

#[cfg(feature = "readline")]
use std::ffi::CString;

#[cfg(feature = "readline")]
fn main() {
    let prompt = CString::new("> ").unwrap();
    while let Ok(s) = readline::readline(&prompt) {
        let bytes = s.to_bytes();
        let string = String::from_utf8_lossy(bytes).into_owned().to_string();
        match lambed::parser::parse_string(&string) {
            Err(err) => println!("{:?}", err),
            Ok((term, _)) => {
                println!("{:?}", term);
                let result = lambed::eval::eval(term);
                println!("{:?}", result)
            }
        }
    }
}
<commit_msg>make repl work without readline<commit_after>#[cfg(feature = "readline")]
extern crate readline;
extern crate lambed;

#[cfg(feature = "readline")]
fn interact<F: Fn(&String)>(f: F) {
    use std::ffi::CString;
    let prompt = CString::new("> ").unwrap();
    while let Ok(s) = readline::readline(&prompt) {
        let bytes = s.to_bytes();
        let string = String::from_utf8_lossy(bytes).into_owned().to_string();
        f(&string)
    }
}

#[cfg(not(feature = "readline"))]
fn interact<F: Fn(&String)>(f: F) {
    use std::io;
    let mut stdin = io::stdin();
    let mut string = String::new();
    while let Ok(_) = stdin.read_line(&mut string) {
        f(&string);
        string.clear()
    }
}

fn main() {
    interact(|string| {
        match lambed::parser::parse_string(string) {
            Err(err) => println!("{:?}", err),
            Ok((term, _)) => {
                println!("{:?}", term);
                let result = lambed::eval::eval(term);
                println!("{:?}", result)
            }
        }
    })
}
<|endoftext|>


<commit_before>extern crate mdbook;
#[macro_use]
extern crate clap;
extern crate log;
extern crate env_logger;
extern crate open;

// Dependencies for the Watch feature
#[cfg(feature = "watch")]
extern crate notify;
#[cfg(feature = "watch")]
extern crate time;
#[cfg(feature = "watch")]
extern crate crossbeam;

// Dependencies for the Serve feature
#[cfg(feature = "serve")]
extern crate iron;
#[cfg(feature = "serve")]
extern crate staticfile;
#[cfg(feature = "serve")]
extern crate ws;

use std::env;
use std::error::Error;
use std::ffi::OsStr;
use std::io::{self, Write};
use std::path::{Path, PathBuf};

use clap::{App, ArgMatches, SubCommand, AppSettings};

// Uses for the Watch feature
#[cfg(feature = "watch")]
use notify::Watcher;
#[cfg(feature = "watch")]
use std::time::Duration;
#[cfg(feature = "watch")]
use std::sync::mpsc::channel;

use mdbook::MDBook;

const NAME: &'static str = "mdbook";

fn main() {
    env_logger::init().unwrap();

    // Create a list of valid arguments and sub-commands
    let matches = App::new(NAME)
                    .about("Create a book in form of a static website from markdown files")
                    .author("Mathieu David <mathieudavid@mathieudavid.org>")
                    // Get the version from our Cargo.toml using clap's crate_version!() macro
                    .version(&*format!("v{}", crate_version!()))
                    .setting(AppSettings::SubcommandRequired)
                    .after_help("For more information about a specific command, try `mdbook <command> --help`\nSource code for mdbook available at: https://github.com/azerupi/mdBook")
                    .subcommand(SubCommand::with_name("init")
                        .about("Create boilerplate structure and files in the directory")
                        // the {n} denotes a newline which will properly aligned in all help messages
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'")
                        .arg_from_usage("--theme 'Copies the default theme into your source folder'")
                        .arg_from_usage("--force 'skip confirmation prompts'"))
                    .subcommand(SubCommand::with_name("build")
                        .about("Build the book from the markdown files")
                        .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
                        .arg_from_usage("-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'")
                        .arg_from_usage("--no-create 'Will not create non-existent files linked from SUMMARY.md'")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'"))
                    .subcommand(SubCommand::with_name("watch")
                        .about("Watch the files for changes")
                        .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
                        .arg_from_usage("-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'"))
                    .subcommand(SubCommand::with_name("serve")
                        .about("Serve the book at http://localhost:3000. Rebuild and reload on change.")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'")
                        .arg_from_usage("-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'")
                        .arg_from_usage("-p, --port=[port] 'Use another port{n}(Defaults to 3000)'")
                        .arg_from_usage("-w, --websocket-port=[ws-port] 'Use another port for the websocket connection (livereload){n}(Defaults to 3001)'")
                        .arg_from_usage("-i, --interface=[interface] 'Interface to listen on{n}(Defaults to localhost)'")
                        .arg_from_usage("-a, --address=[address] 'Address that the browser can reach the websocket server from{n}(Defaults to the interface address)'")
                        .arg_from_usage("-o, --open 'Open the book server in a web browser'"))
                    .subcommand(SubCommand::with_name("test")
                        .about("Test that code samples compile"))
                    .get_matches();

    // Check which subcomamnd the user ran...
    let res = match matches.subcommand() {
        ("init", Some(sub_matches)) => init(sub_matches),
        ("build", Some(sub_matches)) => build(sub_matches),
        #[cfg(feature = "watch")]
        ("watch", Some(sub_matches)) => watch(sub_matches),
        #[cfg(feature = "serve")]
        ("serve", Some(sub_matches)) => serve(sub_matches),
        ("test", Some(sub_matches)) => test(sub_matches),
        (_, _) => unreachable!(),
    };

    if let Err(e) = res {
        writeln!(&mut io::stderr(), "An error occured:\n{}", e).ok();
        ::std::process::exit(101);
    }
}

// Simple function that user comfirmation
fn confirm() -> bool {
    io::stdout().flush().unwrap();
    let mut s = String::new();
    io::stdin().read_line(&mut s).ok();
    match &*s.trim() {
        "Y" | "y" | "yes" | "Yes" => true,
        _ => false,
    }
}

// Init command implementation
fn init(args: &ArgMatches) -> Result<(), Box<Error>> {

    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir);

    // Call the function that does the initialization
    book.init()?;

    // If flag `--theme` is present, copy theme to src
    if args.is_present("theme") {

        // Skip this if `--force` is present
        if !args.is_present("force") {
            // Print warning
            print!("\nCopying the default theme to {:?}", book.get_source());
            println!("could potentially overwrite files already present in that directory.");
            print!("\nAre you sure you want to continue? (y/n) ");

            // Read answer from user and exit if it's not 'yes'
            if !confirm() {
                println!("\nSkipping...\n");
                println!("All done, no errors...");
                ::std::process::exit(0);
            }
        }

        // Call the function that copies the theme
        book.copy_theme()?;
        println!("\nTheme copied.");

    }

    // Because of `src/book/mdbook.rs#L37-L39`, `dest` will always start with `root`
    let is_dest_inside_root = book.get_destination()
                                  .map(|p| p.starts_with(book.get_root()))
                                  .unwrap_or(false);

    if !args.is_present("force") && is_dest_inside_root {
        println!("\nDo you want a .gitignore to be created? (y/n)");

        if confirm() {
            book.create_gitignore();
            println!("\n.gitignore created.");
        }
    }

    println!("\nAll done, no errors...");

    Ok(())
}

// Build command implementation
fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let book = MDBook::new(&book_dir).read_config()?;

    let mut book = match args.value_of("dest-dir") {
        Some(dest_dir) => book.with_destination(Path::new(dest_dir)),
        None => book,
    };

    if args.is_present("no-create") {
        book.create_missing = false;
    }

    book.build()?;

    if let Some(d) = book.get_destination() {
        if args.is_present("open") {
            open(d.join("index.html"));
        }
    }

    Ok(())
}

// Watch command implementation
#[cfg(feature = "watch")]
fn watch(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let book = MDBook::new(&book_dir).read_config()?;

    let mut book = match args.value_of("dest-dir") {
        Some(dest_dir) => book.with_destination(Path::new(dest_dir)),
        None => book,
    };

    if args.is_present("open") {
        book.build()?;
        if let Some(d) = book.get_destination() {
            open(d.join("index.html"));
        }
    }

    trigger_on_change(&mut book, |path, book| {
        println!("File changed: {:?}\nBuilding book...\n", path);
        if let Err(e) = book.build() {
            println!("Error while building: {:?}", e);
        }
        println!("");
    });

    Ok(())
}

// Watch command implementation
#[cfg(feature = "serve")]
fn serve(args: &ArgMatches) -> Result<(), Box<Error>> {
    const RELOAD_COMMAND: &'static str = "reload";

    let book_dir = get_book_dir(args);
    let book = MDBook::new(&book_dir).read_config()?;

    let mut book = match args.value_of("dest-dir") {
        Some(dest_dir) => book.with_destination(Path::new(dest_dir)),
        None => book,
    };

    if let None = book.get_destination() {
        println!("The HTML renderer is not set up, impossible to serve the files.");
        std::process::exit(2);
    }

    let port = args.value_of("port").unwrap_or("3000");
    let ws_port = args.value_of("websocket-port").unwrap_or("3001");
    let interface = args.value_of("interface").unwrap_or("localhost");
    let public_address = args.value_of("address").unwrap_or(interface);
    let open_browser = args.is_present("open");

    let address = format!("{}:{}", interface, port);
    let ws_address = format!("{}:{}", interface, ws_port);

    book.set_livereload(format!(r#"
        <script type="text/javascript">
            var socket = new WebSocket("ws://{}:{}");
            socket.onmessage = function (event) {{
                if (event.data === "{}") {{
                    socket.close();
                    location.reload(true); // force reload from server (not from cache)
                }}
            }};

            window.onbeforeunload = function() {{
                socket.close();
            }}
        </script>
    "#,
                                public_address,
                                ws_port,
                                RELOAD_COMMAND));

    book.build()?;

    let staticfile = staticfile::Static::new(book.get_destination().expect("destination is present, checked before"));
    let iron = iron::Iron::new(staticfile);
    let _iron = iron.http(&*address).unwrap();

    let ws_server = ws::WebSocket::new(|_| |_| Ok(())).unwrap();

    let broadcaster = ws_server.broadcaster();

    std::thread::spawn(move || { ws_server.listen(&*ws_address).unwrap(); });

    let serving_url = format!("http://{}", address);
    println!("\nServing on: {}", serving_url);

    if open_browser {
        open(serving_url);
    }

    trigger_on_change(&mut book, move |path, book| {
        println!("File changed: {:?}\nBuilding book...\n", path);
        match book.build() {
            Err(e) => println!("Error while building: {:?}", e),
            _ => broadcaster.send(RELOAD_COMMAND).unwrap(),
        }
        println!("");
    });

    Ok(())
}

fn test(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config()?;

    book.test()?;

    Ok(())
}

fn get_book_dir(args: &ArgMatches) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() {
            env::current_dir().unwrap().join(dir)
        } else {
            p.to_path_buf()
        }
    } else {
        env::current_dir().unwrap()
    }
}

fn open<P: AsRef<OsStr>>(path: P) {
    if let Err(e) = open::that(path) {
        println!("Error opening web browser: {}", e);
    }
}

// Calls the closure when a book source file is changed. This is blocking!
#[cfg(feature = "watch")]
fn trigger_on_change<F>(book: &mut MDBook, closure: F) -> ()
    where F: Fn(&Path, &mut MDBook) -> ()
{
    use notify::RecursiveMode::*;
    use notify::DebouncedEvent::*;

    // Create a channel to receive the events.
    let (tx, rx) = channel();

    let mut watcher = match notify::watcher(tx, Duration::from_secs(1)) {
        Ok(w) => w,
        Err(e) => {
            println!("Error while trying to watch the files:\n\n\t{:?}", e);
            ::std::process::exit(0);
        },
    };

    // Add the source directory to the watcher
    if let Err(e) = watcher.watch(book.get_source(), Recursive) {
        println!("Error while watching {:?}:\n    {:?}", book.get_source(), e);
        ::std::process::exit(0);
    };

    // Add the theme directory to the watcher
    watcher.watch(book.get_theme_path(), Recursive).unwrap_or_default();

    // Add the book.{json,toml} file to the watcher if it exists, because it's not
    // located in the source directory
    if watcher
           .watch(book.get_root().join("book.json"), NonRecursive)
           .is_err() {
        // do nothing if book.json is not found
    }
    if watcher
           .watch(book.get_root().join("book.toml"), NonRecursive)
           .is_err() {
        // do nothing if book.toml is not found
    }

    println!("\nListening for changes...\n");

    loop {
        match rx.recv() {
            Ok(event) => {
                match event {
                    NoticeWrite(path) |
                    NoticeRemove(path) |
                    Create(path) |
                    Write(path) |
                    Remove(path) |
                    Rename(_, path) => {
                        closure(&path, book);
                    },
                    _ => {},
                }
            },
            Err(e) => {
                println!("An error occured: {:?}", e);
            },
        }
    }
}
<commit_msg>fix build failure<commit_after>extern crate mdbook;
#[macro_use]
extern crate clap;
extern crate log;
extern crate env_logger;
extern crate open;

// Dependencies for the Watch feature
#[cfg(feature = "watch")]
extern crate notify;
#[cfg(feature = "watch")]
extern crate time;
#[cfg(feature = "watch")]
extern crate crossbeam;

// Dependencies for the Serve feature
#[cfg(feature = "serve")]
extern crate iron;
#[cfg(feature = "serve")]
extern crate staticfile;
#[cfg(feature = "serve")]
extern crate ws;

use std::env;
use std::error::Error;
use std::ffi::OsStr;
use std::io::{self, Write};
use std::path::{Path, PathBuf};

use clap::{App, ArgMatches, SubCommand, AppSettings};

// Uses for the Watch feature
#[cfg(feature = "watch")]
use notify::Watcher;
#[cfg(feature = "watch")]
use std::time::Duration;
#[cfg(feature = "watch")]
use std::sync::mpsc::channel;

use mdbook::MDBook;

const NAME: &'static str = "mdbook";

fn main() {
    env_logger::init().unwrap();

    // Create a list of valid arguments and sub-commands
    let matches = App::new(NAME)
                    .about("Create a book in form of a static website from markdown files")
                    .author("Mathieu David <mathieudavid@mathieudavid.org>")
                    // Get the version from our Cargo.toml using clap's crate_version!() macro
                    .version(&*format!("v{}", crate_version!()))
                    .setting(AppSettings::SubcommandRequired)
                    .after_help("For more information about a specific command, try `mdbook <command> --help`\nSource code for mdbook available at: https://github.com/azerupi/mdBook")
                    .subcommand(SubCommand::with_name("init")
                        .about("Create boilerplate structure and files in the directory")
                        // the {n} denotes a newline which will properly aligned in all help messages
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'")
                        .arg_from_usage("--theme 'Copies the default theme into your source folder'")
                        .arg_from_usage("--force 'skip confirmation prompts'"))
                    .subcommand(SubCommand::with_name("build")
                        .about("Build the book from the markdown files")
                        .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
                        .arg_from_usage("-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'")
                        .arg_from_usage("--no-create 'Will not create non-existent files linked from SUMMARY.md'")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'"))
                    .subcommand(SubCommand::with_name("watch")
                        .about("Watch the files for changes")
                        .arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
                        .arg_from_usage("-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'"))
                    .subcommand(SubCommand::with_name("serve")
                        .about("Serve the book at http://localhost:3000. Rebuild and reload on change.")
                        .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'")
                        .arg_from_usage("-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'")
                        .arg_from_usage("-p, --port=[port] 'Use another port{n}(Defaults to 3000)'")
                        .arg_from_usage("-w, --websocket-port=[ws-port] 'Use another port for the websocket connection (livereload){n}(Defaults to 3001)'")
                        .arg_from_usage("-i, --interface=[interface] 'Interface to listen on{n}(Defaults to localhost)'")
                        .arg_from_usage("-a, --address=[address] 'Address that the browser can reach the websocket server from{n}(Defaults to the interface address)'")
                        .arg_from_usage("-o, --open 'Open the book server in a web browser'"))
                    .subcommand(SubCommand::with_name("test")
                        .about("Test that code samples compile"))
                    .get_matches();

    // Check which subcomamnd the user ran...
    let res = match matches.subcommand() {
        ("init", Some(sub_matches)) => init(sub_matches),
        ("build", Some(sub_matches)) => build(sub_matches),
        #[cfg(feature = "watch")]
        ("watch", Some(sub_matches)) => watch(sub_matches),
        #[cfg(feature = "serve")]
        ("serve", Some(sub_matches)) => serve(sub_matches),
        ("test", Some(sub_matches)) => test(sub_matches),
        (_, _) => unreachable!(),
    };

    if let Err(e) = res {
        writeln!(&mut io::stderr(), "An error occured:\n{}", e).ok();
        ::std::process::exit(101);
    }
}

// Simple function that user comfirmation
fn confirm() -> bool {
    io::stdout().flush().unwrap();
    let mut s = String::new();
    io::stdin().read_line(&mut s).ok();
    match &*s.trim() {
        "Y" | "y" | "yes" | "Yes" => true,
        _ => false,
    }
}

// Init command implementation
fn init(args: &ArgMatches) -> Result<(), Box<Error>> {

    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir);

    // Call the function that does the initialization
    book.init()?;

    // If flag `--theme` is present, copy theme to src
    if args.is_present("theme") {

        // Skip this if `--force` is present
        if !args.is_present("force") {
            // Print warning
            print!("\nCopying the default theme to {:?}", book.get_source());
            println!("could potentially overwrite files already present in that directory.");
            print!("\nAre you sure you want to continue? (y/n) ");

            // Read answer from user and exit if it's not 'yes'
            if !confirm() {
                println!("\nSkipping...\n");
                println!("All done, no errors...");
                ::std::process::exit(0);
            }
        }

        // Call the function that copies the theme
        book.copy_theme()?;
        println!("\nTheme copied.");

    }

    // Because of `src/book/mdbook.rs#L37-L39`, `dest` will always start with `root`
    let is_dest_inside_root = book.get_destination()
                                  .map(|p| p.starts_with(book.get_root()))
                                  .unwrap_or(false);

    if !args.is_present("force") && is_dest_inside_root {
        println!("\nDo you want a .gitignore to be created? (y/n)");

        if confirm() {
            book.create_gitignore();
            println!("\n.gitignore created.");
        }
    }

    println!("\nAll done, no errors...");

    Ok(())
}

// Build command implementation
fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let book = MDBook::new(&book_dir).read_config()?;

    let mut book = match args.value_of("dest-dir") {
        Some(dest_dir) => book.with_destination(Path::new(dest_dir)),
        None => book,
    };

    if args.is_present("no-create") {
        book.create_missing = false;
    }

    book.build()?;

    if let Some(d) = book.get_destination() {
        if args.is_present("open") {
            open(d.join("index.html"));
        }
    }

    Ok(())
}

// Watch command implementation
#[cfg(feature = "watch")]
fn watch(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let book = MDBook::new(&book_dir).read_config()?;

    let mut book = match args.value_of("dest-dir") {
        Some(dest_dir) => book.with_destination(Path::new(dest_dir)),
        None => book,
    };

    if args.is_present("open") {
        book.build()?;
        if let Some(d) = book.get_destination() {
            open(d.join("index.html"));
        }
    }

    trigger_on_change(&mut book, |path, book| {
        println!("File changed: {:?}\nBuilding book...\n", path);
        if let Err(e) = book.build() {
            println!("Error while building: {:?}", e);
        }
        println!("");
    });

    Ok(())
}

// Watch command implementation
#[cfg(feature = "serve")]
fn serve(args: &ArgMatches) -> Result<(), Box<Error>> {
    const RELOAD_COMMAND: &'static str = "reload";

    let book_dir = get_book_dir(args);
    let book = MDBook::new(&book_dir).read_config()?;

    let mut book = match args.value_of("dest-dir") {
        Some(dest_dir) => book.with_destination(Path::new(dest_dir)),
        None => book,
    };

    if let None = book.get_destination() {
        println!("The HTML renderer is not set up, impossible to serve the files.");
        std::process::exit(2);
    }

    let port = args.value_of("port").unwrap_or("3000");
    let ws_port = args.value_of("websocket-port").unwrap_or("3001");
    let interface = args.value_of("interface").unwrap_or("localhost");
    let public_address = args.value_of("address").unwrap_or(interface);
    let open_browser = args.is_present("open");

    let address = format!("{}:{}", interface, port);
    let ws_address = format!("{}:{}", interface, ws_port);

    book.set_livereload(format!(r#"
        <script type="text/javascript">
            var socket = new WebSocket("ws://{}:{}");
            socket.onmessage = function (event) {{
                if (event.data === "{}") {{
                    socket.close();
                    location.reload(true); // force reload from server (not from cache)
                }}
            }};

            window.onbeforeunload = function() {{
                socket.close();
            }}
        </script>
    "#,
                                public_address,
                                ws_port,
                                RELOAD_COMMAND));

    book.build()?;

    let staticfile = staticfile::Static::new(book.get_destination().expect("destination is present, checked before"));
    let iron = iron::Iron::new(staticfile);
    let _iron = iron.http(&*address).unwrap();

    let ws_server = ws::WebSocket::new(|_| |_| Ok(())).unwrap();

    let broadcaster = ws_server.broadcaster();

    std::thread::spawn(move || { ws_server.listen(&*ws_address).unwrap(); });

    let serving_url = format!("http://{}", address);
    println!("\nServing on: {}", serving_url);

    if open_browser {
        open(serving_url);
    }

    trigger_on_change(&mut book, move |path, book| {
        println!("File changed: {:?}\nBuilding book...\n", path);
        match book.build() {
            Err(e) => println!("Error while building: {:?}", e),
            _ => broadcaster.send(RELOAD_COMMAND).unwrap(),
        }
        println!("");
    });

    Ok(())
}

fn test(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config()?;

    book.test()?;

    Ok(())
}

fn get_book_dir(args: &ArgMatches) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() {
            env::current_dir().unwrap().join(dir)
        } else {
            p.to_path_buf()
        }
    } else {
        env::current_dir().unwrap()
    }
}

fn open<P: AsRef<OsStr>>(path: P) {
    if let Err(e) = open::that(path) {
        println!("Error opening web browser: {}", e);
    }
}

// Calls the closure when a book source file is changed. This is blocking!
#[cfg(feature = "watch")]
fn trigger_on_change<F>(book: &mut MDBook, closure: F) -> ()
    where F: Fn(&Path, &mut MDBook) -> ()
{
    use notify::RecursiveMode::*;
    use notify::DebouncedEvent::*;

    // Create a channel to receive the events.
    let (tx, rx) = channel();

    let mut watcher = match notify::watcher(tx, Duration::from_secs(1)) {
        Ok(w) => w,
        Err(e) => {
            println!("Error while trying to watch the files:\n\n\t{:?}", e);
            ::std::process::exit(0);
        },
    };

    // Add the source directory to the watcher
    if let Err(e) = watcher.watch(book.get_source(), Recursive) {
        println!("Error while watching {:?}:\n    {:?}", book.get_source(), e);
        ::std::process::exit(0);
    };

    // Add the theme directory to the watcher
    if let Some(t) = book.get_theme_path() {
        watcher.watch(t, Recursive).unwrap_or_default();
    }

    // Add the book.{json,toml} file to the watcher if it exists, because it's not
    // located in the source directory
    if watcher
           .watch(book.get_root().join("book.json"), NonRecursive)
           .is_err() {
        // do nothing if book.json is not found
    }
    if watcher
           .watch(book.get_root().join("book.toml"), NonRecursive)
           .is_err() {
        // do nothing if book.toml is not found
    }

    println!("\nListening for changes...\n");

    loop {
        match rx.recv() {
            Ok(event) => {
                match event {
                    NoticeWrite(path) |
                    NoticeRemove(path) |
                    Create(path) |
                    Write(path) |
                    Remove(path) |
                    Rename(_, path) => {
                        closure(&path, book);
                    },
                    _ => {},
                }
            },
            Err(e) => {
                println!("An error occured: {:?}", e);
            },
        }
    }
}
<|endoftext|>


<commit_before>//! Write systems to disk.

use error::Result;
use grafen::system::System;

use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf};

/// Output a system to disk as a GROMOS formatted file.
/// The filename extension is adjusted to .gro.
///
/// # Errors
/// Returns an error if the file could not be written to.
pub fn write_gromos(system: &System, output_file: &Path, title: &str) -> Result<()> {
    let path = PathBuf::from(output_file).with_extension("gro");
    let file = File::create(&path)?;
    let mut writer = BufWriter::new(file);

    writer.write_fmt(format_args!("{}\n", title))?;
    writer.write_fmt(format_args!("{}\n", system.num_atoms()))?;

    for (i, residue) in system.residues.iter().enumerate() {
        for (j, atom) in residue.base.atoms.iter().enumerate() {
            // GROMOS files wrap atom and residue numbering after five digits
            // so we must output at most that. We also switch to indexing the
            // numbers from 1 instead of from 0.
            let residue_number = (i + 1) % 100_000;
            let atom_number = (j + 1) % 100_000;

            let position = residue.position + atom.position;

            writer.write_fmt(format_args!("{:>5}{:<5}{:>5}{:>5}{:>8.3}{:>8.3}{:>8.3}\n",
                                        residue_number,
                                        residue.base.code,
                                        atom.code,
                                        atom_number,
                                        position.x,
                                        position.y,
                                        position.z))?;

        }
    }

    writer.write_fmt(format_args!("{:12.8} {:12.8} {:12.8}\n",
                                system.dimensions.x,
                                system.dimensions.y,
                                system.dimensions.z))?;

    Ok(())
}
<commit_msg>Unpack positions to tuples in `output` module<commit_after>//! Write systems to disk.

use error::Result;
use grafen::system::System;

use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf};

/// Output a system to disk as a GROMOS formatted file.
/// The filename extension is adjusted to .gro.
///
/// # Errors
/// Returns an error if the file could not be written to.
pub fn write_gromos(system: &System, output_file: &Path, title: &str) -> Result<()> {
    let path = PathBuf::from(output_file).with_extension("gro");
    let file = File::create(&path)?;
    let mut writer = BufWriter::new(file);

    writer.write_fmt(format_args!("{}\n", title))?;
    writer.write_fmt(format_args!("{}\n", system.num_atoms()))?;

    for (i, residue) in system.residues.iter().enumerate() {
        for (j, atom) in residue.base.atoms.iter().enumerate() {
            // GROMOS files wrap atom and residue numbering after five digits
            // so we must output at most that. We also switch to indexing the
            // numbers from 1 instead of from 0.
            let residue_number = (i + 1) % 100_000;
            let atom_number = (j + 1) % 100_000;

            let position = residue.position + atom.position;
            let (x, y, z) = position.to_tuple();

            writer.write_fmt(format_args!("{:>5}{:<5}{:>5}{:>5}{:>8.3}{:>8.3}{:>8.3}\n",
                                        residue_number,
                                        residue.base.code,
                                        atom.code,
                                        atom_number,
                                        x, y, z))?;
        }
    }

    let (dx, dy, dz) = system.dimensions.to_tuple();
    writer.write_fmt(format_args!("{:12.8} {:12.8} {:12.8}\n", dx, dy, dz))?;

    Ok(())
}
<|endoftext|>


<commit_before>extern crate zwreec;
extern crate getopts;
#[macro_use] extern crate log;
extern crate time;
extern crate term;

use std::env;
use std::vec::Vec;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::exit;

mod logger;

// shorthand to display program usage
macro_rules! print_usage(
    ($prog:ident, $opts:ident) => (
    print_stderr!("{}", $opts.usage(&format!("Usage: {} [-hV] [-vq] [-l [LOGFILE]] [-o OUTPUT] INPUT", $prog)));
    )
);

// found in:
// http://stackoverflow.com/a/27590832
macro_rules! print_stderr(
    ($($arg:tt)*) => (
        match write!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

fn main() {
    //early init

    // handling command line parameters
    let args: Vec<String> = env::args().collect();
    let ref program = args[0];
    let mut loggers: Vec<Box<logger::SharedLogger>> = vec![];

    // define options
    let mut opts = getopts::Options::new();
    opts.optflagmulti("v", "verbose", "be more verbose. Can be used multiple times.");
    opts.optflag("q", "quiet", "be quiet");
    opts.optflagopt("l", "logfile", "specify log file (default zwreec.log)", "LOGFILE");
    opts.optopt("o", "", "name of the output file", "FILE");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "display version");

    let parsed_opts = match opts.parse(&args[1..]) {
        Ok(m)  => { m }
        Err(f) => {
            // parsing error
            // display usage and return
            print_stderr!("{}\n", f.to_string());
            print_usage!(program, opts);
            exit(1);
        }
    };

    // examine options
    if parsed_opts.opt_present("h") {
        // parsed "-h|--help"
        // display usage and return
        print_usage!(program, opts);
        exit(1);
    }

    if parsed_opts.opt_present("V") {
        // parsed "-V|--version"
        // display current version
        println!("{} {}", program, match option_env!("CFG_VERSION") {
            Some(s) => s.to_string(),
            None => format!("{}.{}.{}{}",
                            env!("CARGO_PKG_VERSION_MAJOR"),
                            env!("CARGO_PKG_VERSION_MINOR"),
                            env!("CARGO_PKG_VERSION_PATCH"),
                            option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
        });
        exit(1);
    }

    if parsed_opts.opt_present("v") {
        // parsed "-v|--verbose"
        // set log level to verbose
        loggers.push(logger::TermLogger::new(
                match parsed_opts.opt_count("v") {
                    1 => logger::LogLevelFilter::Info,
                    2 => logger::LogLevelFilter::Debug,
                    _ => logger::LogLevelFilter::Trace,
                }));
    } else if parsed_opts.opt_present("q") {
        // parsed "-q|--quiet"
        // set log level to error
        loggers.push(logger::TermLogger::new(logger::LogLevelFilter::Error));
    } else {
        // default
        // set log level to warn
        loggers.push(logger::TermLogger::new(logger::LogLevelFilter::Warn));
    }

    if parsed_opts.opt_present("l") {
        // parsed "-l|--logfile"
        // sets a logger to output to logfile
        let name = if let Some(n) = parsed_opts.opt_str("l") {
            n
        } else {
            "zwreec.log".to_string()
        };
        loggers.push(logger::FileLogger::new(
                        logger::LogLevelFilter::Trace,
                        File::create(name).unwrap())
            );
    }

    // check parsed options and open the source file
    let mut infile = if parsed_opts.free.len() == 1 {
        // check number of 'free' parameter
        // one free parameter is the input file name
        let path = Path::new(&parsed_opts.free[0]);
        match File::open(path) {
            Err(why) => {
                panic!("couldn't open {}: {}",
                               path.display(), Error::description(&why))
            },
            Ok(file) => {
                info!("Opened input: {}", path.display());
                file
            }
        }
    } else {
        // TODO: check if STDOUT is a tty
        print_stderr!("Input file name missing\n");
        print_usage!(program, opts);
        exit(1);
    };

    // check parsed options and open a file for the resulting output
    let mut outfile = if let Some(file) = parsed_opts.opt_str("o") {
        // parsed "-o FILE"
        // try to open FILE
        let path = Path::new(&file);
        match File::open(path) {
            Err(why) => {
                panic!("couldn't open {}: {}",
                       path.display(), Error::description(&why))
            },
            Ok(file) => {
                info!("Opened output: {}", path.display());
                file
            }
        }
    } else {
        // assume default
        let path = Path::new("a.z8");
        match File::open(path) {
            Err(why) => {
                panic!("couldn't open {}: {}",
                       path.display(), Error::description(&why))
            },
            Ok(file) => {
                debug!("No output file specified, assuming default");
                info!("Opened output: {}", path.display());
                file
            }
        }
    };

    // activate logger
    let _ = logger::CombinedLogger::init(loggers);

    debug!("parsed command line options");
    info!("main started");

    // call library
    zwreec::compile(&mut infile, &mut outfile);

    // only for testing
    debug!("(2) {}", zwreec::backend::temp_hello());
    debug!("(3) {}", zwreec::utils::file::temp_hello());

    info!("main finished");
}
<commit_msg>Remove calls to previously removed temp functions<commit_after>extern crate zwreec;
extern crate getopts;
#[macro_use] extern crate log;
extern crate time;
extern crate term;

use std::env;
use std::vec::Vec;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::exit;

mod logger;

// shorthand to display program usage
macro_rules! print_usage(
    ($prog:ident, $opts:ident) => (
    print_stderr!("{}", $opts.usage(&format!("Usage: {} [-hV] [-vq] [-l [LOGFILE]] [-o OUTPUT] INPUT", $prog)));
    )
);

// found in:
// http://stackoverflow.com/a/27590832
macro_rules! print_stderr(
    ($($arg:tt)*) => (
        match write!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

fn main() {
    //early init

    // handling command line parameters
    let args: Vec<String> = env::args().collect();
    let ref program = args[0];
    let mut loggers: Vec<Box<logger::SharedLogger>> = vec![];

    // define options
    let mut opts = getopts::Options::new();
    opts.optflagmulti("v", "verbose", "be more verbose. Can be used multiple times.");
    opts.optflag("q", "quiet", "be quiet");
    opts.optflagopt("l", "logfile", "specify log file (default zwreec.log)", "LOGFILE");
    opts.optopt("o", "", "name of the output file", "FILE");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "display version");

    let parsed_opts = match opts.parse(&args[1..]) {
        Ok(m)  => { m }
        Err(f) => {
            // parsing error
            // display usage and return
            print_stderr!("{}\n", f.to_string());
            print_usage!(program, opts);
            exit(1);
        }
    };

    // examine options
    if parsed_opts.opt_present("h") {
        // parsed "-h|--help"
        // display usage and return
        print_usage!(program, opts);
        exit(1);
    }

    if parsed_opts.opt_present("V") {
        // parsed "-V|--version"
        // display current version
        println!("{} {}", program, match option_env!("CFG_VERSION") {
            Some(s) => s.to_string(),
            None => format!("{}.{}.{}{}",
                            env!("CARGO_PKG_VERSION_MAJOR"),
                            env!("CARGO_PKG_VERSION_MINOR"),
                            env!("CARGO_PKG_VERSION_PATCH"),
                            option_env!("CARGO_PKG_VERSION_PRE").unwrap_or(""))
        });
        exit(1);
    }

    if parsed_opts.opt_present("v") {
        // parsed "-v|--verbose"
        // set log level to verbose
        loggers.push(logger::TermLogger::new(
                match parsed_opts.opt_count("v") {
                    1 => logger::LogLevelFilter::Info,
                    2 => logger::LogLevelFilter::Debug,
                    _ => logger::LogLevelFilter::Trace,
                }));
    } else if parsed_opts.opt_present("q") {
        // parsed "-q|--quiet"
        // set log level to error
        loggers.push(logger::TermLogger::new(logger::LogLevelFilter::Error));
    } else {
        // default
        // set log level to warn
        loggers.push(logger::TermLogger::new(logger::LogLevelFilter::Warn));
    }

    if parsed_opts.opt_present("l") {
        // parsed "-l|--logfile"
        // sets a logger to output to logfile
        let name = if let Some(n) = parsed_opts.opt_str("l") {
            n
        } else {
            "zwreec.log".to_string()
        };
        loggers.push(logger::FileLogger::new(
                        logger::LogLevelFilter::Trace,
                        File::create(name).unwrap())
            );
    }

    // check parsed options and open the source file
    let mut infile = if parsed_opts.free.len() == 1 {
        // check number of 'free' parameter
        // one free parameter is the input file name
        let path = Path::new(&parsed_opts.free[0]);
        match File::open(path) {
            Err(why) => {
                panic!("couldn't open {}: {}",
                               path.display(), Error::description(&why))
            },
            Ok(file) => {
                info!("Opened input: {}", path.display());
                file
            }
        }
    } else {
        // TODO: check if STDOUT is a tty
        print_stderr!("Input file name missing\n");
        print_usage!(program, opts);
        exit(1);
    };

    // check parsed options and open a file for the resulting output
    let mut outfile = if let Some(file) = parsed_opts.opt_str("o") {
        // parsed "-o FILE"
        // try to open FILE
        let path = Path::new(&file);
        match File::open(path) {
            Err(why) => {
                panic!("couldn't open {}: {}",
                       path.display(), Error::description(&why))
            },
            Ok(file) => {
                info!("Opened output: {}", path.display());
                file
            }
        }
    } else {
        // assume default
        let path = Path::new("a.z8");
        match File::open(path) {
            Err(why) => {
                panic!("couldn't open {}: {}",
                       path.display(), Error::description(&why))
            },
            Ok(file) => {
                debug!("No output file specified, assuming default");
                info!("Opened output: {}", path.display());
                file
            }
        }
    };

    // activate logger
    let _ = logger::CombinedLogger::init(loggers);

    debug!("parsed command line options");
    info!("main started");

    // call library
    zwreec::compile(&mut infile, &mut outfile);

    info!("main finished");
}
<|endoftext|>


<commit_before>use crate::io::AsyncBufRead;

use pin_project_lite::pin_project;
use std::future::Future;
use std::io;
use std::marker::PhantomPinned;
use std::pin::Pin;
use std::task::{Context, Poll};

pin_project! {
    /// Future for the [`fill_buf`](crate::io::AsyncBufReadExt::fill_buf) method.
    #[derive(Debug)]
    #[must_use = "futures do nothing unless you `.await` or poll them"]
    pub struct FillBuf<'a, R: ?Sized> {
        reader: Option<&'a mut R>,
        #[pin]
        _pin: PhantomPinned,
    }
}

pub(crate) fn fill_buf<R>(reader: &mut R) -> FillBuf<'_, R>
where
    R: AsyncBufRead + ?Sized + Unpin,
{
    FillBuf {
        reader: Some(reader),
        _pin: PhantomPinned,
    }
}

impl<'a, R: AsyncBufRead + ?Sized + Unpin> Future for FillBuf<'a, R> {
    type Output = io::Result<&'a [u8]>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let me = self.project();

        let reader = me.reader.take().expect("Polled after completion.");
        match Pin::new(&mut *reader).poll_fill_buf(cx) {
            Poll::Ready(Ok(slice)) => unsafe {
                // Safety: This is necessary only due to a limitation in the
                // borrow checker. Once Rust starts using the polonius borrow
                // checker, this can be simplified.
                let slice = std::mem::transmute::<&[u8], &'a [u8]>(slice);
                Poll::Ready(Ok(slice))
            },
            Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
            Poll::Pending => {
                *me.reader = Some(reader);
                Poll::Pending
            }
        }
    }
}
<commit_msg>io: improve safety comment on `FillBuf` (#4476)<commit_after>use crate::io::AsyncBufRead;

use pin_project_lite::pin_project;
use std::future::Future;
use std::io;
use std::marker::PhantomPinned;
use std::pin::Pin;
use std::task::{Context, Poll};

pin_project! {
    /// Future for the [`fill_buf`](crate::io::AsyncBufReadExt::fill_buf) method.
    #[derive(Debug)]
    #[must_use = "futures do nothing unless you `.await` or poll them"]
    pub struct FillBuf<'a, R: ?Sized> {
        reader: Option<&'a mut R>,
        #[pin]
        _pin: PhantomPinned,
    }
}

pub(crate) fn fill_buf<R>(reader: &mut R) -> FillBuf<'_, R>
where
    R: AsyncBufRead + ?Sized + Unpin,
{
    FillBuf {
        reader: Some(reader),
        _pin: PhantomPinned,
    }
}

impl<'a, R: AsyncBufRead + ?Sized + Unpin> Future for FillBuf<'a, R> {
    type Output = io::Result<&'a [u8]>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let me = self.project();

        let reader = me.reader.take().expect("Polled after completion.");
        match Pin::new(&mut *reader).poll_fill_buf(cx) {
            Poll::Ready(Ok(slice)) => unsafe {
                // Safety: This is necessary only due to a limitation in the
                // borrow checker. Once Rust starts using the polonius borrow
                // checker, this can be simplified.
                //
                // The safety of this transmute relies on the fact that the
                // value of `reader` is `None` when we return in this branch.
                // Otherwise the caller could poll us again after
                // completion, and access the mutable reference while the
                // returned immutable reference still exists.
                let slice = std::mem::transmute::<&[u8], &'a [u8]>(slice);
                Poll::Ready(Ok(slice))
            },
            Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
            Poll::Pending => {
                *me.reader = Some(reader);
                Poll::Pending
            }
        }
    }
}
<|endoftext|>