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

use evcxr;

use colored::*;
use evcxr::{CommandContext, CompilationError, Error};
use rustyline::{error::ReadlineError, Editor};
use std::fs;
use std::io;
use std::sync::mpsc;
use structopt::StructOpt;

use evcxr_repl::EvcxrRustylineHelper;

const PROMPT: &str = ">> ";

struct Repl {
    command_context: CommandContext,
    ide_mode: bool,
}

fn send_output<T: io::Write + Send + 'static>(
    channel: mpsc::Receiver<String>,
    mut output: T,
    color: Option<Color>,
) {
    std::thread::spawn(move || {
        while let Ok(line) = channel.recv() {
            let status = if let Some(color) = color {
                writeln!(output, "{}", line.color(color))
            } else {
                writeln!(output, "{}", line)
            };
            if status.is_err() {
                break;
            }
        }
    });
}

impl Repl {
    fn new(ide_mode: bool) -> Result<Repl, Error> {
        let (command_context, outputs) = CommandContext::new()?;
        send_output(outputs.stdout, io::stdout(), None);
        send_output(outputs.stderr, io::stderr(), Some(Color::BrightRed));
        let mut repl = Repl {
            command_context,
            ide_mode,
        };
        repl.execute(":load_config");
        Ok(repl)
    }

    fn execute(&mut self, to_run: &str) {
        let success = match self.command_context.execute(to_run) {
            Ok(output) => {
                if let Some(text) = output.get("text/plain") {
                    println!("{}", text);
                }
                if let Some(duration) = output.timing {
                    println!("{}", format!("Took {}ms", duration.as_millis()).blue());

                    for phase in output.phases {
                        println!(
                            "{}",
                            format!("  {}: {}ms", phase.name, phase.duration.as_millis()).blue()
                        );
                    }
                }
                true
            }
            Err(evcxr::Error::CompilationErrors(errors)) => {
                self.display_errors(errors);
                false
            }
            Err(err) => {
                eprintln!("{}", format!("{}", err).bright_red());
                false
            }
        };

        if self.ide_mode {
            let success_marker = if success { "\u{0091}" } else { "\u{0092}" };
            print!("{}", success_marker);
        }
    }

    fn display_errors(&mut self, errors: Vec<CompilationError>) {
        for error in errors {
            if error.is_from_user_code() {
                for spanned_message in error.spanned_messages() {
                    if let Some(span) = &spanned_message.span {
                        for _ in 1..span.start_column + PROMPT.len() {
                            print!(" ");
                        }
                        let mut carrots = String::new();
                        for _ in span.start_column..span.end_column {
                            carrots.push('^');
                        }
                        print!("{}", carrots.bright_red());
                        println!(" {}", spanned_message.label.bright_blue());
                    } else {
                        // Our error originates from both user-code and generated
                        // code.
                        println!("{}", spanned_message.label.bright_blue());
                    }
                }
                println!("{}", error.message().bright_red());
                for help in error.help() {
                    println!("{} {}", "help:".bold(), help);
                }
                if let Some(extra_hint) = error.evcxr_extra_hint() {
                    println!("{}", extra_hint);
                }
            } else {
                println!(
                    "A compilation error was found in code we generated.\n\
                     Ideally this should't happen. Type :last_error_json to see details.\n{}",
                    error.rendered()
                );
            }
        }
    }
}

fn readline_direct(prompt: &str) -> rustyline::Result<String> {
    use std::io::Write;

    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    stdout.write_all(prompt.as_bytes())?;
    stdout.flush()?;

    let mut line = String::new();
    if io::stdin().read_line(&mut line)? > 0 {
        line = line.replace('\u{2028}', "\n");
        Ok(line)
    } else {
        Err(rustyline::error::ReadlineError::Eof)
    }
}

#[derive(StructOpt, Debug)]
#[structopt(name = "evcxr")]
struct Options {
    #[structopt(long)]
    disable_readline: bool,
    #[structopt(long)]
    ide_mode: bool,
    /// Optimization level (0, 1 or 2)
    #[structopt(long, default_value = "")]
    opt: String,
}

fn main() {
    evcxr::runtime_hook();

    let options = Options::from_args();

    if options.disable_readline {
        #[cfg(windows)]
        colored::control::set_virtual_terminal(true).ok();
    }

    println!("Welcome to evcxr. For help, type :help");
    let mut repl = match Repl::new(options.ide_mode) {
        Ok(c) => c,
        Err(error) => {
            eprintln!("{}", error);
            return;
        }
    };

    repl.command_context.set_opt_level(&options.opt).ok();
    let mut editor = Editor::<EvcxrRustylineHelper>::new();
    editor.set_helper(Some(EvcxrRustylineHelper::default()));
    let mut opt_history_file = None;
    let config_dir = evcxr::config_dir();
    if let Some(config_dir) = &config_dir {
        fs::create_dir_all(config_dir).ok();
        let history_file = config_dir.join("history.txt");
        editor.load_history(&history_file).ok();
        opt_history_file = Some(history_file);
    }
    loop {
        let prompt = format!("{}", PROMPT.yellow());
        let readline = if options.disable_readline {
            readline_direct(&prompt)
        } else {
            editor.readline(PROMPT)
        };
        match readline {
            Ok(line) => {
                editor.add_history_entry(line.clone());
                repl.execute(&line);
            }
            Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => break,
            Err(err) => {
                eprintln!("Error: {:?}", err);
                break;
            }
        }
    }
    if let Some(history_file) = &opt_history_file {
        editor.save_history(&history_file).ok();
    }
}
<commit_msg>Fix unicode color console output on Windows (#115)<commit_after>// Copyright 2020 The Evcxr Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use evcxr;

use colored::*;
use evcxr::{CommandContext, CompilationError, Error};
use rustyline::{error::ReadlineError, Editor};
use std::fs;
use std::io;
use std::sync::mpsc;
use structopt::StructOpt;

use evcxr_repl::EvcxrRustylineHelper;

const PROMPT: &str = ">> ";

struct Repl {
    command_context: CommandContext,
    ide_mode: bool,
}

fn send_output<T: io::Write + Send + 'static>(
    channel: mpsc::Receiver<String>,
    mut output: T,
    color: Option<Color>,
) {
    std::thread::spawn(move || {
        while let Ok(line) = channel.recv() {
            let status = if let Some(color) = color {
                writeln!(output, "{}", line.color(color))
            } else {
                writeln!(output, "{}", line)
            };
            if status.is_err() {
                break;
            }
        }
    });
}

impl Repl {
    fn new(ide_mode: bool) -> Result<Repl, Error> {
        let (command_context, outputs) = CommandContext::new()?;
        send_output(outputs.stdout, io::stdout(), None);
        send_output(outputs.stderr, io::stderr(), Some(Color::BrightRed));
        let mut repl = Repl {
            command_context,
            ide_mode,
        };
        repl.execute(":load_config");
        Ok(repl)
    }

    fn execute(&mut self, to_run: &str) {
        let success = match self.command_context.execute(to_run) {
            Ok(output) => {
                if let Some(text) = output.get("text/plain") {
                    println!("{}", text);
                }
                if let Some(duration) = output.timing {
                    println!("{}", format!("Took {}ms", duration.as_millis()).blue());

                    for phase in output.phases {
                        println!(
                            "{}",
                            format!("  {}: {}ms", phase.name, phase.duration.as_millis()).blue()
                        );
                    }
                }
                true
            }
            Err(evcxr::Error::CompilationErrors(errors)) => {
                self.display_errors(errors);
                false
            }
            Err(err) => {
                eprintln!("{}", format!("{}", err).bright_red());
                false
            }
        };

        if self.ide_mode {
            let success_marker = if success { "\u{0091}" } else { "\u{0092}" };
            print!("{}", success_marker);
        }
    }

    fn display_errors(&mut self, errors: Vec<CompilationError>) {
        for error in errors {
            if error.is_from_user_code() {
                for spanned_message in error.spanned_messages() {
                    if let Some(span) = &spanned_message.span {
                        for _ in 1..span.start_column + PROMPT.len() {
                            print!(" ");
                        }
                        let mut carrots = String::new();
                        for _ in span.start_column..span.end_column {
                            carrots.push('^');
                        }
                        print!("{}", carrots.bright_red());
                        println!(" {}", spanned_message.label.bright_blue());
                    } else {
                        // Our error originates from both user-code and generated
                        // code.
                        println!("{}", spanned_message.label.bright_blue());
                    }
                }
                println!("{}", error.message().bright_red());
                for help in error.help() {
                    println!("{} {}", "help:".bold(), help);
                }
                if let Some(extra_hint) = error.evcxr_extra_hint() {
                    println!("{}", extra_hint);
                }
            } else {
                println!(
                    "A compilation error was found in code we generated.\n\
                     Ideally this should't happen. Type :last_error_json to see details.\n{}",
                    error.rendered()
                );
            }
        }
    }
}

fn readline_direct(prompt: &str) -> rustyline::Result<String> {
    use std::io::Write;

    // Write prompt and flush it to stdout
    let mut stdout = io::stdout();
    stdout.write_all(prompt.as_bytes())?;
    stdout.flush()?;

    let mut line = String::new();
    if io::stdin().read_line(&mut line)? > 0 {
        line = line.replace('\u{2028}', "\n");
        Ok(line)
    } else {
        Err(rustyline::error::ReadlineError::Eof)
    }
}

#[derive(StructOpt, Debug)]
#[structopt(name = "evcxr")]
struct Options {
    #[structopt(long)]
    disable_readline: bool,
    #[structopt(long)]
    ide_mode: bool,
    /// Optimization level (0, 1 or 2)
    #[structopt(long, default_value = "")]
    opt: String,
}

fn main() {
    evcxr::runtime_hook();

    let options = Options::from_args();

    #[cfg(windows)]
    colored::control::set_virtual_terminal(true).ok();

    println!("Welcome to evcxr. For help, type :help");
    let mut repl = match Repl::new(options.ide_mode) {
        Ok(c) => c,
        Err(error) => {
            eprintln!("{}", error);
            return;
        }
    };

    repl.command_context.set_opt_level(&options.opt).ok();
    let mut editor = Editor::<EvcxrRustylineHelper>::new();
    editor.set_helper(Some(EvcxrRustylineHelper::default()));
    let mut opt_history_file = None;
    let config_dir = evcxr::config_dir();
    if let Some(config_dir) = &config_dir {
        fs::create_dir_all(config_dir).ok();
        let history_file = config_dir.join("history.txt");
        editor.load_history(&history_file).ok();
        opt_history_file = Some(history_file);
    }
    loop {
        let prompt = format!("{}", PROMPT.yellow());
        let readline = if options.disable_readline {
            readline_direct(&prompt)
        } else {
            editor.readline(PROMPT)
        };
        match readline {
            Ok(line) => {
                editor.add_history_entry(line.clone());
                repl.execute(&line);
            }
            Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => break,
            Err(err) => {
                eprintln!("Error: {:?}", err);
                break;
            }
        }
    }
    if let Some(history_file) = &opt_history_file {
        editor.save_history(&history_file).ok();
    }
}
<|endoftext|>


<commit_before>// # Custom collector example
//
// This example shows how you can implement your own
// collector. As an example, we will compute a collector
// that computes the standard deviation of a given fast field.
//
// Of course, you can have a look at the tantivy's built-in collectors
// such as the `CountCollector` for more examples.

// ---
// Importing tantivy...
use crate::collector::{Collector, SegmentCollector};
use crate::fastfield::FastFieldReader;
use crate::schema::Field;
use crate::{Score, SegmentReader, TantivyError};

/// The `FilterCollector` collector filters docs using a u64 fast field value and a predicate.
/// Only the documents for which the predicate returned "true" will be passed on to the next collector.
///
/// ```rust
/// use tantivy::collector::{TopDocs, FilterCollector};
/// use tantivy::query::QueryParser;
/// use tantivy::schema::{Schema, TEXT, INDEXED, FAST};
/// use tantivy::{doc, DocAddress, Index};
///
/// let mut schema_builder = Schema::builder();
/// let title = schema_builder.add_text_field("title", TEXT);
/// let price = schema_builder.add_u64_field("price", INDEXED | FAST);
/// let schema = schema_builder.build();
/// let index = Index::create_in_ram(schema);
///
/// let mut index_writer = index.writer_with_num_threads(1, 10_000_000).unwrap();
/// index_writer.add_document(doc!(title => "The Name of the Wind", price => 30_200u64));
/// index_writer.add_document(doc!(title => "The Diary of Muadib", price => 29_240u64));
/// index_writer.add_document(doc!(title => "A Dairy Cow", price => 21_240u64));
/// index_writer.add_document(doc!(title => "The Diary of a Young Girl", price => 20_120u64));
/// assert!(index_writer.commit().is_ok());
///
/// let reader = index.reader().unwrap();
/// let searcher = reader.searcher();
///
/// let query_parser = QueryParser::for_index(&index, vec![title]);
/// let query = query_parser.parse_query("diary").unwrap();
/// let no_filter_collector = FilterCollector::new(price, &|value| value > 20_120u64, TopDocs::with_limit(1));
/// let top_docs = searcher.search(&query, &no_filter_collector).unwrap();
///
/// assert_eq!(top_docs.len(), 1);
/// assert_eq!(top_docs[0].1, DocAddress(0, 1));
///
/// let filter_all_collector = FilterCollector::new(price, &|value| value < 5u64, TopDocs::with_limit(2));
/// let filtered_top_docs = searcher.search(&query, &filter_all_collector).unwrap();
///
/// assert_eq!(filtered_top_docs.len(), 0);
/// ```
pub struct FilterCollector<TCollector, TPredicate>
where
    TPredicate: 'static,
{
    field: Field,
    collector: TCollector,
    predicate: &'static TPredicate,
}

impl<TCollector, TPredicate> FilterCollector<TCollector, TPredicate>
where
    TCollector: Collector + Send + Sync,
    TPredicate: Fn(u64) -> bool + Send + Sync,
{
    /// Create a new FilterCollector.
    pub fn new(
        field: Field,
        predicate: &'static TPredicate,
        collector: TCollector,
    ) -> FilterCollector<TCollector, TPredicate> {
        FilterCollector {
            field,
            predicate,
            collector,
        }
    }
}

impl<TCollector, TPredicate> Collector for FilterCollector<TCollector, TPredicate>
where
    TCollector: Collector + Send + Sync,
    TPredicate: 'static + Fn(u64) -> bool + Send + Sync,
{
    // That's the type of our result.
    // Our standard deviation will be a float.
    type Fruit = TCollector::Fruit;

    type Child = FilterSegmentCollector<TCollector::Child, TPredicate>;

    fn for_segment(
        &self,
        segment_local_id: u32,
        segment_reader: &SegmentReader,
    ) -> crate::Result<FilterSegmentCollector<TCollector::Child, TPredicate>> {
        let fast_field_reader = segment_reader
            .fast_fields()
            .u64(self.field)
            .ok_or_else(|| {
                let field_name = segment_reader.schema().get_field_name(self.field);
                TantivyError::SchemaError(format!(
                    "Field {:?} is not a u64 fast field.",
                    field_name
                ))
            })?;
        let segment_collector = self
            .collector
            .for_segment(segment_local_id, segment_reader)?;
        Ok(FilterSegmentCollector {
            fast_field_reader,
            segment_collector: segment_collector,
            predicate: self.predicate,
        })
    }

    fn requires_scoring(&self) -> bool {
        self.collector.requires_scoring()
    }

    fn merge_fruits(
        &self,
        segment_fruits: Vec<<TCollector::Child as SegmentCollector>::Fruit>,
    ) -> crate::Result<TCollector::Fruit> {
        self.collector.merge_fruits(segment_fruits)
    }
}

pub struct FilterSegmentCollector<TSegmentCollector, TPredicate>
where
    TPredicate: 'static,
{
    fast_field_reader: FastFieldReader<u64>,
    segment_collector: TSegmentCollector,
    predicate: &'static TPredicate,
}

impl<TSegmentCollector, TPredicate> SegmentCollector
    for FilterSegmentCollector<TSegmentCollector, TPredicate>
where
    TSegmentCollector: SegmentCollector,
    TPredicate: 'static + Fn(u64) -> bool + Send + Sync,
{
    type Fruit = TSegmentCollector::Fruit;

    fn collect(&mut self, doc: u32, score: Score) {
        let value = self.fast_field_reader.get(doc);
        if (self.predicate)(value) {
            self.segment_collector.collect(doc, score)
        }
    }

    fn harvest(self) -> <TSegmentCollector as SegmentCollector>::Fruit {
        self.segment_collector.harvest()
    }
}
<commit_msg>better test<commit_after>// # Custom collector example
//
// This example shows how you can implement your own
// collector. As an example, we will compute a collector
// that computes the standard deviation of a given fast field.
//
// Of course, you can have a look at the tantivy's built-in collectors
// such as the `CountCollector` for more examples.

// ---
// Importing tantivy...
use crate::collector::{Collector, SegmentCollector};
use crate::fastfield::FastFieldReader;
use crate::schema::Field;
use crate::{Score, SegmentReader, TantivyError};

/// The `FilterCollector` collector filters docs using a u64 fast field value and a predicate.
/// Only the documents for which the predicate returned "true" will be passed on to the next collector.
///
/// ```rust
/// use tantivy::collector::{TopDocs, FilterCollector};
/// use tantivy::query::QueryParser;
/// use tantivy::schema::{Schema, TEXT, INDEXED, FAST};
/// use tantivy::{doc, DocAddress, Index};
///
/// let mut schema_builder = Schema::builder();
/// let title = schema_builder.add_text_field("title", TEXT);
/// let price = schema_builder.add_u64_field("price", INDEXED | FAST);
/// let schema = schema_builder.build();
/// let index = Index::create_in_ram(schema);
///
/// let mut index_writer = index.writer_with_num_threads(1, 10_000_000).unwrap();
/// index_writer.add_document(doc!(title => "The Name of the Wind", price => 30_200u64));
/// index_writer.add_document(doc!(title => "The Diary of Muadib", price => 29_240u64));
/// index_writer.add_document(doc!(title => "A Dairy Cow", price => 21_240u64));
/// index_writer.add_document(doc!(title => "The Diary of a Young Girl", price => 20_120u64));
/// assert!(index_writer.commit().is_ok());
///
/// let reader = index.reader().unwrap();
/// let searcher = reader.searcher();
///
/// let query_parser = QueryParser::for_index(&index, vec![title]);
/// let query = query_parser.parse_query("diary").unwrap();
/// let no_filter_collector = FilterCollector::new(price, &|value| value > 20_120u64, TopDocs::with_limit(2));
/// let top_docs = searcher.search(&query, &no_filter_collector).unwrap();
///
/// assert_eq!(top_docs.len(), 1);
/// assert_eq!(top_docs[0].1, DocAddress(0, 1));
///
/// let filter_all_collector = FilterCollector::new(price, &|value| value < 5u64, TopDocs::with_limit(2));
/// let filtered_top_docs = searcher.search(&query, &filter_all_collector).unwrap();
///
/// assert_eq!(filtered_top_docs.len(), 0);
/// ```
pub struct FilterCollector<TCollector, TPredicate>
where
    TPredicate: 'static,
{
    field: Field,
    collector: TCollector,
    predicate: &'static TPredicate,
}

impl<TCollector, TPredicate> FilterCollector<TCollector, TPredicate>
where
    TCollector: Collector + Send + Sync,
    TPredicate: Fn(u64) -> bool + Send + Sync,
{
    /// Create a new FilterCollector.
    pub fn new(
        field: Field,
        predicate: &'static TPredicate,
        collector: TCollector,
    ) -> FilterCollector<TCollector, TPredicate> {
        FilterCollector {
            field,
            predicate,
            collector,
        }
    }
}

impl<TCollector, TPredicate> Collector for FilterCollector<TCollector, TPredicate>
where
    TCollector: Collector + Send + Sync,
    TPredicate: 'static + Fn(u64) -> bool + Send + Sync,
{
    // That's the type of our result.
    // Our standard deviation will be a float.
    type Fruit = TCollector::Fruit;

    type Child = FilterSegmentCollector<TCollector::Child, TPredicate>;

    fn for_segment(
        &self,
        segment_local_id: u32,
        segment_reader: &SegmentReader,
    ) -> crate::Result<FilterSegmentCollector<TCollector::Child, TPredicate>> {
        let fast_field_reader = segment_reader
            .fast_fields()
            .u64(self.field)
            .ok_or_else(|| {
                let field_name = segment_reader.schema().get_field_name(self.field);
                TantivyError::SchemaError(format!(
                    "Field {:?} is not a u64 fast field.",
                    field_name
                ))
            })?;
        let segment_collector = self
            .collector
            .for_segment(segment_local_id, segment_reader)?;
        Ok(FilterSegmentCollector {
            fast_field_reader,
            segment_collector: segment_collector,
            predicate: self.predicate,
        })
    }

    fn requires_scoring(&self) -> bool {
        self.collector.requires_scoring()
    }

    fn merge_fruits(
        &self,
        segment_fruits: Vec<<TCollector::Child as SegmentCollector>::Fruit>,
    ) -> crate::Result<TCollector::Fruit> {
        self.collector.merge_fruits(segment_fruits)
    }
}

pub struct FilterSegmentCollector<TSegmentCollector, TPredicate>
where
    TPredicate: 'static,
{
    fast_field_reader: FastFieldReader<u64>,
    segment_collector: TSegmentCollector,
    predicate: &'static TPredicate,
}

impl<TSegmentCollector, TPredicate> SegmentCollector
    for FilterSegmentCollector<TSegmentCollector, TPredicate>
where
    TSegmentCollector: SegmentCollector,
    TPredicate: 'static + Fn(u64) -> bool + Send + Sync,
{
    type Fruit = TSegmentCollector::Fruit;

    fn collect(&mut self, doc: u32, score: Score) {
        let value = self.fast_field_reader.get(doc);
        if (self.predicate)(value) {
            self.segment_collector.collect(doc, score)
        }
    }

    fn harvest(self) -> <TSegmentCollector as SegmentCollector>::Fruit {
        self.segment_collector.harvest()
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

use clap::Arg;
use human_size::{Byte, Size};
use lucet_runtime::{self, DlModule, Limits, MmapRegion, Module, Region};
use lucet_wasi::{hostcalls, WasiCtxBuilder};
use std::fs::File;
use std::sync::Arc;

struct Config<'a> {
    lucet_module: &'a str,
    guest_args: Vec<&'a str>,
    entrypoint: &'a str,
    preopen_dirs: Vec<(File, &'a str)>,
    limits: Limits,
}

fn main() {
    // No-ops, but makes sure the linker doesn't throw away parts
    // of the runtime:
    lucet_runtime::lucet_internal_ensure_linked();
    hostcalls::ensure_linked();

    let matches = app_from_crate!()
        .arg(
            Arg::with_name("entrypoint")
                .long("entrypoint")
                .takes_value(true)
                .default_value("_start")
                .help("Entrypoint to run within the WASI module"),
        )
        .arg(
            Arg::with_name("preopen_dirs")
                .required(false)
                .long("dir")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1)
                .help("A directory to provide to the WASI guest")
                .long_help(
                    "Directories on the host can be provided to the WASI guest as part of a \
                     virtual filesystem. Each directory is specified as \
                     --dir `host_path:guest_path`, where `guest_path` specifies the path that will \
                     correspond to `host_path` for calls like `fopen` in the guest.\
                     \n\n\
                     For example, `--dir /home/host_user/wasi_sandbox:/sandbox` will make \
                     `/home/host_user/wasi_sandbox` available within the guest as `/sandbox`.\
                     \n\n\
                     Guests will be able to access any files and directories under the \
                     `host_path`, but will be unable to access other parts of the host \
                     filesystem through relative paths (e.g., `/sandbox/../some_other_file`) \
                     or through symlinks.",
                ),
        )
        .arg(
            Arg::with_name("lucet_module")
                .required(true)
                .help("Path to the `lucetc`-compiled WASI module"),
        )
        .arg(
            Arg::with_name("heap_memory_size")
                .long("max-heap-size")
                .takes_value(true)
                .default_value("1024 KiB")
                .help("Maximum heap size (must be a multiple of 4 KiB)"),
        )
        .arg(
            Arg::with_name("heap_address_space_size")
                .long("heap-address-space")
                .takes_value(true)
                .default_value("8 GiB")
                .help("Maximum heap address space size (must be a multiple of 4 KiB, and >= `max-heap-size`)"),
        )
        .arg(
            Arg::with_name("stack_size")
                .long("stack-size")
                .takes_value(true)
                .default_value("128 KiB")
                .help("Maximum stack size (must be a multiple of 4 KiB)"),
        )
        .arg(
            Arg::with_name("globals_size")
                .long("globals-size")
                .takes_value(true)
                .default_value("4 KiB")
                .help("Maximum globals size (must be a multiple of 4 KiB)"),
        )
        .arg(
            Arg::with_name("guest_args")
                .required(false)
                .multiple(true)
                .help("Arguments to the WASI `main` function"),
        )
        .get_matches();

    let entrypoint = matches.value_of("entrypoint").unwrap();

    let lucet_module = matches.value_of("lucet_module").unwrap();

    let preopen_dirs = matches
        .values_of("preopen_dirs")
        .map(|vals| {
            vals.map(|preopen_dir| {
                if let [host_path, guest_path] =
                    preopen_dir.split(':').collect::<Vec<&str>>().as_slice()
                {
                    let host_dir = File::open(host_path).unwrap();
                    (host_dir, *guest_path)
                } else {
                    println!("Invalid directory specification: {}", preopen_dir);
                    println!("{}", matches.usage());
                    std::process::exit(1);
                }
            })
            .collect()
        })
        .unwrap_or(vec![]);

    let heap_memory_size = value_t!(matches, "heap_memory_size", Size)
        .unwrap_or_else(|e| e.exit())
        .into::<Byte>()
        .value() as usize;
    let heap_address_space_size = value_t!(matches, "heap_address_space_size", Size)
        .unwrap_or_else(|e| e.exit())
        .into::<Byte>()
        .value() as usize;

    if heap_memory_size > heap_address_space_size {
        println!("`heap-address-space` must be at least as large as `max-heap-size`");
        println!("{}", matches.usage());
        std::process::exit(1);
    }

    let stack_size = value_t!(matches, "stack_size", Size)
        .unwrap_or_else(|e| e.exit())
        .into::<Byte>()
        .value() as usize;
    let globals_size = value_t!(matches, "globals_size", Size)
        .unwrap_or_else(|e| e.exit())
        .into::<Byte>()
        .value() as usize;

    let limits = Limits {
        heap_memory_size,
        heap_address_space_size,
        stack_size,
        globals_size,
    };

    let guest_args = matches
        .values_of("guest_args")
        .map(|vals| vals.collect())
        .unwrap_or(vec![]);

    let config = Config {
        lucet_module,
        guest_args,
        entrypoint,
        preopen_dirs,
        limits,
    };

    run(config)
}

fn run(config: Config) {
    lucet_wasi::hostcalls::ensure_linked();
    let exitcode = {
        // doing all of this in a block makes sure everything gets dropped before exiting
        let region = MmapRegion::create(1, &config.limits).expect("region can be created");
        let module = DlModule::load(&config.lucet_module).expect("module can be loaded");

        // put the path to the module on the front for argv[0]
        let args = std::iter::once(config.lucet_module)
            .chain(config.guest_args.into_iter())
            .collect::<Vec<&str>>();
        let mut ctx = WasiCtxBuilder::new().args(&args).inherit_env();
        for (dir, guest_path) in config.preopen_dirs {
            ctx = ctx.preopened_dir(dir, guest_path);
        }
        let mut inst = region
            .new_instance_builder(module as Arc<dyn Module>)
            .with_embed_ctx(ctx.build().expect("WASI ctx can be created"))
            .build()
            .expect("instance can be created");

        match inst.run(config.entrypoint.as_bytes(), &[]) {
            // normal termination implies 0 exit code
            Ok(_) => 0,
            Err(lucet_runtime::Error::RuntimeTerminated(
                lucet_runtime::TerminationDetails::Provided(any),
            )) => *any
                .downcast_ref::<lucet_wasi::host::__wasi_exitcode_t>()
                .expect("termination yields an exitcode"),
            Err(e) => panic!("lucet-wasi runtime error: {}", e),
        }
    };
    std::process::exit(exitcode as i32);
}
<commit_msg>[lucet-wasi] increase default memory limits<commit_after>#[macro_use]
extern crate clap;

use clap::Arg;
use human_size::{Byte, Size};
use lucet_runtime::{self, DlModule, Limits, MmapRegion, Module, Region};
use lucet_runtime_internals::module::ModuleInternal;
use lucet_wasi::{hostcalls, WasiCtxBuilder};
use std::fs::File;
use std::sync::Arc;

struct Config<'a> {
    lucet_module: &'a str,
    guest_args: Vec<&'a str>,
    entrypoint: &'a str,
    preopen_dirs: Vec<(File, &'a str)>,
    limits: Limits,
}

fn main() {
    // No-ops, but makes sure the linker doesn't throw away parts
    // of the runtime:
    lucet_runtime::lucet_internal_ensure_linked();
    hostcalls::ensure_linked();

    let matches = app_from_crate!()
        .arg(
            Arg::with_name("entrypoint")
                .long("entrypoint")
                .takes_value(true)
                .default_value("_start")
                .help("Entrypoint to run within the WASI module"),
        )
        .arg(
            Arg::with_name("preopen_dirs")
                .required(false)
                .long("dir")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1)
                .help("A directory to provide to the WASI guest")
                .long_help(
                    "Directories on the host can be provided to the WASI guest as part of a \
                     virtual filesystem. Each directory is specified as \
                     --dir `host_path:guest_path`, where `guest_path` specifies the path that will \
                     correspond to `host_path` for calls like `fopen` in the guest.\
                     \n\n\
                     For example, `--dir /home/host_user/wasi_sandbox:/sandbox` will make \
                     `/home/host_user/wasi_sandbox` available within the guest as `/sandbox`.\
                     \n\n\
                     Guests will be able to access any files and directories under the \
                     `host_path`, but will be unable to access other parts of the host \
                     filesystem through relative paths (e.g., `/sandbox/../some_other_file`) \
                     or through symlinks.",
                ),
        )
        .arg(
            Arg::with_name("lucet_module")
                .required(true)
                .help("Path to the `lucetc`-compiled WASI module"),
        )
        .arg(
            Arg::with_name("heap_memory_size")
                .long("max-heap-size")
                .takes_value(true)
                .default_value("4 GiB")
                .help("Maximum heap size (must be a multiple of 4 KiB)"),
        )
        .arg(
            Arg::with_name("heap_address_space_size")
                .long("heap-address-space")
                .takes_value(true)
                .default_value("8 GiB")
                .help("Maximum heap address space size (must be a multiple of 4 KiB, and >= `max-heap-size`)"),
        )
        .arg(
            Arg::with_name("stack_size")
                .long("stack-size")
                .takes_value(true)
                .default_value("8 MiB")
                .help("Maximum stack size (must be a multiple of 4 KiB)"),
        )
        .arg(
            Arg::with_name("guest_args")
                .required(false)
                .multiple(true)
                .help("Arguments to the WASI `main` function"),
        )
        .get_matches();

    let entrypoint = matches.value_of("entrypoint").unwrap();

    let lucet_module = matches.value_of("lucet_module").unwrap();

    let preopen_dirs = matches
        .values_of("preopen_dirs")
        .map(|vals| {
            vals.map(|preopen_dir| {
                if let [host_path, guest_path] =
                    preopen_dir.split(':').collect::<Vec<&str>>().as_slice()
                {
                    let host_dir = File::open(host_path).unwrap();
                    (host_dir, *guest_path)
                } else {
                    println!("Invalid directory specification: {}", preopen_dir);
                    println!("{}", matches.usage());
                    std::process::exit(1);
                }
            })
            .collect()
        })
        .unwrap_or(vec![]);

    let heap_memory_size = value_t!(matches, "heap_memory_size", Size)
        .unwrap_or_else(|e| e.exit())
        .into::<Byte>()
        .value() as usize;
    let heap_address_space_size = value_t!(matches, "heap_address_space_size", Size)
        .unwrap_or_else(|e| e.exit())
        .into::<Byte>()
        .value() as usize;

    if heap_memory_size > heap_address_space_size {
        println!("`heap-address-space` must be at least as large as `max-heap-size`");
        println!("{}", matches.usage());
        std::process::exit(1);
    }

    let stack_size = value_t!(matches, "stack_size", Size)
        .unwrap_or_else(|e| e.exit())
        .into::<Byte>()
        .value() as usize;

    let limits = Limits {
        heap_memory_size,
        heap_address_space_size,
        stack_size,
        globals_size: 0, // calculated from module
    };

    let guest_args = matches
        .values_of("guest_args")
        .map(|vals| vals.collect())
        .unwrap_or(vec![]);

    let config = Config {
        lucet_module,
        guest_args,
        entrypoint,
        preopen_dirs,
        limits,
    };

    run(config)
}

fn run(config: Config) {
    lucet_wasi::hostcalls::ensure_linked();
    let exitcode = {
        // doing all of this in a block makes sure everything gets dropped before exiting
        let module = DlModule::load(&config.lucet_module).expect("module can be loaded");
        let min_globals_size = module.globals().len() * std::mem::size_of::<u64>();
        let globals_size = ((min_globals_size + 4096 - 1) / 4096) * 4096;

        let region = MmapRegion::create(
            1,
            &Limits {
                globals_size,
                ..config.limits
            },
        )
        .expect("region can be created");

        // put the path to the module on the front for argv[0]
        let args = std::iter::once(config.lucet_module)
            .chain(config.guest_args.into_iter())
            .collect::<Vec<&str>>();
        let mut ctx = WasiCtxBuilder::new().args(&args).inherit_env();
        for (dir, guest_path) in config.preopen_dirs {
            ctx = ctx.preopened_dir(dir, guest_path);
        }
        let mut inst = region
            .new_instance_builder(module as Arc<dyn Module>)
            .with_embed_ctx(ctx.build().expect("WASI ctx can be created"))
            .build()
            .expect("instance can be created");

        match inst.run(config.entrypoint.as_bytes(), &[]) {
            // normal termination implies 0 exit code
            Ok(_) => 0,
            Err(lucet_runtime::Error::RuntimeTerminated(
                lucet_runtime::TerminationDetails::Provided(any),
            )) => *any
                .downcast_ref::<lucet_wasi::host::__wasi_exitcode_t>()
                .expect("termination yields an exitcode"),
            Err(e) => panic!("lucet-wasi runtime error: {}", e),
        }
    };
    std::process::exit(exitcode as i32);
}
<|endoftext|>


<commit_before>import c = ctypes;

export init_flag;
export init_timer, init_audio, init_video, init_cdrom, init_joystick,
       init_noparachute, init_eventthread, init_everything;
export init, init_subsystem, quit_subsystem, quit;
export was_init;
export get_error, set_error;

enum init_flag {
    init_timer       = 0x00000001,
    init_audio       = 0x00000010,
    init_video       = 0x00000020,
    init_cdrom       = 0x00000100,
    init_joystick    = 0x00000200,
    init_noparachute = 0x00100000,
    init_eventthread = 0x01000000,
    init_everything  = 0x0000FFFF,
}

fn init(flags: [init_flag]) -> int {
    SDL::SDL_Init(util::flags_to_bitfield(flags)) as int
}

fn init_subsystem(flags: [init_flag]) -> int {
    SDL::SDL_InitSubSystem(util::flags_to_bitfield(flags)) as int
}

fn quit_subsystem(flags: [init_flag]) {
    SDL::SDL_QuitSubSystem(util::flags_to_bitfield(flags))
}

fn quit() {
    SDL::SDL_Quit()
}

fn was_init(flags: [init_flag]) -> [init_flag] {
    let bitflags = SDL::SDL_WasInit(util::flags_to_bitfield(flags));
    let all_flags = [
        init_timer,
        init_audio,
        init_video,
        init_cdrom,
        init_joystick
    ];
    vec::foldl([], all_flags) {|vecflags, flag|
        if bitflags & (flag as c::c_int) != 0 as c::c_int {
            vecflags + [flag]
        } else {
            vecflags
        }
    }
}

fn get_error() -> str unsafe {
    let cstr = SDL::SDL_GetError();
    // FIXME: Converting sbuf to *c_char
    let cstr = unsafe::reinterpret_cast(cstr);
    str::from_cstr(cstr)
}

fn set_error(s: str) {
    str::as_buf(s) {|buf|
        // FIXME: Converting sbuf to *c_char
        let buf = unsafe { unsafe::reinterpret_cast(buf) };
        SDL::SDL_SetError(buf)
    }
}

mod util {
    fn flags_to_bitfield(flags: [init_flag]) -> u32 {
        vec::foldl(0u32, flags) {|flags, flag|
            flags | flag as u32
        }
    }
}

native mod SDL {
    fn SDL_Init(flags: u32) -> c::c_int;
    fn SDL_InitSubSystem(flags: u32) -> c::c_int;
    fn SDL_QuitSubSystem(flags: u32);
    fn SDL_Quit();
    fn SDL_WasInit(flags: u32) -> c::c_int;
    fn SDL_GetError() -> *c::c_char;
    // FIXME: This is actually a varargs call
    fn SDL_SetError(fmt: *c::c_char);
}

#[test]
fn test_init() {
    init([init_everything]);
    quit();
}

#[test]
fn test_was_init() {
    init([init_timer, init_video]);
    // FIXME
    quit();
}<commit_msg>Add some tests<commit_after>import c = ctypes;

export init_flag;
export init_timer, init_audio, init_video, init_cdrom, init_joystick,
       init_noparachute, init_eventthread, init_everything;
export init, init_subsystem, quit_subsystem, quit;
export was_init;
export get_error, set_error;

enum init_flag {
    init_timer       = 0x00000001,
    init_audio       = 0x00000010,
    init_video       = 0x00000020,
    init_cdrom       = 0x00000100,
    init_joystick    = 0x00000200,
    init_noparachute = 0x00100000,
    init_eventthread = 0x01000000,
    init_everything  = 0x0000FFFF,
}

fn init(flags: [init_flag]) -> int {
    SDL::SDL_Init(util::flags_to_bitfield(flags)) as int
}

fn init_subsystem(flags: [init_flag]) -> int {
    SDL::SDL_InitSubSystem(util::flags_to_bitfield(flags)) as int
}

fn quit_subsystem(flags: [init_flag]) {
    SDL::SDL_QuitSubSystem(util::flags_to_bitfield(flags))
}

fn quit() {
    SDL::SDL_Quit()
}

fn was_init(flags: [init_flag]) -> [init_flag] {
    let bitflags = SDL::SDL_WasInit(util::flags_to_bitfield(flags));
    let all_flags = [
        init_timer,
        init_audio,
        init_video,
        init_cdrom,
        init_joystick
    ];
    vec::foldl([], all_flags) {|vecflags, flag|
        if bitflags & (flag as c::c_int) != 0 as c::c_int {
            vecflags + [flag]
        } else {
            vecflags
        }
    }
}

fn get_error() -> str unsafe {
    let cstr = SDL::SDL_GetError();
    // FIXME: Converting sbuf to *c_char
    let cstr = unsafe::reinterpret_cast(cstr);
    str::from_cstr(cstr)
}

fn set_error(s: str) {
    str::as_buf(s) {|buf|
        // FIXME: Converting sbuf to *c_char
        let buf = unsafe { unsafe::reinterpret_cast(buf) };
        SDL::SDL_SetError(buf)
    }
}

mod util {
    fn flags_to_bitfield(flags: [init_flag]) -> u32 {
        vec::foldl(0u32, flags) {|flags, flag|
            flags | flag as u32
        }
    }
}

native mod SDL {
    fn SDL_Init(flags: u32) -> c::c_int;
    fn SDL_InitSubSystem(flags: u32) -> c::c_int;
    fn SDL_QuitSubSystem(flags: u32);
    fn SDL_Quit();
    fn SDL_WasInit(flags: u32) -> c::c_int;
    fn SDL_GetError() -> *c::c_char;
    // FIXME: This is actually a varargs call
    fn SDL_SetError(fmt: *c::c_char);
}

#[test]
fn test_everything() {
    init([init_everything]);
    run_tests([
        test_was_init,
        test_set_error
    ]);
    quit();
}

#[cfg(test)]
fn run_tests(tests: [fn()]) {
    vec::iter(tests) {|test| test()}
}

#[cfg(test)]
fn test_was_init() {
    assert vec::contains(was_init([init_timer]), init_timer);
}

#[cfg(test)]
fn test_set_error() {
    set_error("test");
    assert get_error() == "test";
}<|endoftext|>


<commit_before>use std::io::process::{Command,ProcessOutput};

fn main() {
    // initial command "rustc"
    let mut cmd = Command::new("rustc");
    // append the "--version" flag to the command
    cmd.arg("--version");

    // the `output` method will spawn `rustc --version`, wait until the process
    // finishes and return the output of the process
    match cmd.output() {
        Err(why) => fail!("couldn't spawn rustc: {}", why.desc),
        // destructure the ProcessOutput struct
        Ok(ProcessOutput { error: error, output: output, status: status }) => {
            // check if process succeeded, i.e. the exit code was 0
            if status.success() {
                // output has type `Vec<u8>`
                // convert to UTF-8 String (this operation could fail)
                let s = String::from_utf8(output).unwrap();

                print!("rustc succeeded and stdout was:\n{}", s);
            } else {
                // error also has type `Vec<u8>`
                let s = String::from_utf8(error).unwrap();

                print!("rustc succeeded and stderr was:\n{}", s);
            }
        },
    }
}
<commit_msg>process: fix copy/paste typo<commit_after>use std::io::process::{Command,ProcessOutput};

fn main() {
    // initial command "rustc"
    let mut cmd = Command::new("rustc");
    // append the "--version" flag to the command
    cmd.arg("--version");

    // the `output` method will spawn `rustc --version`, wait until the process
    // finishes and return the output of the process
    match cmd.output() {
        Err(why) => fail!("couldn't spawn rustc: {}", why.desc),
        // destructure the ProcessOutput struct
        Ok(ProcessOutput { error: error, output: output, status: status }) => {
            // check if process succeeded, i.e. the exit code was 0
            if status.success() {
                // output has type `Vec<u8>`
                // convert to UTF-8 String (this operation could fail)
                let s = String::from_utf8(output).unwrap();

                print!("rustc succeeded and stdout was:\n{}", s);
            } else {
                // error also has type `Vec<u8>`
                let s = String::from_utf8(error).unwrap();

                print!("rustc failed and stderr was:\n{}", s);
            }
        },
    }
}
<|endoftext|>


<commit_before>use inner::logger::{Verbosity, log_fatal, log_verbose, log_error};
use std::path::Path;
use std::fs::{create_dir, create_dir_all, remove_dir, remove_file};
use std::fs::File;
use std::io::prelude::*;
use std::env::current_dir;
use std::fmt::Display;
use std::io;
use git2::Repository;
use std::ffi::OsStr;

pub fn new(name: &str, is_lib: bool, verb: &Verbosity) {
    let path = Path::new(name);
    let current_dir = match current_dir() {
        Ok(path_buf) => path_buf,
        Err(e) => {
            log_fatal(e, verb);
            return
        },
    };

    if path.exists() {
        log_fatal(format!("the directory `{}` already exists in {:?}", name, current_dir), verb)
    }

    match create_dir_all(path.join("vendor")) {
        Ok(_) => {
            log_verbose("Create project", name, verb)
        },
        Err(e) => log_fatal(e, verb),
    }

    let content;
    let go_file;
    if is_lib {
        content = format!("package {}\n\n", name);
        go_file = format!("{}.go", name);
    } else {
        content = String::from("package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello, World!\")\n}\n\n");
        go_file = String::from("main.go");
    };

    match File::create(path.join(go_file.as_str())) {
        Ok(mut file) => {
            match file.write_all(content.as_bytes()) {
                Ok(_) => log_verbose("Create file", go_file, verb),
                Err(e) => delete_new_project(e, path, current_dir.as_path(), verb),
            };
        },
        Err(e) => delete_new_project(e, path, current_dir.as_path(), verb),
    }

    match create_json(path.join("rubigo.json"), name) {
        Ok(_) => log_verbose("Create file", "rubigo.json", verb),
        Err(e) => delete_new_project(e, path, current_dir.as_path(), verb),
    }

    match Repository::init(path) {
        Ok(repo) => log_verbose("Initialize git", match repo.workdir() {
            Some(repo_path) => match repo_path.to_str() {
                Some(repo_path_str) => repo_path_str,
                None => "unknown",
            },
            None => "unknown",
        }, verb),
        Err(e) => delete_new_project(e, path, current_dir.as_path(), verb),
    }

    log_verbose("Done", "Rubigo project has been created", verb)
}

pub fn init(verb: &Verbosity) {
    let json_path = Path::new("rubigo.json");
    if json_path.exists() {
        log_fatal("Rubigo project has already been initialized", verb)
    } else {
        match create_json(json_path, match json_path.parent() {
            Some(folder) => folder.file_name().unwrap_or(OsStr::new("unknown")),
            None => OsStr::new("unknown"),
        }.to_str().unwrap_or("unknown")) {
            Ok(_) => {
                log_verbose("Create file", "rubigo.json", verb);
                let lock_path = Path::new("rubigo.lock");
                if lock_path.exists() {
                    match remove_file(lock_path) {
                        Ok(_) => log_verbose("Delete file", "rubigo.lock", verb),
                        Err(e) => delete_init_project(e, json_path, verb),
                    }
                }
            },
            Err(e) => delete_init_project(e, json_path, verb),
        }
    }

    let vendor_path = Path::new("vendor");
    if !vendor_path.exists() {
        match create_dir(vendor_path) {
            Ok(_) => log_verbose("Create directory", "vendor", verb),
            Err(e) => delete_init_project(e, json_path, verb),
        }
    } else {
        log_verbose("Check directory", "vendor", verb)
        // TODO check for packages
    }

    log_verbose("Done", "Rubigo project has been initialized", verb)
}

fn delete_init_project<T: Display>(err: T, path: &Path, verb: &Verbosity) {
    match remove_file(path) {
        Ok(_) => log_verbose("Delete file", "rubigo.json", verb),
        _ => (),
    }
    log_fatal(err, verb)
}

fn delete_new_project<T: Display>(err: T, path: &Path, current_dir: &Path, verb: &Verbosity) {
    match remove_dir(path) {
        Ok(_) => log_verbose("Delete project", current_dir.to_str().unwrap_or("unknown"), verb),
        Err(e) => log_error(e, verb),
    }
    log_fatal(err, verb)
}

fn create_json<P: AsRef<Path>>(json_path: P, project_name: &str) -> io::Result<()> {
    let data = object!{
        "info" => object!{
            "name" => project_name
        },
        "packages" => object!{
            "git" => array![],
            "local" => array![],
            "global" => array![]
        },
        "defaults" => object!{}
    };

    match File::create(json_path) {
        Ok(mut file) => {
            match file.write_all(format!("{:#}", data).as_bytes()) {
                Ok(_) => (),
                Err(e) => return Err(e),
            }
        },
        Err(e) => return Err(e),
    }

    Ok(())
}
<commit_msg>Replace remove_dir with remove_dir_all<commit_after>use inner::logger::{Verbosity, log_fatal, log_verbose, log_error};
use std::path::Path;
use std::fs::{create_dir, create_dir_all, remove_dir_all, remove_file};
use std::fs::File;
use std::io::prelude::*;
use std::env::current_dir;
use std::fmt::Display;
use std::io;
use git2::Repository;
use std::ffi::OsStr;

pub fn new(name: &str, is_lib: bool, verb: &Verbosity) {
    let path = Path::new(name);
    let current_dir = match current_dir() {
        Ok(path_buf) => path_buf,
        Err(e) => {
            log_fatal(e, verb);
            return
        },
    };

    if path.exists() {
        log_fatal(format!("the directory `{}` already exists in {:?}", name, current_dir), verb)
    }

    match create_dir_all(path.join("vendor")) {
        Ok(_) => {
            log_verbose("Create project", name, verb)
        },
        Err(e) => log_fatal(e, verb),
    }

    let content;
    let go_file;
    if is_lib {
        content = format!("package {}\n\n", name);
        go_file = format!("{}.go", name);
    } else {
        content = String::from("package main\n\nimport \"fmt\"\n\nfunc main() {\n\tfmt.Println(\"Hello, World!\")\n}\n\n");
        go_file = String::from("main.go");
    };

    match File::create(path.join(go_file.as_str())) {
        Ok(mut file) => {
            match file.write_all(content.as_bytes()) {
                Ok(_) => log_verbose("Create file", go_file, verb),
                Err(e) => delete_new_project(e, path, current_dir.as_path(), verb),
            };
        },
        Err(e) => delete_new_project(e, path, current_dir.as_path(), verb),
    }

    match create_json(path.join("rubigo.json"), name) {
        Ok(_) => log_verbose("Create file", "rubigo.json", verb),
        Err(e) => delete_new_project(e, path, current_dir.as_path(), verb),
    }

    match Repository::init(path) {
        Ok(repo) => log_verbose("Initialize git", match repo.workdir() {
            Some(repo_path) => match repo_path.to_str() {
                Some(repo_path_str) => repo_path_str,
                None => "unknown",
            },
            None => "unknown",
        }, verb),
        Err(e) => delete_new_project(e, path, current_dir.as_path(), verb),
    }

    log_verbose("Done", "Rubigo project has been created", verb)
}

pub fn init(verb: &Verbosity) {
    let json_path = Path::new("rubigo.json");
    if json_path.exists() {
        log_fatal("Rubigo project has already been initialized", verb)
    } else {
        match create_json(json_path, match json_path.parent() {
            Some(folder) => folder.file_name().unwrap_or(OsStr::new("unknown")),
            None => OsStr::new("unknown"),
        }.to_str().unwrap_or("unknown")) {
            Ok(_) => {
                log_verbose("Create file", "rubigo.json", verb);
                let lock_path = Path::new("rubigo.lock");
                if lock_path.exists() {
                    match remove_file(lock_path) {
                        Ok(_) => log_verbose("Delete file", "rubigo.lock", verb),
                        Err(e) => delete_init_project(e, json_path, verb),
                    }
                }
            },
            Err(e) => delete_init_project(e, json_path, verb),
        }
    }

    let vendor_path = Path::new("vendor");
    if !vendor_path.exists() {
        match create_dir(vendor_path) {
            Ok(_) => log_verbose("Create directory", "vendor", verb),
            Err(e) => delete_init_project(e, json_path, verb),
        }
    } else {
        log_verbose("Check directory", "vendor", verb)
        // TODO check for packages
    }

    log_verbose("Done", "Rubigo project has been initialized", verb)
}

fn delete_init_project<T: Display>(err: T, path: &Path, verb: &Verbosity) {
    match remove_file(path) {
        Ok(_) => log_verbose("Delete file", "rubigo.json", verb),
        _ => (),
    }
    log_fatal(err, verb)
}

fn delete_new_project<T: Display>(err: T, path: &Path, current_dir: &Path, verb: &Verbosity) {
    match remove_dir_all(path) {
        Ok(_) => log_verbose("Delete project", current_dir.to_str().unwrap_or("unknown"), verb),
        Err(e) => log_error(e, verb),
    }
    log_fatal(err, verb)
}

fn create_json<P: AsRef<Path>>(json_path: P, project_name: &str) -> io::Result<()> {
    let data = object!{
        "info" => object!{
            "name" => project_name
        },
        "packages" => object!{
            "git" => array![],
            "local" => array![],
            "global" => array![]
        },
        "defaults" => object!{}
    };

    match File::create(json_path) {
        Ok(mut file) => {
            match file.write_all(format!("{:#}", data).as_bytes()) {
                Ok(_) => (),
                Err(e) => return Err(e),
            }
        },
        Err(e) => return Err(e),
    }

    Ok(())
}
<|endoftext|>


<commit_before>// Writing tests using the paste! macro.
//
// Eli Bendersky [https://eli.thegreenplace.net]
// This code is in the public domain.

macro_rules! calculator_tests {
    ($($name:ident: $type:ty,)*) => {
    $(
        paste! {
        #[test]
        fn [<test_ $name>]() {
            let c = <$type>::new();
            assert_eq!(c.add(2, 3), 5);
            assert_eq!(c.add(10, 43), 53);
        }

        #[test]
        fn [<test_ $name _feature1>]() {
            let c = <$type>::new();
            assert_eq!(c.add(6, 9), 15);
        }
        } // end paste
    )*
    }
}

#[cfg(test)]
mod tests {
    use crate::calculator::{Bar, Calculator, Foo};
    use paste::paste;

    calculator_tests! {
        foo: Foo,
        bar: Bar,
    }
}
<commit_msg>Clean up whitespace<commit_after>// Writing tests using the paste! macro.
//
// Eli Bendersky [https://eli.thegreenplace.net]
// This code is in the public domain.
macro_rules! calculator_tests {
    ($($name:ident: $type:ty,)*) => {
    $(
        paste! {
        #[test]
        fn [<test_ $name>]() {
            let c = <$type>::new();
            assert_eq!(c.add(2, 3), 5);
            assert_eq!(c.add(10, 43), 53);
        }

        #[test]
        fn [<test_ $name _feature1>]() {
            let c = <$type>::new();
            assert_eq!(c.add(6, 9), 15);
        }
        } // end paste
    )*
    }
}

#[cfg(test)]
mod tests {
    use crate::calculator::{Bar, Calculator, Foo};
    use paste::paste;

    calculator_tests! {
        foo: Foo,
        bar: Bar,
    }
}
<|endoftext|>


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

// A simple wrapper around a build_script execution to generate file to reuse
// by rust_library/rust_binary.
extern crate cargo_build_script_output_parser;

use cargo_build_script_output_parser::{BuildScriptOutput, CompileAndLinkFlags};
use std::collections::BTreeMap;
use std::env;
use std::ffi::OsString;
use std::fs::{create_dir_all, read_to_string, write};
use std::path::Path;
use std::process::Command;

fn main() -> Result<(), String> {
    // We use exec_root.join rather than std::fs::canonicalize, to avoid resolving symlinks, as
    // some execution strategies and remote execution environments may use symlinks in ways which
    // canonicalizing them may break them, e.g. by having input files be symlinks into a /cas
    // directory - resolving these may cause tools which inspect $0, or try to resolve files
    // relative to themselves, to fail.
    let exec_root = env::current_dir().expect("Failed to get current directory");

    let mut args = env::args().skip(1);
    let manifest_dir_env = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR was not set");
    let rustc_env = env::var("RUSTC").expect("RUSTC was not set");
    let manifest_dir = exec_root.join(&manifest_dir_env);
    let rustc = exec_root.join(&rustc_env);

    // TODO: we should consider an alternative to positional arguments.
    match (args.next(), args.next(), args.next(), args.next(), args.next(), args.next(), args.next(), args.next()) {
        (Some(progname), Some(crate_name), Some(crate_links), Some(out_dir), Some(envfile), Some(flagfile), Some(linkflags), Some(depenvfile)) => {
            let out_dir_abs = exec_root.join(&out_dir);
            // For some reason Google's RBE does not create the output directory, force create it.
            create_dir_all(&out_dir_abs).expect(&format!("Failed to make output directory: {:?}", out_dir_abs));

            let target_env_vars = get_target_env_vars(&rustc_env).expect("Error getting target env vars from rustc");

            let mut command = Command::new(exec_root.join(&progname));
            command
                .current_dir(&manifest_dir)
                .envs(target_env_vars)
                .env("OUT_DIR", out_dir_abs)
                .env("CARGO_MANIFEST_DIR", manifest_dir)
                .env("RUSTC", rustc)
                .env("RUST_BACKTRACE", "full");

            while let Some(dep_env_path) = args.next() {
                if let Ok(contents) = read_to_string(dep_env_path) {
                    for line in contents.split('\n') {
                        // split on empty contents will still produce a single empty string in iterable.
                        if line.is_empty() {
                            continue;
                        }
                        let mut key_val = line.splitn(2, '=');
                        match (key_val.next(), key_val.next()) {
                            (Some(key), Some(value)) => {
                                command.env(key, value.replace("${pwd}", &exec_root.to_string_lossy()));
                            }
                            _ => {
                                return Err("error: Wrong environment file format, should not happen".to_owned())
                            }
                        }
                    }
                } else {
                    return Err("error: Dependency environment file unreadable".to_owned())
                }
            }

            if let Some(cc_path) = env::var_os("CC") {
                command.env("CC", absolutify(&exec_root, cc_path));
            }

            if let Some(ar_path) = env::var_os("AR") {
                // The default OSX toolchain uses libtool as ar_executable not ar.
                // This doesn't work when used as $AR, so simply don't set it - tools will probably fall back to
                // /usr/bin/ar which is probably good enough.
                if Path::new(&ar_path).file_name() == Some("libtool".as_ref()) {
                    command.env_remove("AR");
                } else {
                    command.env("AR", absolutify(&exec_root, ar_path));
                }
            }

            // replace env vars with a ${pwd} prefix with the exec_root
            for (key, value) in env::vars() {
                let exec_root_str = exec_root.to_str().expect("exec_root not in utf8");
                if value.contains("${pwd}") {
                    env::set_var(key, value.replace("${pwd}", exec_root_str));
                }
            }

            let output = BuildScriptOutput::from_command(&mut command).map_err(|exit_code| {
                format!(
                    "Build script process failed{}",
                    if let Some(exit_code) = exit_code {
                        format!(" with exit code {}", exit_code)
                    } else {
                        String::new()
                    }
                )
            })?;

            // The right way to set the dep env var is to use the links attribute from the
            // Cargo.toml, but cargo_build_script didn't used to have a `links` attribute, so for
            // backward-compatibility reasons, try to infer it from the name of the crate.
            // TODO: remove this backward-compatibility fallback in next major version.
            let crate_links = match crate_links.as_ref() {
                "" => {
                    const SYS_CRATE_SUFFIX: &str = "-sys";
                    if crate_name.ends_with(SYS_CRATE_SUFFIX) {
                        crate_name
                            .split_at(crate_name.rfind(SYS_CRATE_SUFFIX).unwrap())
                            .0
                    } else {
                        &crate_name
                    }
                },
                crate_links => crate_links,
            };

            write(&envfile, BuildScriptOutput::to_env(&output, &exec_root.to_string_lossy()).as_bytes())
                .expect(&format!("Unable to write file {:?}", envfile));
            write(&depenvfile, BuildScriptOutput::to_dep_env(&output, crate_links, &exec_root.to_string_lossy()).as_bytes())
                .expect(&format!("Unable to write file {:?}", depenvfile));

            let CompileAndLinkFlags { compile_flags, link_flags } = BuildScriptOutput::to_flags(&output, &exec_root.to_string_lossy());

            write(&flagfile, compile_flags.as_bytes())
                .expect(&format!("Unable to write file {:?}", flagfile));
            write(&linkflags, link_flags.as_bytes())
                .expect(&format!("Unable to write file {:?}", linkflags));
            Ok(())
        }
        _ => {
            Err("Usage: $0 progname crate_name out_dir envfile flagfile linkflagfile depenvfile [arg1...argn]".to_owned())
        }
    }
}

fn get_target_env_vars<P: AsRef<Path>>(rustc: &P) -> Result<BTreeMap<String, String>, String> {
    // As done by Cargo when constructing a cargo::core::compiler::build_context::target_info::TargetInfo.
    let output = Command::new(rustc.as_ref())
        .arg("--print=cfg")
        .output()
        .map_err(|err| format!("Error running rustc to get target information: {}", err))?;
    if !output.status.success() {
        return Err(format!(
            "Error running rustc to get target information: {:?}",
            output
        ));
    }
    let stdout = std::str::from_utf8(&output.stdout)
        .map_err(|err| format!("Non-UTF8 stdout from rustc: {:?}", err))?;

    let mut values = BTreeMap::new();

    for line in stdout.lines() {
        if line.starts_with("target_") && line.contains('=') {
            let mut parts = line.splitn(2, '=');
            // UNWRAP: Verified that line contains = and split into exactly 2 parts.
            let key = parts.next().unwrap();
            let value = parts.next().unwrap();
            if value.starts_with('"') && value.ends_with('"') && value.len() >= 2 {
                values
                    .entry(key)
                    .or_insert(vec![])
                    .push(value[1..(value.len() - 1)].to_owned());
            }
        }
    }

    Ok(values
        .into_iter()
        .map(|(key, value)| (format!("CARGO_CFG_{}", key.to_uppercase()), value.join(",")))
        .collect())
}

fn absolutify(root: &Path, maybe_relative: OsString) -> OsString {
    let path = Path::new(&maybe_relative);
    if path.is_relative() {
        root.join(path).into_os_string()
    } else {
        maybe_relative
    }
}
<commit_msg>use target platform for CARGO_CFG_TARGET_* (#494)<commit_after>// Copyright 2018 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// A simple wrapper around a build_script execution to generate file to reuse
// by rust_library/rust_binary.
extern crate cargo_build_script_output_parser;

use cargo_build_script_output_parser::{BuildScriptOutput, CompileAndLinkFlags};
use std::collections::BTreeMap;
use std::env;
use std::ffi::OsString;
use std::fs::{create_dir_all, read_to_string, write};
use std::path::Path;
use std::process::Command;

fn main() -> Result<(), String> {
    // We use exec_root.join rather than std::fs::canonicalize, to avoid resolving symlinks, as
    // some execution strategies and remote execution environments may use symlinks in ways which
    // canonicalizing them may break them, e.g. by having input files be symlinks into a /cas
    // directory - resolving these may cause tools which inspect $0, or try to resolve files
    // relative to themselves, to fail.
    let exec_root = env::current_dir().expect("Failed to get current directory");

    let mut args = env::args().skip(1);
    let manifest_dir_env = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR was not set");
    let rustc_env = env::var("RUSTC").expect("RUSTC was not set");
    let manifest_dir = exec_root.join(&manifest_dir_env);
    let rustc = exec_root.join(&rustc_env);

    // TODO: we should consider an alternative to positional arguments.
    match (args.next(), args.next(), args.next(), args.next(), args.next(), args.next(), args.next(), args.next()) {
        (Some(progname), Some(crate_name), Some(crate_links), Some(out_dir), Some(envfile), Some(flagfile), Some(linkflags), Some(depenvfile)) => {
            let out_dir_abs = exec_root.join(&out_dir);
            // For some reason Google's RBE does not create the output directory, force create it.
            create_dir_all(&out_dir_abs).expect(&format!("Failed to make output directory: {:?}", out_dir_abs));

            let target_env_vars = get_target_env_vars(&rustc_env).expect("Error getting target env vars from rustc");

            let mut command = Command::new(exec_root.join(&progname));
            command
                .current_dir(&manifest_dir)
                .envs(target_env_vars)
                .env("OUT_DIR", out_dir_abs)
                .env("CARGO_MANIFEST_DIR", manifest_dir)
                .env("RUSTC", rustc)
                .env("RUST_BACKTRACE", "full");

            while let Some(dep_env_path) = args.next() {
                if let Ok(contents) = read_to_string(dep_env_path) {
                    for line in contents.split('\n') {
                        // split on empty contents will still produce a single empty string in iterable.
                        if line.is_empty() {
                            continue;
                        }
                        let mut key_val = line.splitn(2, '=');
                        match (key_val.next(), key_val.next()) {
                            (Some(key), Some(value)) => {
                                command.env(key, value.replace("${pwd}", &exec_root.to_string_lossy()));
                            }
                            _ => {
                                return Err("error: Wrong environment file format, should not happen".to_owned())
                            }
                        }
                    }
                } else {
                    return Err("error: Dependency environment file unreadable".to_owned())
                }
            }

            if let Some(cc_path) = env::var_os("CC") {
                command.env("CC", absolutify(&exec_root, cc_path));
            }

            if let Some(ar_path) = env::var_os("AR") {
                // The default OSX toolchain uses libtool as ar_executable not ar.
                // This doesn't work when used as $AR, so simply don't set it - tools will probably fall back to
                // /usr/bin/ar which is probably good enough.
                if Path::new(&ar_path).file_name() == Some("libtool".as_ref()) {
                    command.env_remove("AR");
                } else {
                    command.env("AR", absolutify(&exec_root, ar_path));
                }
            }

            // replace env vars with a ${pwd} prefix with the exec_root
            for (key, value) in env::vars() {
                let exec_root_str = exec_root.to_str().expect("exec_root not in utf8");
                if value.contains("${pwd}") {
                    env::set_var(key, value.replace("${pwd}", exec_root_str));
                }
            }

            let output = BuildScriptOutput::from_command(&mut command).map_err(|exit_code| {
                format!(
                    "Build script process failed{}",
                    if let Some(exit_code) = exit_code {
                        format!(" with exit code {}", exit_code)
                    } else {
                        String::new()
                    }
                )
            })?;

            // The right way to set the dep env var is to use the links attribute from the
            // Cargo.toml, but cargo_build_script didn't used to have a `links` attribute, so for
            // backward-compatibility reasons, try to infer it from the name of the crate.
            // TODO: remove this backward-compatibility fallback in next major version.
            let crate_links = match crate_links.as_ref() {
                "" => {
                    const SYS_CRATE_SUFFIX: &str = "-sys";
                    if crate_name.ends_with(SYS_CRATE_SUFFIX) {
                        crate_name
                            .split_at(crate_name.rfind(SYS_CRATE_SUFFIX).unwrap())
                            .0
                    } else {
                        &crate_name
                    }
                },
                crate_links => crate_links,
            };

            write(&envfile, BuildScriptOutput::to_env(&output, &exec_root.to_string_lossy()).as_bytes())
                .expect(&format!("Unable to write file {:?}", envfile));
            write(&depenvfile, BuildScriptOutput::to_dep_env(&output, crate_links, &exec_root.to_string_lossy()).as_bytes())
                .expect(&format!("Unable to write file {:?}", depenvfile));

            let CompileAndLinkFlags { compile_flags, link_flags } = BuildScriptOutput::to_flags(&output, &exec_root.to_string_lossy());

            write(&flagfile, compile_flags.as_bytes())
                .expect(&format!("Unable to write file {:?}", flagfile));
            write(&linkflags, link_flags.as_bytes())
                .expect(&format!("Unable to write file {:?}", linkflags));
            Ok(())
        }
        _ => {
            Err("Usage: $0 progname crate_name out_dir envfile flagfile linkflagfile depenvfile [arg1...argn]".to_owned())
        }
    }
}

fn get_target_env_vars<P: AsRef<Path>>(rustc: &P) -> Result<BTreeMap<String, String>, String> {
    // As done by Cargo when constructing a cargo::core::compiler::build_context::target_info::TargetInfo.
    let output = Command::new(rustc.as_ref())
        .arg("--print=cfg")
        .arg(format!(
            "--target={}",
            env::var("TARGET").expect("missing TARGET")
        ))
        .output()
        .map_err(|err| format!("Error running rustc to get target information: {}", err))?;
    if !output.status.success() {
        return Err(format!(
            "Error running rustc to get target information: {:?}",
            output
        ));
    }
    let stdout = std::str::from_utf8(&output.stdout)
        .map_err(|err| format!("Non-UTF8 stdout from rustc: {:?}", err))?;

    let mut values = BTreeMap::new();

    for line in stdout.lines() {
        if line.starts_with("target_") && line.contains('=') {
            let mut parts = line.splitn(2, '=');
            // UNWRAP: Verified that line contains = and split into exactly 2 parts.
            let key = parts.next().unwrap();
            let value = parts.next().unwrap();
            if value.starts_with('"') && value.ends_with('"') && value.len() >= 2 {
                values
                    .entry(key)
                    .or_insert(vec![])
                    .push(value[1..(value.len() - 1)].to_owned());
            }
        }
    }

    Ok(values
        .into_iter()
        .map(|(key, value)| (format!("CARGO_CFG_{}", key.to_uppercase()), value.join(",")))
        .collect())
}

fn absolutify(root: &Path, maybe_relative: OsString) -> OsString {
    let path = Path::new(&maybe_relative);
    if path.is_relative() {
        root.join(path).into_os_string()
    } else {
        maybe_relative
    }
}
<|endoftext|>


<commit_before>#![feature(core,libc,old_io)]

extern crate libusb_sys as ffi;
extern crate libc;

use libc::{c_int,c_uint,c_uchar};

use std::mem;
use std::slice;

use std::str::FromStr;
use std::old_io::{MemReader,Reader};

#[derive(Debug)]
struct Endpoint {
  config: u8,
  iface: u8,
  setting: u8,
  address: u8
}

fn main() {
  let args: Vec<String> = std::env::args().collect();

  if args.len() < 3 {
    println!("usage: show_device <vendor-id> <product-id>");
    return;
  }

  let vid: u16 = FromStr::from_str(args[1].as_slice()).unwrap();
  let pid: u16 = FromStr::from_str(args[2].as_slice()).unwrap();

  let mut context: *mut ::ffi::libusb_context = unsafe { mem::uninitialized() };
  let mut device_list: *const *mut ::ffi::libusb_device = unsafe { mem::uninitialized() };

  match unsafe { ::ffi::libusb_init(&mut context) } {
    0 => (),
    e => panic!("libusb_init: {}", e)
  };

  let handle = unsafe { ::ffi::libusb_open_device_with_vid_pid(context, vid, pid) };

  if !handle.is_null() {
    match unsafe { ::ffi::libusb_reset_device(handle) } {
      0 => {
        unsafe { ::ffi::libusb_set_auto_detach_kernel_driver(handle, 0) };

        let device = unsafe { ::ffi::libusb_get_device(handle) };
        unsafe { ::ffi::libusb_ref_device(device) };

        if unsafe { ::ffi::libusb_get_device_list(context, &mut device_list) } >= 0 {
          print_device_tree(device);
          println!("");

          unsafe { ::ffi::libusb_free_device_list(device_list, 1) };
        }

        let languages = get_language_ids(handle);
        println!("Supported languages: {:?}", languages);

        let mut active_config: c_int = unsafe { mem::uninitialized() };
        match unsafe { ::ffi::libusb_get_configuration(handle, &mut active_config) } {
          0 => println!("Active configuration: {}", active_config),
          e => println!("libusb_get_configuration: {}", e)
        }
        println!("");

        match find_readable_endpoint(device, ::ffi::LIBUSB_TRANSFER_TYPE_INTERRUPT) {
          Some(ep) => read_endpoint(handle, device, ep, ::ffi::LIBUSB_TRANSFER_TYPE_INTERRUPT),
          None => println!("No readable interrupt endpoint")
        }
        println!("");

        match find_readable_endpoint(device, ::ffi::LIBUSB_TRANSFER_TYPE_BULK) {
          Some(ep) => read_endpoint(handle, device, ep, ::ffi::LIBUSB_TRANSFER_TYPE_BULK),
          None => println!("No readable bulk endpoint")
        }

        unsafe { ::ffi::libusb_unref_device(device) };
      },
      e => println!("libusb_reset_device: {}", e)
    }

    unsafe { ::ffi::libusb_close(handle) };
  }

  unsafe { ::ffi::libusb_exit(context) };
}

fn print_device_tree(device: *mut ::ffi::libusb_device) -> usize {
  if device.is_null() {
    return 0;
  }

  let parent = unsafe { ::ffi::libusb_get_parent(device) };
  let depth = print_device_tree(parent);

  for _ in (0..depth) {
    print!("  ");
  }

  let bus = unsafe { ::ffi::libusb_get_bus_number(device) };
  let address = unsafe { ::ffi::libusb_get_device_address(device) };

  println!("Bus {:03} Device {:03}", bus, address);

  return depth + 1;
}

fn get_language_ids(handle: *mut ::ffi::libusb_device_handle) -> Vec<u16> {
  let mut buf = Vec::<u8>::with_capacity(255);
  let len = unsafe { ::ffi::libusb_get_string_descriptor(handle, 0, 0, buf.as_slice().as_ptr() as *mut c_uchar, buf.capacity() as c_int) };

  let mut languages = Vec::<u16>::new();

  if len >= 0 {
    unsafe { buf.set_len(len as usize) };

    if buf.len() >= 2 {
      let num_languages = (buf.len() - 2) / 2;
      languages.reserve(num_languages);

      let mut reader = MemReader::new(buf);

      match reader.read_le_u16() {
        Ok(_) => (),
        Err(_) => return languages
      }

      for _ in (0..num_languages) {
        match reader.read_le_u16() {
          Ok(n) => languages.push(n),
          Err(_) => return languages
        }
      }
    }
  }
  else {
    println!("libusb_get_string_descriptor: {}", len);
  }

  languages
}

fn find_readable_endpoint(device: *mut ::ffi::libusb_device, transfer_type: u8) -> Option<Endpoint> {
  let mut device_descriptor: ::ffi::libusb_device_descriptor = unsafe { mem::uninitialized() };

  match unsafe { ::ffi::libusb_get_device_descriptor(device, &mut device_descriptor) } {
    0 => {
      for i in (0..device_descriptor.bNumConfigurations) {
        let mut config_ptr: *const ::ffi::libusb_config_descriptor = unsafe { mem::uninitialized() };

        match unsafe { ::ffi::libusb_get_config_descriptor(device, i, &mut config_ptr) } {
          0 => {
            let config_descriptor = unsafe { config_ptr.as_ref() }.unwrap();
            let interfaces = unsafe { slice::from_raw_parts(config_descriptor.interface, config_descriptor.bNumInterfaces as usize) };

            for iface in interfaces {
              let settings = unsafe { slice::from_raw_parts(iface.altsetting, iface.num_altsetting as usize) };

              for iface_descriptor in settings {
                let endpoints = unsafe { slice::from_raw_parts(iface_descriptor.endpoint, iface_descriptor.bNumEndpoints as usize) };

                for endpoint_descriptor in endpoints {
                  let is_input = endpoint_descriptor.bEndpointAddress & ::ffi::LIBUSB_ENDPOINT_DIR_MASK == ::ffi::LIBUSB_ENDPOINT_IN;
                  let matches_type = endpoint_descriptor.bmAttributes & ::ffi::LIBUSB_TRANSFER_TYPE_MASK == transfer_type;

                  if is_input && matches_type {
                    return Some(Endpoint {
                      config: config_descriptor.bConfigurationValue,
                      iface: iface_descriptor.bInterfaceNumber,
                      setting: iface_descriptor.bAlternateSetting,
                      address: endpoint_descriptor.bEndpointAddress
                    });
                  }
                }
              }
            }
          },
          e => println!("libusb_get_config_descriptor: {}", e)
        }
      }

      None
    },
    e => {
      println!("libusb_get_device_descriptor: {}", e);
      None
    }
  }
}

fn read_endpoint(handle: *mut ::ffi::libusb_device_handle, device: *mut ::ffi::libusb_device, endpoint: Endpoint, transfer_type: u8) {
  println!("Reading from endpoint: {:?}", endpoint);

  let has_kernel_driver = unsafe {
    if ::ffi::libusb_kernel_driver_active(handle, endpoint.iface as c_int) == 1 {
      match ::ffi::libusb_detach_kernel_driver(handle, endpoint.iface as c_int) {
        0 => (),
        e => println!("libusb_detach_kernel_driver: {}", e)
      }

      true
    }
    else {
      false
    }
  };

  println!(" - kernel driver? {}", has_kernel_driver);

  match unsafe { ::ffi::libusb_set_configuration(handle, endpoint.config as c_int) } {
    0 => {
      println!(" - max packet size: {}", unsafe { ::ffi::libusb_get_max_packet_size(device, endpoint.address as c_uchar) });
      println!(" - max iso packet size: {}", unsafe { ::ffi::libusb_get_max_iso_packet_size(device, endpoint.address as c_uchar) });

      match unsafe { ::ffi::libusb_claim_interface(handle, endpoint.iface as c_int) } {
        0 => {
          match unsafe { ::ffi::libusb_set_interface_alt_setting(handle, endpoint.iface as c_int, endpoint.setting as c_int) } {
            0 => {
              let mut vec = Vec::<u8>::with_capacity(256);
              let timeout: c_uint = 1000;

              let mut transferred: c_int = unsafe { mem::uninitialized() };

              match transfer_type {
                ::ffi::LIBUSB_TRANSFER_TYPE_INTERRUPT => {
                  match unsafe { ::ffi::libusb_interrupt_transfer(handle, endpoint.address as c_uchar, vec.as_slice().as_ptr() as *mut c_uchar, vec.capacity() as c_int, &mut transferred, timeout) } {
                    0 => {
                      unsafe { vec.set_len(transferred as usize) };
                      println!(" - read: {:?}", vec);
                    },
                    e => println!("libusb_interrupt_transfer: {}", e)
                  }
                },
                ::ffi::LIBUSB_TRANSFER_TYPE_BULK => {
                  match unsafe { ::ffi::libusb_bulk_transfer(handle, endpoint.address as c_uchar, vec.as_slice().as_ptr() as *mut c_uchar, vec.capacity() as c_int, &mut transferred, timeout) } {
                    0 => {
                      unsafe { vec.set_len(transferred as usize) };
                      println!(" - read: {:?}", vec);
                    },
                    e => println!("libusb_interrupt_transfer: {}", e)
                  }
                },
                tt => println!(" - can't read endpoint with transfer type {}", tt)
              }
            },
            e => println!("libusb_set_interface_alt_setting: {}", e)
          }

          match unsafe { ::ffi::libusb_release_interface(handle, endpoint.iface as c_int) } {
            0 => (),
            e => println!("libusb_release_interface: {}", e)
          }
        },
        e => println!("libusb_claim_interface: {}", e)
      }
    },
    e => println!("libusb_set_configuration: {}", e)
  }

  if has_kernel_driver {
    match unsafe { ::ffi::libusb_attach_kernel_driver(handle, endpoint.iface as c_int) } {
      0 => (),
      e => println!("libusb_attach_kernel_driver: {}", e)
    }
  }
}
<commit_msg>replaces as_slice() in examples<commit_after>#![feature(core,libc,old_io,convert)]

extern crate libusb_sys as ffi;
extern crate libc;

use libc::{c_int,c_uint,c_uchar};

use std::mem;
use std::slice;

use std::str::FromStr;
use std::old_io::{MemReader,Reader};

#[derive(Debug)]
struct Endpoint {
  config: u8,
  iface: u8,
  setting: u8,
  address: u8
}

fn main() {
  let args: Vec<String> = std::env::args().collect();

  if args.len() < 3 {
    println!("usage: show_device <vendor-id> <product-id>");
    return;
  }

  let vid: u16 = FromStr::from_str(args[1].as_ref()).unwrap();
  let pid: u16 = FromStr::from_str(args[2].as_ref()).unwrap();

  let mut context: *mut ::ffi::libusb_context = unsafe { mem::uninitialized() };
  let mut device_list: *const *mut ::ffi::libusb_device = unsafe { mem::uninitialized() };

  match unsafe { ::ffi::libusb_init(&mut context) } {
    0 => (),
    e => panic!("libusb_init: {}", e)
  };

  let handle = unsafe { ::ffi::libusb_open_device_with_vid_pid(context, vid, pid) };

  if !handle.is_null() {
    match unsafe { ::ffi::libusb_reset_device(handle) } {
      0 => {
        unsafe { ::ffi::libusb_set_auto_detach_kernel_driver(handle, 0) };

        let device = unsafe { ::ffi::libusb_get_device(handle) };
        unsafe { ::ffi::libusb_ref_device(device) };

        if unsafe { ::ffi::libusb_get_device_list(context, &mut device_list) } >= 0 {
          print_device_tree(device);
          println!("");

          unsafe { ::ffi::libusb_free_device_list(device_list, 1) };
        }

        let languages = get_language_ids(handle);
        println!("Supported languages: {:?}", languages);

        let mut active_config: c_int = unsafe { mem::uninitialized() };
        match unsafe { ::ffi::libusb_get_configuration(handle, &mut active_config) } {
          0 => println!("Active configuration: {}", active_config),
          e => println!("libusb_get_configuration: {}", e)
        }
        println!("");

        match find_readable_endpoint(device, ::ffi::LIBUSB_TRANSFER_TYPE_INTERRUPT) {
          Some(ep) => read_endpoint(handle, device, ep, ::ffi::LIBUSB_TRANSFER_TYPE_INTERRUPT),
          None => println!("No readable interrupt endpoint")
        }
        println!("");

        match find_readable_endpoint(device, ::ffi::LIBUSB_TRANSFER_TYPE_BULK) {
          Some(ep) => read_endpoint(handle, device, ep, ::ffi::LIBUSB_TRANSFER_TYPE_BULK),
          None => println!("No readable bulk endpoint")
        }

        unsafe { ::ffi::libusb_unref_device(device) };
      },
      e => println!("libusb_reset_device: {}", e)
    }

    unsafe { ::ffi::libusb_close(handle) };
  }

  unsafe { ::ffi::libusb_exit(context) };
}

fn print_device_tree(device: *mut ::ffi::libusb_device) -> usize {
  if device.is_null() {
    return 0;
  }

  let parent = unsafe { ::ffi::libusb_get_parent(device) };
  let depth = print_device_tree(parent);

  for _ in (0..depth) {
    print!("  ");
  }

  let bus = unsafe { ::ffi::libusb_get_bus_number(device) };
  let address = unsafe { ::ffi::libusb_get_device_address(device) };

  println!("Bus {:03} Device {:03}", bus, address);

  return depth + 1;
}

fn get_language_ids(handle: *mut ::ffi::libusb_device_handle) -> Vec<u16> {
  let mut buf = Vec::<u8>::with_capacity(255);
  let len = unsafe { ::ffi::libusb_get_string_descriptor(handle, 0, 0, (&buf[..]).as_ptr() as *mut c_uchar, buf.capacity() as c_int) };

  let mut languages = Vec::<u16>::new();

  if len >= 0 {
    unsafe { buf.set_len(len as usize) };

    if buf.len() >= 2 {
      let num_languages = (buf.len() - 2) / 2;
      languages.reserve(num_languages);

      let mut reader = MemReader::new(buf);

      match reader.read_le_u16() {
        Ok(_) => (),
        Err(_) => return languages
      }

      for _ in (0..num_languages) {
        match reader.read_le_u16() {
          Ok(n) => languages.push(n),
          Err(_) => return languages
        }
      }
    }
  }
  else {
    println!("libusb_get_string_descriptor: {}", len);
  }

  languages
}

fn find_readable_endpoint(device: *mut ::ffi::libusb_device, transfer_type: u8) -> Option<Endpoint> {
  let mut device_descriptor: ::ffi::libusb_device_descriptor = unsafe { mem::uninitialized() };

  match unsafe { ::ffi::libusb_get_device_descriptor(device, &mut device_descriptor) } {
    0 => {
      for i in (0..device_descriptor.bNumConfigurations) {
        let mut config_ptr: *const ::ffi::libusb_config_descriptor = unsafe { mem::uninitialized() };

        match unsafe { ::ffi::libusb_get_config_descriptor(device, i, &mut config_ptr) } {
          0 => {
            let config_descriptor = unsafe { config_ptr.as_ref() }.unwrap();
            let interfaces = unsafe { slice::from_raw_parts(config_descriptor.interface, config_descriptor.bNumInterfaces as usize) };

            for iface in interfaces {
              let settings = unsafe { slice::from_raw_parts(iface.altsetting, iface.num_altsetting as usize) };

              for iface_descriptor in settings {
                let endpoints = unsafe { slice::from_raw_parts(iface_descriptor.endpoint, iface_descriptor.bNumEndpoints as usize) };

                for endpoint_descriptor in endpoints {
                  let is_input = endpoint_descriptor.bEndpointAddress & ::ffi::LIBUSB_ENDPOINT_DIR_MASK == ::ffi::LIBUSB_ENDPOINT_IN;
                  let matches_type = endpoint_descriptor.bmAttributes & ::ffi::LIBUSB_TRANSFER_TYPE_MASK == transfer_type;

                  if is_input && matches_type {
                    return Some(Endpoint {
                      config: config_descriptor.bConfigurationValue,
                      iface: iface_descriptor.bInterfaceNumber,
                      setting: iface_descriptor.bAlternateSetting,
                      address: endpoint_descriptor.bEndpointAddress
                    });
                  }
                }
              }
            }
          },
          e => println!("libusb_get_config_descriptor: {}", e)
        }
      }

      None
    },
    e => {
      println!("libusb_get_device_descriptor: {}", e);
      None
    }
  }
}

fn read_endpoint(handle: *mut ::ffi::libusb_device_handle, device: *mut ::ffi::libusb_device, endpoint: Endpoint, transfer_type: u8) {
  println!("Reading from endpoint: {:?}", endpoint);

  let has_kernel_driver = unsafe {
    if ::ffi::libusb_kernel_driver_active(handle, endpoint.iface as c_int) == 1 {
      match ::ffi::libusb_detach_kernel_driver(handle, endpoint.iface as c_int) {
        0 => (),
        e => println!("libusb_detach_kernel_driver: {}", e)
      }

      true
    }
    else {
      false
    }
  };

  println!(" - kernel driver? {}", has_kernel_driver);

  match unsafe { ::ffi::libusb_set_configuration(handle, endpoint.config as c_int) } {
    0 => {
      println!(" - max packet size: {}", unsafe { ::ffi::libusb_get_max_packet_size(device, endpoint.address as c_uchar) });
      println!(" - max iso packet size: {}", unsafe { ::ffi::libusb_get_max_iso_packet_size(device, endpoint.address as c_uchar) });

      match unsafe { ::ffi::libusb_claim_interface(handle, endpoint.iface as c_int) } {
        0 => {
          match unsafe { ::ffi::libusb_set_interface_alt_setting(handle, endpoint.iface as c_int, endpoint.setting as c_int) } {
            0 => {
              let mut vec = Vec::<u8>::with_capacity(256);
              let timeout: c_uint = 1000;

              let mut transferred: c_int = unsafe { mem::uninitialized() };

              match transfer_type {
                ::ffi::LIBUSB_TRANSFER_TYPE_INTERRUPT => {
                  match unsafe { ::ffi::libusb_interrupt_transfer(handle, endpoint.address as c_uchar, (&vec[..]).as_ptr() as *mut c_uchar, vec.capacity() as c_int, &mut transferred, timeout) } {
                    0 => {
                      unsafe { vec.set_len(transferred as usize) };
                      println!(" - read: {:?}", vec);
                    },
                    e => println!("libusb_interrupt_transfer: {}", e)
                  }
                },
                ::ffi::LIBUSB_TRANSFER_TYPE_BULK => {
                  match unsafe { ::ffi::libusb_bulk_transfer(handle, endpoint.address as c_uchar, (&vec[..]).as_ptr() as *mut c_uchar, vec.capacity() as c_int, &mut transferred, timeout) } {
                    0 => {
                      unsafe { vec.set_len(transferred as usize) };
                      println!(" - read: {:?}", vec);
                    },
                    e => println!("libusb_interrupt_transfer: {}", e)
                  }
                },
                tt => println!(" - can't read endpoint with transfer type {}", tt)
              }
            },
            e => println!("libusb_set_interface_alt_setting: {}", e)
          }

          match unsafe { ::ffi::libusb_release_interface(handle, endpoint.iface as c_int) } {
            0 => (),
            e => println!("libusb_release_interface: {}", e)
          }
        },
        e => println!("libusb_claim_interface: {}", e)
      }
    },
    e => println!("libusb_set_configuration: {}", e)
  }

  if has_kernel_driver {
    match unsafe { ::ffi::libusb_attach_kernel_driver(handle, endpoint.iface as c_int) } {
      0 => (),
      e => println!("libusb_attach_kernel_driver: {}", e)
    }
  }
}
<|endoftext|>